summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/busctl/busctl.c87
-rw-r--r--src/grp-boot/bootctl/bootctl.c12
-rw-r--r--src/grp-boot/systemd-boot/Makefile4
-rw-r--r--src/grp-boot/systemd-boot/boot.c13
-rw-r--r--src/grp-boot/systemd-boot/measure.c312
-rw-r--r--src/grp-boot/systemd-boot/measure.h21
-rw-r--r--src/grp-boot/systemd-boot/splash.c4
-rw-r--r--src/grp-boot/systemd-boot/stub.c13
-rw-r--r--src/grp-coredump/coredumpctl/coredumpctl.c8
-rw-r--r--src/grp-coredump/systemd-coredump/coredump.c59
-rw-r--r--src/grp-coredump/systemd-coredump/stacktrace.c4
-rw-r--r--src/grp-journal-remote/.gitignore (renamed from src/journal-remote/.gitignore)0
-rw-r--r--src/grp-journal-remote/browse.html (renamed from src/journal-remote/browse.html)2
-rwxr-xr-xsrc/grp-journal-remote/log-generator.py (renamed from src/journal-remote/log-generator.py)0
-rw-r--r--src/grp-journal-remote/microhttpd-util.c (renamed from src/journal-remote/microhttpd-util.c)0
-rw-r--r--src/grp-journal-remote/microhttpd-util.h (renamed from src/journal-remote/microhttpd-util.h)4
-rw-r--r--src/grp-journal-remote/systemd-journal-gatewayd/Makefile (renamed from src/systemd-bus-proxyd/Makefile)56
-rw-r--r--src/grp-journal-remote/systemd-journal-gatewayd/journal-gatewayd.c (renamed from src/journal-remote/journal-gatewayd.c)4
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/Makefile (renamed from src/journal-remote/Makefile)30
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/journal-remote-parse.c (renamed from src/journal-remote/journal-remote-parse.c)2
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/journal-remote-parse.h (renamed from src/journal-remote/journal-remote-parse.h)4
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/journal-remote-write.c (renamed from src/journal-remote/journal-remote-write.c)2
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/journal-remote-write.h (renamed from src/journal-remote/journal-remote-write.h)5
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/journal-remote.c (renamed from src/journal-remote/journal-remote.c)6
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/journal-remote.conf.in (renamed from src/journal-remote/journal-remote.conf.in)0
-rw-r--r--src/grp-journal-remote/systemd-journal-remote/journal-remote.h (renamed from src/journal-remote/journal-remote.h)5
-rw-r--r--src/grp-journal-remote/systemd-journal-upload/Makefile (renamed from src/systemd-bootchart/Makefile)39
-rw-r--r--src/grp-journal-remote/systemd-journal-upload/journal-upload-journal.c (renamed from src/journal-remote/journal-upload-journal.c)37
-rw-r--r--src/grp-journal-remote/systemd-journal-upload/journal-upload.c (renamed from src/journal-remote/journal-upload.c)5
-rw-r--r--src/grp-journal-remote/systemd-journal-upload/journal-upload.conf.in (renamed from src/journal-remote/journal-upload.conf.in)0
-rw-r--r--src/grp-journal-remote/systemd-journal-upload/journal-upload.h (renamed from src/journal-remote/journal-upload.h)3
-rw-r--r--src/grp-journal/.gitignore (renamed from src/journal/.gitignore)0
-rw-r--r--src/grp-journal/Makefile170
-rw-r--r--src/grp-journal/catalog/systemd.be.catalog (renamed from src/journal/catalog/systemd.be.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.be@latin.catalog (renamed from src/journal/catalog/systemd.be@latin.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.bg.catalog324
-rw-r--r--src/grp-journal/catalog/systemd.catalog (renamed from src/journal/catalog/systemd.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.da.catalog (renamed from src/journal/catalog/systemd.da.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.fr.catalog (renamed from src/journal/catalog/systemd.fr.catalog)72
-rw-r--r--src/grp-journal/catalog/systemd.hr.catalog314
-rw-r--r--src/grp-journal/catalog/systemd.hu.catalog (renamed from src/journal/catalog/systemd.hu.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.it.catalog (renamed from src/journal/catalog/systemd.it.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.ko.catalog (renamed from src/journal/catalog/systemd.ko.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.pl.catalog (renamed from src/journal/catalog/systemd.pl.catalog)60
-rw-r--r--src/grp-journal/catalog/systemd.pt_BR.catalog (renamed from src/journal/catalog/systemd.pt_BR.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.ru.catalog (renamed from src/journal/catalog/systemd.ru.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.sr.catalog (renamed from src/journal/catalog/systemd.sr.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.zh_CN.catalog (renamed from src/journal/catalog/systemd.zh_CN.catalog)2
-rw-r--r--src/grp-journal/catalog/systemd.zh_TW.catalog (renamed from src/journal/catalog/systemd.zh_TW.catalog)2
-rw-r--r--src/grp-journal/journalctl/Makefile (renamed from src/libbus-proxy-core/Makefile)35
-rw-r--r--src/grp-journal/journalctl/journalctl.c (renamed from src/journal/journalctl.c)240
-rw-r--r--src/grp-journal/libjournal-core/Makefile56
-rw-r--r--src/grp-journal/libjournal-core/cat.c (renamed from src/journal/cat.c)0
-rw-r--r--src/grp-journal/libjournal-core/journal-qrcode.c (renamed from src/journal/journal-qrcode.c)0
-rw-r--r--src/grp-journal/libjournal-core/journal-qrcode.h (renamed from src/journal/journal-qrcode.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-audit.c (renamed from src/journal/journald-audit.c)6
-rw-r--r--src/grp-journal/libjournal-core/journald-audit.h (renamed from src/journal/journald-audit.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-console.c (renamed from src/journal/journald-console.c)0
-rw-r--r--src/grp-journal/libjournal-core/journald-console.h (renamed from src/journal/journald-console.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-gperf.gperf (renamed from src/journal/journald-gperf.gperf)2
-rw-r--r--src/grp-journal/libjournal-core/journald-kmsg.c (renamed from src/journal/journald-kmsg.c)2
-rw-r--r--src/grp-journal/libjournal-core/journald-kmsg.h (renamed from src/journal/journald-kmsg.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-native.c (renamed from src/journal/journald-native.c)16
-rw-r--r--src/grp-journal/libjournal-core/journald-native.h (renamed from src/journal/journald-native.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-rate-limit.c (renamed from src/journal/journald-rate-limit.c)4
-rw-r--r--src/grp-journal/libjournal-core/journald-rate-limit.h (renamed from src/journal/journald-rate-limit.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-server.c (renamed from src/journal/journald-server.c)92
-rw-r--r--src/grp-journal/libjournal-core/journald-server.h (renamed from src/journal/journald-server.h)2
-rw-r--r--src/grp-journal/libjournal-core/journald-stream.c (renamed from src/journal/journald-stream.c)17
-rw-r--r--src/grp-journal/libjournal-core/journald-stream.h (renamed from src/journal/journald-stream.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-syslog.c (renamed from src/journal/journald-syslog.c)36
-rw-r--r--src/grp-journal/libjournal-core/journald-syslog.h (renamed from src/journal/journald-syslog.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald-wall.c (renamed from src/journal/journald-wall.c)0
-rw-r--r--src/grp-journal/libjournal-core/journald-wall.h (renamed from src/journal/journald-wall.h)0
-rw-r--r--src/grp-journal/libjournal-core/journald.conf (renamed from src/journal/journald.conf)2
-rw-r--r--src/grp-journal/libjournal-core/test-audit-type.c (renamed from src/journal/test-audit-type.c)0
-rw-r--r--src/grp-journal/libjournal-core/test-catalog.c (renamed from src/journal/test-catalog.c)2
-rw-r--r--src/grp-journal/libjournal-core/test-compress-benchmark.c (renamed from src/journal/test-compress-benchmark.c)4
-rw-r--r--src/grp-journal/libjournal-core/test-compress.c (renamed from src/journal/test-compress.c)0
-rw-r--r--src/grp-journal/libjournal-core/test-journal-enum.c (renamed from src/journal/test-journal-enum.c)2
-rw-r--r--src/grp-journal/libjournal-core/test-journal-flush.c (renamed from src/journal/test-journal-flush.c)4
-rw-r--r--src/grp-journal/libjournal-core/test-journal-init.c (renamed from src/journal/test-journal-init.c)0
-rw-r--r--src/grp-journal/libjournal-core/test-journal-interleaving.c (renamed from src/journal/test-journal-interleaving.c)16
-rw-r--r--src/grp-journal/libjournal-core/test-journal-match.c (renamed from src/journal/test-journal-match.c)0
-rw-r--r--src/grp-journal/libjournal-core/test-journal-send.c (renamed from src/journal/test-journal-send.c)0
-rw-r--r--src/grp-journal/libjournal-core/test-journal-stream.c (renamed from src/journal/test-journal-stream.c)12
-rw-r--r--src/grp-journal/libjournal-core/test-journal-syslog.c (renamed from src/journal/test-journal-syslog.c)0
-rw-r--r--src/grp-journal/libjournal-core/test-journal-verify.c (renamed from src/journal/test-journal-verify.c)12
-rw-r--r--src/grp-journal/libjournal-core/test-journal.c (renamed from src/journal/test-journal.c)24
-rw-r--r--src/grp-journal/libjournal-core/test-mmap-cache.c (renamed from src/journal/test-mmap-cache.c)0
-rw-r--r--src/grp-journal/systemd-journald/Makefile94
-rw-r--r--src/grp-journal/systemd-journald/journald.c (renamed from src/journal/journald.c)0
-rw-r--r--src/grp-machine/libmachine-core/Makefile4
-rw-r--r--src/grp-machine/libmachine-core/image-dbus.c73
-rw-r--r--src/grp-machine/libmachine-core/machine-dbus.c162
-rw-r--r--src/grp-machine/libmachine-core/machine-dbus.h1
-rw-r--r--src/grp-machine/libmachine-core/machine.c41
-rw-r--r--src/grp-machine/libmachine-core/machine.h20
-rw-r--r--src/grp-machine/libmachine-core/machined-dbus.c111
-rw-r--r--src/grp-machine/libmachine-core/machined.h4
-rw-r--r--src/grp-machine/libmachine-core/operation.c131
-rw-r--r--src/grp-machine/libmachine-core/operation.h (renamed from src/libcore/bus-endpoint.h)37
-rw-r--r--src/grp-machine/machinectl/machinectl.c298
-rw-r--r--src/grp-machine/nss-mymachines/nss-mymachines.c2
-rw-r--r--src/grp-machine/systemd-machined/machined.c8
-rw-r--r--src/grp-resolve/nss-resolve/nss-resolve.c81
-rw-r--r--src/grp-resolve/systemd-resolved/Makefile113
-rw-r--r--src/grp-resolve/systemd-resolved/RFCs2
-rw-r--r--src/grp-resolve/systemd-resolved/dns-type.c17
-rw-r--r--src/grp-resolve/systemd-resolved/dns-type.h15
-rw-r--r--src/grp-resolve/systemd-resolved/resolve-tool.c346
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-bus.c134
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-conf.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-answer.c14
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-answer.h2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-cache.c146
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c80
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-packet.c458
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-packet.h6
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-query.c31
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-question.c10
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-rr.c207
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-rr.h33
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-scope.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-server.c9
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c14
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-transaction.c786
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-transaction.h9
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-dns-zone.c39
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-etc-hosts.c6
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-link-bus.c6
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-link-bus.h2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-link.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-llmnr.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-manager.c10
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-mdns.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved-resolv-conf.c4
-rw-r--r--src/grp-resolve/systemd-resolved/resolved.c2
-rw-r--r--src/grp-resolve/systemd-resolved/resolved.conf.in2
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pktsbin0 -> 169 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pktsbin0 -> 986 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/fake-caa.pktsbin0 -> 196 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pktsbin0 -> 1483 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/gandi.net.pktsbin0 -> 1010 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/google.com.pktsbin0 -> 747 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pktsbin0 -> 1803 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/root.pktsbin0 -> 1061 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pktsbin0 -> 330 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/teamits.com.pktsbin0 -> 1021 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pktsbin0 -> 2533 bytes
-rw-r--r--src/grp-resolve/systemd-resolved/test-dns-packet.c114
-rw-r--r--src/grp-resolve/systemd-resolved/test-dnssec.c275
-rw-r--r--src/grp-resolve/systemd-resolved/test-resolve-tables.c37
-rw-r--r--src/grp-system/systemctl/systemctl.c804
-rw-r--r--src/grp-system/systemd/Makefile3
-rw-r--r--src/grp-system/systemd/main.c109
-rw-r--r--src/grp-system/systemd/org.freedesktop.systemd1.conf20
-rw-r--r--src/grp-system/systemd/system.conf3
-rw-r--r--src/grp-system/systemd/triggers.systemd.in2
-rw-r--r--src/grp-system/systemd/user.conf2
-rw-r--r--src/grp-timedate/systemd-timedated/timedated.c48
-rw-r--r--src/grp-timedate/timedatectl/timedatectl.c10
-rw-r--r--src/hostname/hostnamed.c2
-rw-r--r--src/import/Makefile2
-rw-r--r--src/import/aufs-util.c73
-rw-r--r--src/import/curl-util.c4
-rw-r--r--src/import/import-common.c4
-rw-r--r--src/import/importd.c2
-rw-r--r--src/import/pull-common.c2
-rw-r--r--src/import/pull-job.h9
-rw-r--r--src/import/pull-raw.c6
-rw-r--r--src/import/pull-tar.c6
-rw-r--r--src/initctl/initctl.c2
-rw-r--r--src/journal/Makefile348
-rw-r--r--src/libbasic/Makefile7
-rw-r--r--src/libbasic/MurmurHash2.c2
-rw-r--r--src/libbasic/af-list.h16
-rw-r--r--src/libbasic/alloc-util.h22
-rw-r--r--src/libbasic/architecture.c (renamed from src/libshared/architecture.c)5
-rw-r--r--src/libbasic/architecture.h (renamed from src/libshared/architecture.h)26
-rw-r--r--src/libbasic/btrfs-util.h4
-rw-r--r--src/libbasic/c-rbtree.c679
-rw-r--r--src/libbasic/c-rbtree.h297
-rw-r--r--src/libbasic/calendarspec.c22
-rw-r--r--src/libbasic/cgroup-util.c90
-rw-r--r--src/libbasic/cgroup-util.h36
-rw-r--r--src/libbasic/clock-util.c11
-rw-r--r--src/libbasic/clock-util.h2
-rw-r--r--src/libbasic/copy.c121
-rw-r--r--src/libbasic/copy.h1
-rw-r--r--src/libbasic/def.h2
-rw-r--r--src/libbasic/dirent-util.c12
-rw-r--r--src/libbasic/dirent-util.h2
-rw-r--r--src/libbasic/escape.c28
-rw-r--r--src/libbasic/escape.h1
-rw-r--r--src/libbasic/ether-addr-util.c81
-rw-r--r--src/libbasic/ether-addr-util.h12
-rw-r--r--src/libbasic/exit-status.c3
-rw-r--r--src/libbasic/exit-status.h1
-rw-r--r--src/libbasic/extract-word.c14
-rw-r--r--src/libbasic/fd-util.c18
-rw-r--r--src/libbasic/fd-util.h2
-rw-r--r--src/libbasic/fdset.c15
-rw-r--r--src/libbasic/fdset.h1
-rw-r--r--src/libbasic/fileio.c140
-rw-r--r--src/libbasic/fileio.h6
-rw-r--r--src/libbasic/formats-util.h2
-rw-r--r--src/libbasic/fs-util.c33
-rw-r--r--src/libbasic/fs-util.h3
-rw-r--r--src/libbasic/gunicode.h4
-rw-r--r--src/libbasic/hashmap.c24
-rw-r--r--src/libbasic/hexdecoct.c13
-rw-r--r--src/libbasic/hostname-util.c46
-rw-r--r--src/libbasic/hostname-util.h1
-rw-r--r--src/libbasic/io-util.c7
-rw-r--r--src/libbasic/io-util.h2
-rw-r--r--src/libbasic/json.c871
-rw-r--r--src/libbasic/json.h90
-rw-r--r--src/libbasic/list.h14
-rw-r--r--src/libbasic/locale-util.c49
-rw-r--r--src/libbasic/locale-util.h24
-rw-r--r--src/libbasic/log.c6
-rw-r--r--src/libbasic/log.h3
-rw-r--r--src/libbasic/login-util.h4
-rw-r--r--src/libbasic/macro.h15
-rw-r--r--src/libbasic/mempool.h2
-rw-r--r--src/libbasic/missing.h288
-rw-r--r--src/libbasic/missing_syscall.h310
-rw-r--r--src/libbasic/mount-util.c8
-rw-r--r--src/libbasic/nss-util.h43
-rw-r--r--src/libbasic/parse-util.c2
-rw-r--r--src/libbasic/parse-util.h12
-rw-r--r--src/libbasic/path-util.c73
-rw-r--r--src/libbasic/path-util.h20
-rw-r--r--src/libbasic/process-util.c103
-rw-r--r--src/libbasic/process-util.h6
-rw-r--r--src/libbasic/rlimit-util.c52
-rw-r--r--src/libbasic/rm-rf.h9
-rw-r--r--src/libbasic/selinux-util.c34
-rw-r--r--src/libbasic/selinux-util.h2
-rw-r--r--src/libbasic/set.h3
-rw-r--r--src/libbasic/sigbus.h4
-rw-r--r--src/libbasic/signal-util.c2
-rw-r--r--src/libbasic/signal-util.h12
-rw-r--r--src/libbasic/socket-label.c34
-rw-r--r--src/libbasic/socket-util.c80
-rw-r--r--src/libbasic/socket-util.h15
-rw-r--r--src/libbasic/special.h1
-rw-r--r--src/libbasic/stdio-util.h2
-rw-r--r--src/libbasic/strbuf.c9
-rw-r--r--src/libbasic/string-table.h54
-rw-r--r--src/libbasic/string-util.c2
-rw-r--r--src/libbasic/string-util.h1
-rw-r--r--src/libbasic/strv.c40
-rw-r--r--src/libbasic/strv.h1
-rw-r--r--src/libbasic/terminal-util.c19
-rw-r--r--src/libbasic/time-util.c129
-rw-r--r--src/libbasic/time-util.h2
-rw-r--r--src/libbasic/user-util.c1
-rw-r--r--src/libbasic/user-util.h5
-rw-r--r--src/libbasic/utf8.c2
-rw-r--r--src/libbasic/utf8.h1
-rw-r--r--src/libbasic/util.c41
-rw-r--r--src/libbasic/util.h13
-rw-r--r--src/libbasic/virt.c74
-rw-r--r--src/libbasic/xattr-util.c2
-rw-r--r--src/libbus-proxy-core/bus-xml-policy.c1327
-rw-r--r--src/libbus-proxy-core/bus-xml-policy.h147
-rw-r--r--src/libbus-proxy-core/driver.c745
-rw-r--r--src/libbus-proxy-core/proxy.c953
-rw-r--r--src/libbus-proxy-core/proxy.h66
-rw-r--r--src/libbus-proxy-core/synthesize.c225
-rw-r--r--src/libbus-proxy-core/synthesize.h36
-rw-r--r--src/libbus-proxy-core/test-bus-xml-policy.c170
-rw-r--r--src/libcore/Makefile2
-rw-r--r--src/libcore/automount.c122
-rw-r--r--src/libcore/automount.h4
-rw-r--r--src/libcore/bus-endpoint.c135
-rw-r--r--src/libcore/busname.c25
-rw-r--r--src/libcore/busname.h2
-rw-r--r--src/libcore/cgroup.c389
-rw-r--r--src/libcore/cgroup.h30
-rw-r--r--src/libcore/dbus-cgroup.c331
-rw-r--r--src/libcore/dbus-execute.c79
-rw-r--r--src/libcore/dbus-job.c2
-rw-r--r--src/libcore/dbus-kill.c4
-rw-r--r--src/libcore/dbus-manager.c382
-rw-r--r--src/libcore/dbus-socket.c2
-rw-r--r--src/libcore/dbus-timer.c2
-rw-r--r--src/libcore/dbus-unit.c155
-rw-r--r--src/libcore/dbus-unit.h1
-rw-r--r--src/libcore/dbus.c85
-rw-r--r--src/libcore/dbus.h2
-rw-r--r--src/libcore/device.c8
-rw-r--r--src/libcore/execute.c105
-rw-r--r--src/libcore/execute.h10
-rw-r--r--src/libcore/failure-action.c14
-rw-r--r--src/libcore/ima-setup.c2
-rw-r--r--src/libcore/ima-setup.h2
-rw-r--r--src/libcore/job.c60
-rw-r--r--src/libcore/job.h2
-rw-r--r--src/libcore/load-dropin.c15
-rw-r--r--src/libcore/load-dropin.h2
-rw-r--r--src/libcore/load-fragment-gperf.gperf.m417
-rw-r--r--src/libcore/load-fragment.c430
-rw-r--r--src/libcore/load-fragment.h5
-rw-r--r--src/libcore/machine-id-setup.c49
-rw-r--r--src/libcore/manager.c492
-rw-r--r--src/libcore/manager.h21
-rw-r--r--src/libcore/mount-setup.c3
-rw-r--r--src/libcore/mount.c130
-rw-r--r--src/libcore/mount.h1
-rw-r--r--src/libcore/namespace.c97
-rw-r--r--src/libcore/namespace.h1
-rw-r--r--src/libcore/path.c20
-rw-r--r--src/libcore/path.h1
-rw-r--r--src/libcore/scope.c36
-rw-r--r--src/libcore/selinux-access.c5
-rw-r--r--src/libcore/selinux-setup.c2
-rw-r--r--src/libcore/service.c135
-rw-r--r--src/libcore/service.h6
-rw-r--r--src/libcore/shutdown.c9
-rw-r--r--src/libcore/slice.c11
-rw-r--r--src/libcore/smack-setup.c2
-rw-r--r--src/libcore/socket.c332
-rw-r--r--src/libcore/socket.h4
-rw-r--r--src/libcore/swap.c28
-rw-r--r--src/libcore/swap.h1
-rw-r--r--src/libcore/timer.c18
-rw-r--r--src/libcore/timer.h1
-rw-r--r--src/libcore/transaction.c15
-rw-r--r--src/libcore/umount.c5
-rw-r--r--src/libcore/unit-printf.c11
-rw-r--r--src/libcore/unit.c312
-rw-r--r--src/libcore/unit.h21
-rw-r--r--src/libfirewall/firewall-util.c16
-rw-r--r--src/libshared/Makefile9
-rw-r--r--src/libshared/acpi-fpdt.c6
-rw-r--r--src/libshared/ask-password-api.c2
-rw-r--r--src/libshared/bus-unit-util.c1307
-rw-r--r--src/libshared/bus-unit-util.h57
-rw-r--r--src/libshared/bus-util.c899
-rw-r--r--src/libshared/bus-util.h37
-rw-r--r--src/libshared/cgroup-show.c102
-rw-r--r--src/libshared/cgroup-show.h8
-rw-r--r--src/libshared/condition.c2
-rw-r--r--src/libshared/conf-parser.c53
-rw-r--r--src/libshared/conf-parser.h3
-rw-r--r--src/libshared/dns-domain.c8
-rw-r--r--src/libshared/dns-domain.h5
-rw-r--r--src/libshared/dropin.c2
-rw-r--r--src/libshared/gcrypt-util.c71
-rw-r--r--src/libshared/gcrypt-util.h39
-rw-r--r--src/libshared/generator.c16
-rw-r--r--src/libshared/generator.h4
-rw-r--r--src/libshared/gpt.h4
-rw-r--r--src/libshared/install-printf.h4
-rw-r--r--src/libshared/install.c1299
-rw-r--r--src/libshared/install.h132
-rw-r--r--src/libshared/local-addresses.c3
-rw-r--r--src/libshared/logs-show.c51
-rw-r--r--src/libshared/logs-show.h3
-rw-r--r--src/libshared/machine-image.c39
-rw-r--r--src/libshared/machine-image.h26
-rw-r--r--src/libshared/machine-pool.c9
-rw-r--r--src/libshared/output-mode.c37
-rw-r--r--src/libshared/output-mode.h11
-rw-r--r--src/libshared/pager.c5
-rw-r--r--src/libshared/pager.h2
-rw-r--r--src/libshared/path-lookup.c807
-rw-r--r--src/libshared/path-lookup.h78
-rw-r--r--src/libshared/ptyfwd.c5
-rw-r--r--src/libshared/sleep-config.c6
-rw-r--r--src/libshared/sleep-config.h4
-rw-r--r--src/libshared/spawn-polkit-agent.c4
-rw-r--r--src/libshared/tests.c (renamed from src/systemd-bootchart/store.h)29
-rw-r--r--src/libshared/tests.h (renamed from src/import/aufs-util.h)4
-rw-r--r--src/libshared/uid-range.c2
-rw-r--r--src/libsystemd-network/Makefile13
-rw-r--r--src/libsystemd-network/dhcp-identifier.c33
-rw-r--r--src/libsystemd-network/dhcp-identifier.h21
-rw-r--r--src/libsystemd-network/dhcp-internal.h4
-rw-r--r--src/libsystemd-network/dhcp-option.c13
-rw-r--r--src/libsystemd-network/dhcp-packet.c2
-rw-r--r--src/libsystemd-network/dhcp-server-internal.h6
-rw-r--r--src/libsystemd-network/dhcp6-internal.h3
-rw-r--r--src/libsystemd-network/dhcp6-option.c3
-rw-r--r--src/libsystemd-network/dhcp6-protocol.h7
-rw-r--r--src/libsystemd-network/lldp-internal.c360
-rw-r--r--src/libsystemd-network/lldp-internal.h78
-rw-r--r--src/libsystemd-network/lldp-neighbor.c794
-rw-r--r--src/libsystemd-network/lldp-neighbor.h106
-rw-r--r--src/libsystemd-network/lldp-network.c35
-rw-r--r--src/libsystemd-network/lldp-network.h4
-rw-r--r--src/libsystemd-network/lldp-port.c116
-rw-r--r--src/libsystemd-network/lldp-port.h69
-rw-r--r--src/libsystemd-network/lldp-tlv.c638
-rw-r--r--src/libsystemd-network/lldp-tlv.h94
-rw-r--r--src/libsystemd-network/lldp.h126
-rw-r--r--src/libsystemd-network/network-internal.c188
-rw-r--r--src/libsystemd-network/network-internal.h8
-rw-r--r--src/libsystemd-network/sd-dhcp-client.c208
-rw-r--r--src/libsystemd-network/sd-dhcp-lease.c2
-rw-r--r--src/libsystemd-network/sd-dhcp-server.c47
-rw-r--r--src/libsystemd-network/sd-dhcp6-client.c124
-rw-r--r--src/libsystemd-network/sd-ipv4acd.c8
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c8
-rw-r--r--src/libsystemd-network/sd-lldp.c898
-rw-r--r--src/libsystemd-network/sd-ndisc.c2
-rw-r--r--src/libsystemd-network/test-dhcp-option.c11
-rw-r--r--src/libsystemd-network/test-lldp.c339
-rw-r--r--src/libsystemd/Makefile23
-rw-r--r--src/libsystemd/compat-libs/.gitignore1
-rw-r--r--src/libsystemd/compat-libs/Makefile146
-rw-r--r--src/libsystemd/compat-libs/libsystemd-daemon.pc.in19
-rw-r--r--src/libsystemd/compat-libs/libsystemd-daemon.sym27
-rw-r--r--src/libsystemd/compat-libs/libsystemd-id128.pc.in18
-rw-r--r--src/libsystemd/compat-libs/libsystemd-id128.sym21
-rw-r--r--src/libsystemd/compat-libs/libsystemd-journal.pc.in19
-rw-r--r--src/libsystemd/compat-libs/libsystemd-journal.sym111
-rw-r--r--src/libsystemd/compat-libs/libsystemd-login.pc.in18
-rw-r--r--src/libsystemd/compat-libs/libsystemd-login.sym87
-rw-r--r--src/libsystemd/compat-libs/linkwarning.h35
-rw-r--r--src/libsystemd/include/systemd/_sd-common.h2
-rw-r--r--src/libsystemd/include/systemd/sd-bus-protocol.h2
-rw-r--r--src/libsystemd/include/systemd/sd-bus-vtable.h2
-rw-r--r--src/libsystemd/include/systemd/sd-bus.h4
-rw-r--r--src/libsystemd/include/systemd/sd-device.h1
-rw-r--r--src/libsystemd/include/systemd/sd-dhcp-client.h76
-rw-r--r--src/libsystemd/include/systemd/sd-dhcp-server.h3
-rw-r--r--src/libsystemd/include/systemd/sd-dhcp6-client.h61
-rw-r--r--src/libsystemd/include/systemd/sd-event.h6
-rw-r--r--src/libsystemd/include/systemd/sd-id128.h4
-rw-r--r--src/libsystemd/include/systemd/sd-ipv4acd.h6
-rw-r--r--src/libsystemd/include/systemd/sd-ipv4ll.h6
-rw-r--r--src/libsystemd/include/systemd/sd-journal.h15
-rw-r--r--src/libsystemd/include/systemd/sd-lldp.h156
-rw-r--r--src/libsystemd/include/systemd/sd-login.h2
-rw-r--r--src/libsystemd/include/systemd/sd-messages.h2
-rw-r--r--src/libsystemd/include/systemd/sd-ndisc.h2
-rw-r--r--src/libsystemd/include/systemd/sd-netlink.h6
-rw-r--r--src/libsystemd/include/systemd/sd-network.h12
-rw-r--r--src/libsystemd/include/systemd/sd-resolve.h2
-rw-r--r--src/libsystemd/libsystemd-internal/Makefile6
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.c4
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.h4
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-control.c6
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-dump.c4
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-kernel.c44
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-message.c32
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-objects.c4
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-slot.c2
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-socket.c8
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/bus-track.c2
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/sd-bus.c33
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/test-bus-error.c2
-rw-r--r--src/libsystemd/libsystemd-internal/sd-bus/test-bus-proxy.c117
-rw-r--r--src/libsystemd/libsystemd-internal/sd-daemon/sd-daemon.c6
-rw-r--r--src/libsystemd/libsystemd-internal/sd-device/device-internal.h4
-rw-r--r--src/libsystemd/libsystemd-internal/sd-device/device-private.c6
-rw-r--r--src/libsystemd/libsystemd-internal/sd-device/sd-device.c69
-rw-r--r--src/libsystemd/libsystemd-internal/sd-event/sd-event.c25
-rw-r--r--src/libsystemd/libsystemd-internal/sd-event/test-event.c14
-rw-r--r--src/libsystemd/libsystemd-internal/sd-hwdb/hwdb-internal.h3
-rw-r--r--src/libsystemd/libsystemd-internal/sd-netlink/netlink-message.c29
-rw-r--r--src/libsystemd/libsystemd-internal/sd-netlink/netlink-socket.c12
-rw-r--r--src/libsystemd/libsystemd-internal/sd-netlink/netlink-types.c43
-rw-r--r--src/libsystemd/libsystemd-internal/sd-netlink/rtnl-message.c31
-rw-r--r--src/libsystemd/libsystemd-internal/sd-netlink/sd-netlink.c4
-rw-r--r--src/libsystemd/libsystemd-internal/sd-netlink/test-netlink.c24
-rw-r--r--src/libsystemd/libsystemd-internal/sd-network/sd-network.c105
-rw-r--r--src/libsystemd/libsystemd-internal/sd-path/sd-path.c9
-rw-r--r--src/libsystemd/libsystemd-internal/sd-resolve/sd-resolve.c18
-rw-r--r--src/libsystemd/libsystemd-internal/sd-resolve/test-resolve.c2
-rw-r--r--src/libsystemd/libsystemd-journal-internal/Makefile4
-rw-r--r--src/libsystemd/libsystemd-journal-internal/catalog.c83
-rw-r--r--src/libsystemd/libsystemd-journal-internal/compress.c15
-rw-r--r--src/libsystemd/libsystemd-journal-internal/fsprg.c27
-rw-r--r--src/libsystemd/libsystemd-journal-internal/journal-authenticate.c15
-rw-r--r--src/libsystemd/libsystemd-journal-internal/journal-file.c420
-rw-r--r--src/libsystemd/libsystemd-journal-internal/journal-file.h24
-rw-r--r--src/libsystemd/libsystemd-journal-internal/journal-internal.h3
-rw-r--r--src/libsystemd/libsystemd-journal-internal/journal-send.c18
-rw-r--r--src/libsystemd/libsystemd-journal-internal/journal-vacuum.c8
-rw-r--r--src/libsystemd/libsystemd-journal-internal/journal-verify.c26
-rw-r--r--src/libsystemd/libsystemd-journal-internal/mmap-cache.c8
-rw-r--r--src/libsystemd/libsystemd-journal-internal/sd-journal.c315
-rw-r--r--src/libsystemd/libsystemd.sym6
-rw-r--r--src/libudev/include/libudev.h1
-rw-r--r--src/libudev/src/libudev-device-internal.h4
-rw-r--r--src/libudev/src/libudev-enumerate.c2
-rw-r--r--src/libudev/src/udev.h11
-rw-r--r--src/locale/Makefile2
-rw-r--r--src/locale/language-fallback-map4
-rw-r--r--src/locale/localectl.c20
-rw-r--r--src/locale/localed.c80
-rw-r--r--src/login/.gitignore1
-rw-r--r--src/login/70-uaccess.rules3
-rw-r--r--src/login/Makefile5
-rw-r--r--src/login/loginctl.c98
-rw-r--r--src/login/logind-core.c8
-rw-r--r--src/login/logind-dbus.c57
-rw-r--r--src/login/logind-gperf.gperf2
-rw-r--r--src/login/logind-inhibit.c2
-rw-r--r--src/login/logind-seat-dbus.c2
-rw-r--r--src/login/logind-session-dbus.c52
-rw-r--r--src/login/logind-session.c40
-rw-r--r--src/login/logind-session.h4
-rw-r--r--src/login/logind-user-dbus.c5
-rw-r--r--src/login/logind-user.c15
-rw-r--r--src/login/logind-utmp.c2
-rw-r--r--src/login/logind.c90
-rw-r--r--src/login/logind.conf.in (renamed from src/login/logind.conf)4
-rw-r--r--src/login/logind.h2
-rw-r--r--src/login/org.freedesktop.login1.conf4
-rw-r--r--src/login/org.freedesktop.login1.policy.in8
-rw-r--r--src/login/pam_systemd.c2
-rw-r--r--src/login/sysfs-show.c8
-rw-r--r--src/login/systemd-user.m41
-rw-r--r--src/network/.gitignore1
-rw-r--r--src/network/Makefile15
-rw-r--r--src/network/networkctl.c952
-rw-r--r--src/network/networkd-address-pool.c6
-rw-r--r--src/network/networkd-address-pool.h4
-rw-r--r--src/network/networkd-address.c117
-rw-r--r--src/network/networkd-address.h5
-rw-r--r--src/network/networkd-conf.c111
-rw-r--r--src/network/networkd-conf.h49
-rw-r--r--src/network/networkd-dhcp4.c46
-rw-r--r--src/network/networkd-dhcp6.c25
-rw-r--r--src/network/networkd-fdb.c6
-rw-r--r--src/network/networkd-fdb.h8
-rw-r--r--src/network/networkd-gperf.gperf18
-rw-r--r--src/network/networkd-ipv4ll.c8
-rw-r--r--src/network/networkd-link.c508
-rw-r--r--src/network/networkd-link.h29
-rw-r--r--src/network/networkd-lldp-tx.c416
-rw-r--r--src/network/networkd-lldp-tx.h (renamed from src/systemd-bootchart/svg.h)30
-rw-r--r--src/network/networkd-manager.c27
-rw-r--r--src/network/networkd-ndisc.c37
-rw-r--r--src/network/networkd-netdev-bond.c3
-rw-r--r--src/network/networkd-netdev-bond.h8
-rw-r--r--src/network/networkd-netdev-bridge.c25
-rw-r--r--src/network/networkd-netdev-bridge.h14
-rw-r--r--src/network/networkd-netdev-dummy.h11
-rw-r--r--src/network/networkd-netdev-gperf.gperf14
-rw-r--r--src/network/networkd-netdev-ipvlan.h11
-rw-r--r--src/network/networkd-netdev-macvlan.h6
-rw-r--r--src/network/networkd-netdev-tunnel.c12
-rw-r--r--src/network/networkd-netdev-tunnel.h21
-rw-r--r--src/network/networkd-netdev-tuntap.c10
-rw-r--r--src/network/networkd-netdev-tuntap.h6
-rw-r--r--src/network/networkd-netdev-veth.h5
-rw-r--r--src/network/networkd-netdev-vlan.h5
-rw-r--r--src/network/networkd-netdev-vxlan.c8
-rw-r--r--src/network/networkd-netdev-vxlan.h5
-rw-r--r--src/network/networkd-netdev.c2
-rw-r--r--src/network/networkd-netdev.h57
-rw-r--r--src/network/networkd-network-gperf.gperf11
-rw-r--r--src/network/networkd-network.c37
-rw-r--r--src/network/networkd-network.h40
-rw-r--r--src/network/networkd-route.c119
-rw-r--r--src/network/networkd-route.h5
-rw-r--r--src/network/networkd-wait-online.h4
-rw-r--r--src/network/networkd.c5
-rw-r--r--src/network/networkd.h32
-rw-r--r--src/network/test-network-tables.c2
-rw-r--r--src/network/test-networkd-conf.c142
-rw-r--r--src/nss-myhostname/nss-myhostname.c35
-rw-r--r--src/socket-proxy/socket-proxyd.c19
-rw-r--r--src/systemd-activate/Makefile8
-rw-r--r--src/systemd-activate/activate.c118
-rw-r--r--src/systemd-activate/systemd-activate.xml204
-rw-r--r--src/systemd-analyze/analyze-verify.c10
-rw-r--r--src/systemd-analyze/analyze-verify.h6
-rw-r--r--src/systemd-analyze/analyze.c25
-rw-r--r--src/systemd-ask-password/ask-password.c11
-rw-r--r--src/systemd-bootchart/bootchart.c531
-rw-r--r--src/systemd-bootchart/bootchart.conf26
-rw-r--r--src/systemd-bootchart/bootchart.h119
-rw-r--r--src/systemd-bootchart/store.c555
-rw-r--r--src/systemd-bootchart/svg.c1375
-rw-r--r--src/systemd-bus-proxyd/bus-proxyd.c328
-rw-r--r--src/systemd-cgls/cgls.c13
-rw-r--r--src/systemd-cgroups-agent/cgroups-agent.c48
-rw-r--r--src/systemd-cgtop/cgtop.c56
-rw-r--r--src/systemd-cryptsetup/cryptsetup.c8
-rw-r--r--src/systemd-delta/delta.c32
-rw-r--r--src/systemd-firstboot/firstboot.c20
-rw-r--r--src/systemd-fsck/fsck.c2
-rw-r--r--src/systemd-fstab-generator/fstab-generator.c13
-rw-r--r--src/systemd-gpt-auto-generator/gpt-auto-generator.c6
-rw-r--r--src/systemd-nspawn/Makefile17
-rw-r--r--src/systemd-nspawn/nspawn-cgroup.c9
-rw-r--r--src/systemd-nspawn/nspawn-gperf.gperf7
-rw-r--r--src/systemd-nspawn/nspawn-mount.c25
-rw-r--r--src/systemd-nspawn/nspawn-network.c184
-rw-r--r--src/systemd-nspawn/nspawn-network.h5
-rw-r--r--src/systemd-nspawn/nspawn-patch-uid.c469
-rw-r--r--src/systemd-nspawn/nspawn-patch-uid.h (renamed from src/libbus-proxy-core/driver.h)12
-rw-r--r--src/systemd-nspawn/nspawn-register.c1
-rw-r--r--src/systemd-nspawn/nspawn-settings.c124
-rw-r--r--src/systemd-nspawn/nspawn-settings.h17
-rw-r--r--src/systemd-nspawn/nspawn.c592
-rw-r--r--src/systemd-nspawn/test-patch-uid.c61
-rw-r--r--src/systemd-rc-local-generator/rc-local-generator.c2
-rw-r--r--src/systemd-reply-password/reply-password.c8
-rw-r--r--src/systemd-run/run.c41
-rw-r--r--src/systemd-stdio-bridge/Makefile3
-rw-r--r--src/systemd-stdio-bridge/stdio-bridge.c352
-rw-r--r--src/systemd-sysv-generator/sysv-generator.c59
-rw-r--r--src/systemd-timesync/timesyncd.c2
-rw-r--r--src/systemd-tmpfiles/tmpfiles.c99
-rw-r--r--src/systemd-tty-ask-password-agent/tty-ask-password-agent.c9
-rw-r--r--src/systemd-update-done/update-done.c2
-rw-r--r--src/systemd-user-sessions/user-sessions.c2
-rw-r--r--src/systemd-vconsole/vconsole-setup.c8
-rw-r--r--src/sysusers/sysusers.c2
-rw-r--r--src/test/test-alloc-util.c55
-rw-r--r--src/test/test-boot-timestamps.c51
-rw-r--r--src/test/test-calendarspec.c1
-rw-r--r--src/test/test-cgroup-mask.c21
-rw-r--r--src/test/test-clock.c96
-rw-r--r--src/test/test-conf-parser.c9
-rw-r--r--src/test/test-copy.c92
-rw-r--r--src/test/test-cpu-set-util.c143
-rw-r--r--src/test/test-daemon.c10
-rw-r--r--src/test/test-engine.c7
-rw-r--r--src/test/test-env-util.c (renamed from src/test/test-env-replace.c)30
-rw-r--r--src/test/test-escape.c114
-rw-r--r--src/test/test-execute.c91
-rw-r--r--src/test/test-fd-util.c103
-rw-r--r--src/test/test-fileio.c135
-rw-r--r--src/test/test-fs-util.c91
-rw-r--r--src/test/test-fstab-util.c37
-rw-r--r--src/test/test-glob-util.c50
-rw-r--r--src/test/test-hashmap-plain.c15
-rw-r--r--src/test/test-hexdecoct.c387
-rw-r--r--src/test/test-install-root.c108
-rw-r--r--src/test/test-install.c44
-rw-r--r--src/test/test-io-util.c69
-rw-r--r--src/test/test-ipcrm.c11
-rw-r--r--src/test/test-json.c202
-rw-r--r--src/test/test-libudev.c267
-rw-r--r--src/test/test-loopback.c4
-rw-r--r--src/test/test-namespace.c9
-rw-r--r--src/test/test-netlink-manual.c6
-rw-r--r--src/test/test-ns.c1
-rw-r--r--src/test/test-nss.c454
-rw-r--r--src/test/test-path-lookup.c40
-rw-r--r--src/test/test-path-util.c80
-rw-r--r--src/test/test-path.c12
-rw-r--r--src/test/test-proc-cmdline.c52
-rw-r--r--src/test/test-process-util.c26
-rw-r--r--src/test/test-rbtree.c362
-rw-r--r--src/test/test-rlimit-util.c12
-rw-r--r--src/test/test-sched-prio.c7
-rw-r--r--src/test/test-selinux.c122
-rw-r--r--src/test/test-signal-util.c18
-rw-r--r--src/test/test-siphash24.c47
-rw-r--r--src/test/test-sizeof.c53
-rw-r--r--src/test/test-socket-util.c42
-rw-r--r--src/test/test-stat-util.c68
-rw-r--r--src/test/test-string-util.c265
-rw-r--r--src/test/test-strv.c55
-rw-r--r--src/test/test-tables.c3
-rw-r--r--src/test/test-time.c2
-rw-r--r--src/test/test-tmpfiles.c26
-rw-r--r--src/test/test-udev.c46
-rw-r--r--src/test/test-unit-file.c11
-rw-r--r--src/test/test-unit-name.c2
-rw-r--r--src/test/test-user-util.c27
-rw-r--r--src/test/test-util.c1441
-rw-r--r--src/test/test-web-util.c39
-rw-r--r--src/test/test-xattr-util.c69
-rw-r--r--src/udev/Makefile3
-rw-r--r--src/udev/mtd_probe/mtd_probe.h4
-rw-r--r--src/udev/mtd_probe/probe_smartmedia.c2
-rw-r--r--src/udev/net/ethtool-util.h4
-rw-r--r--src/udev/net/link-config.c1
-rw-r--r--src/udev/net/link-config.h4
-rw-r--r--src/udev/scsi_id/scsi.h4
-rw-r--r--src/udev/scsi_id/scsi_id.h4
-rw-r--r--src/udev/udev-builtin-input_id.c2
-rw-r--r--src/udev/udev-builtin-net_id.c28
-rw-r--r--src/udev/udev-builtin-path_id.c2
-rw-r--r--src/udev/udev-ctrl.c2
-rw-r--r--src/udev/udev-rules.c636
-rw-r--r--src/udev/udevadm-monitor.c4
-rw-r--r--src/udev/udevadm-test.c2
-rw-r--r--src/udev/udevadm-util.h4
-rw-r--r--src/udev/udevadm.c2
-rw-r--r--src/udev/udevd.c9
694 files changed, 24028 insertions, 23736 deletions
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index fd3b241aad..0281409edf 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -62,15 +62,6 @@ static bool arg_allow_interactive_authorization = true;
static bool arg_augment_creds = true;
static usec_t arg_timeout = 0;
-static void pager_open_if_enabled(void) {
-
- /* Cache result before we open the pager */
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
#define NAME_IS_ACQUIRED INT_TO_PTR(1)
#define NAME_IS_ACTIVATABLE INT_TO_PTR(2)
@@ -95,7 +86,7 @@ static int list_bus_names(sd_bus *bus, char **argv) {
if (r < 0)
return log_error_errno(r, "Failed to list names: %m");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
names = hashmap_new(&string_hash_ops);
if (!names)
@@ -258,8 +249,8 @@ static void print_subtree(const char *prefix, const char *path, char **l) {
l++;
}
- vertical = strjoina(prefix, draw_special_char(DRAW_TREE_VERTICAL));
- space = strjoina(prefix, draw_special_char(DRAW_TREE_SPACE));
+ vertical = strjoina(prefix, special_glyph(TREE_VERTICAL));
+ space = strjoina(prefix, special_glyph(TREE_SPACE));
for (;;) {
bool has_more = false;
@@ -280,7 +271,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) {
n++;
}
- printf("%s%s%s\n", prefix, draw_special_char(has_more ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), *l);
+ printf("%s%s%s\n", prefix, special_glyph(has_more ? TREE_BRANCH : TREE_RIGHT), *l);
print_subtree(has_more ? vertical : space, *l, l);
l = n;
@@ -289,7 +280,7 @@ static void print_subtree(const char *prefix, const char *path, char **l) {
static void print_tree(const char *prefix, char **l) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
prefix = strempty(prefix);
@@ -409,7 +400,7 @@ static int tree_one(sd_bus *bus, const char *service, const char *prefix, bool m
p = NULL;
}
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
l = set_get_strv(done);
if (!l)
@@ -438,7 +429,7 @@ static int tree(sd_bus *bus, char **argv) {
if (r < 0)
return log_error_errno(r, "Failed to get name list: %m");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
STRV_FOREACH(i, names) {
int q;
@@ -468,7 +459,7 @@ static int tree(sd_bus *bus, char **argv) {
printf("\n");
if (argv[2]) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
}
@@ -501,8 +492,10 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
} basic;
r = sd_bus_message_peek_type(m, &type, &contents);
- if (r <= 0)
+ if (r < 0)
return r;
+ if (r == 0)
+ return needs_space;
if (bus_type_is_container(type) > 0) {
@@ -533,18 +526,23 @@ static int format_cmdline(sd_bus_message *m, FILE *f, bool needs_space) {
fputc(' ', f);
fprintf(f, "%u", n);
+ needs_space = true;
+
} else if (type == SD_BUS_TYPE_VARIANT) {
if (needs_space)
fputc(' ', f);
fprintf(f, "%s", contents);
+ needs_space = true;
}
- r = format_cmdline(m, f, needs_space || IN_SET(type, SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_VARIANT));
+ r = format_cmdline(m, f, needs_space);
if (r < 0)
return r;
+ needs_space = r > 0;
+
r = sd_bus_message_exit_container(m);
if (r < 0)
return r;
@@ -985,7 +983,7 @@ static int introspect(sd_bus *bus, char **argv) {
return bus_log_parse_error(r);
}
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
name_width = strlen("NAME");
type_width = strlen("TYPE");
@@ -1081,10 +1079,21 @@ static int message_pcap(sd_bus_message *m, FILE *f) {
}
static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FILE *f)) {
- bool added_something = false;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char **i;
+ uint32_t flags = 0;
int r;
+ /* upgrade connection; it's not used for anything else after this call */
+ r = sd_bus_message_new_method_call(bus, &message, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus.Monitoring", "BecomeMonitor");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(message, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
STRV_FOREACH(i, argv+1) {
_cleanup_free_ char *m = NULL;
@@ -1097,34 +1106,38 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL
if (!m)
return log_oom();
- r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', m);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
+ return bus_log_create_error(r);
free(m);
m = strjoin("destination='", *i, "'", NULL);
if (!m)
return log_oom();
- r = sd_bus_add_match(bus, NULL, m, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', m);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
+ return bus_log_create_error(r);
}
STRV_FOREACH(i, arg_matches) {
- r = sd_bus_add_match(bus, NULL, *i, NULL, NULL);
+ r = sd_bus_message_append_basic(message, 's', *i);
if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
-
- added_something = true;
+ return bus_log_create_error(r);
}
- if (!added_something) {
- r = sd_bus_add_match(bus, NULL, "", NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to add match: %m");
+ r = sd_bus_message_close_container(message);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(message, 'u', &flags);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, message, arg_timeout, &error, NULL);
+ if (r < 0) {
+ log_error("%s", bus_error_message(&error, r));
+ return r;
}
log_info("Monitoring bus message stream.");
@@ -1552,7 +1565,7 @@ static int call(sd_bus *bus, char *argv[]) {
if (r == 0 && !arg_quiet) {
if (arg_verbose) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = bus_message_dump(reply, stdout, 0);
if (r < 0)
@@ -1607,7 +1620,7 @@ static int get_property(sd_bus *bus, char *argv[]) {
return bus_log_parse_error(r);
if (arg_verbose) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = bus_message_dump(reply, stdout, BUS_MESSAGE_DUMP_SUBTREE_ONLY);
if (r < 0)
diff --git a/src/grp-boot/bootctl/bootctl.c b/src/grp-boot/bootctl/bootctl.c
index e9baf69f6a..4a356d25d1 100644
--- a/src/grp-boot/bootctl/bootctl.c
+++ b/src/grp-boot/bootctl/bootctl.c
@@ -266,9 +266,9 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
if (r < 0)
return r;
if (r > 0)
- printf(" File: %s/%s/%s (%s)\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name, v);
+ printf(" File: %s/%s/%s (%s)\n", special_glyph(TREE_RIGHT), path, de->d_name, v);
else
- printf(" File: %s/%s/%s\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name);
+ printf(" File: %s/%s/%s\n", special_glyph(TREE_RIGHT), path, de->d_name);
c++;
}
@@ -320,7 +320,7 @@ static int print_efi_option(uint16_t id, bool in_order) {
printf(" ID: 0x%04X\n", id);
printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : "");
printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition));
- printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), path);
+ printf(" File: %s%s\n", special_glyph(TREE_RIGHT), path);
printf("\n");
return 0;
@@ -763,13 +763,13 @@ static int install_variables(const char *esp_path,
"Failed to determine current boot order: %m");
if (first || r == false) {
- r = efi_add_boot_option(slot, "Linux Boot Manager",
+ r = efi_add_boot_option(slot, "Systemd Boot Manager",
part, pstart, psize,
uuid, path);
if (r < 0)
return log_error_errno(r, "Failed to create EFI Boot variable entry: %m");
- log_info("Created EFI boot entry \"Linux Boot Manager\".");
+ log_info("Created EFI boot entry \"Systemd Boot Manager\".");
}
return insert_into_order(slot, first);
@@ -1077,7 +1077,7 @@ static int bootctl_main(int argc, char*argv[]) {
SD_ID128_FORMAT_VAL(loader_part_uuid));
else
printf(" Partition: n/a\n");
- printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), strna(loader_path));
+ printf(" File: %s%s\n", special_glyph(TREE_RIGHT), strna(loader_path));
printf("\n");
} else
printf("System:\n Not booted with EFI\n");
diff --git a/src/grp-boot/systemd-boot/Makefile b/src/grp-boot/systemd-boot/Makefile
index fdb8d42164..5b53fdc7e4 100644
--- a/src/grp-boot/systemd-boot/Makefile
+++ b/src/grp-boot/systemd-boot/Makefile
@@ -90,6 +90,7 @@ systemd_boot_headers = \
src/boot/efi/console.h \
src/boot/efi/graphics.h \
src/boot/efi/pefile.h \
+ src/boot/efi/measure.h \
src/boot/efi/disk.h
systemd_boot_sources = \
@@ -98,6 +99,7 @@ systemd_boot_sources = \
src/boot/efi/graphics.c \
src/boot/efi/pefile.c \
src/boot/efi/disk.c \
+ src/boot/efi/measure.c \
src/boot/efi/boot.c
EXTRA_DIST += $(systemd_boot_sources) $(systemd_boot_headers)
@@ -134,6 +136,7 @@ stub_headers = \
src/boot/efi/disk.h \
src/boot/efi/graphics.h \
src/boot/efi/splash.h \
+ src/boot/efi/measure.h \
src/boot/efi/linux.h
stub_sources = \
@@ -143,6 +146,7 @@ stub_sources = \
src/boot/efi/graphics.c \
src/boot/efi/splash.c \
src/boot/efi/linux.c \
+ src/boot/efi/measure.c \
src/boot/efi/stub.c
EXTRA_DIST += \
diff --git a/src/grp-boot/systemd-boot/boot.c b/src/grp-boot/systemd-boot/boot.c
index 893980071f..30c1ead1aa 100644
--- a/src/grp-boot/systemd-boot/boot.c
+++ b/src/grp-boot/systemd-boot/boot.c
@@ -22,6 +22,7 @@
#include "linux.h"
#include "pefile.h"
#include "util.h"
+#include "measure.h"
#ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI
#define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL
@@ -1644,6 +1645,18 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con
}
loaded_image->LoadOptions = options;
loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16);
+
+#ifdef SD_BOOT_LOG_TPM
+ /* Try to log any options to the TPM, escpecially to catch manually edited options */
+ err = tpm_log_event(SD_TPM_PCR,
+ (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions,
+ loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
+ if (EFI_ERROR(err)) {
+ Print(L"Unable to add image options measurement: %r", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return err;
+ }
+#endif
}
efivar_set_time_usec(L"LoaderTimeExecUSec", 0);
diff --git a/src/grp-boot/systemd-boot/measure.c b/src/grp-boot/systemd-boot/measure.c
new file mode 100644
index 0000000000..7c016387c1
--- /dev/null
+++ b/src/grp-boot/systemd-boot/measure.c
@@ -0,0 +1,312 @@
+/*
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+
+#ifdef SD_BOOT_LOG_TPM
+
+#include <efi.h>
+#include <efilib.h>
+#include "measure.h"
+
+#define EFI_TCG_PROTOCOL_GUID { 0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd} }
+
+typedef struct _TCG_VERSION {
+ UINT8 Major;
+ UINT8 Minor;
+ UINT8 RevMajor;
+ UINT8 RevMinor;
+} TCG_VERSION;
+
+typedef struct _TCG_BOOT_SERVICE_CAPABILITY {
+ UINT8 Size;
+ struct _TCG_VERSION StructureVersion;
+ struct _TCG_VERSION ProtocolSpecVersion;
+ UINT8 HashAlgorithmBitmap;
+ BOOLEAN TPMPresentFlag;
+ BOOLEAN TPMDeactivatedFlag;
+} TCG_BOOT_SERVICE_CAPABILITY;
+
+typedef UINT32 TCG_ALGORITHM_ID;
+#define TCG_ALG_SHA 0x00000004 // The SHA1 algorithm
+
+#define SHA1_DIGEST_SIZE 20
+
+typedef struct _TCG_DIGEST {
+ UINT8 Digest[SHA1_DIGEST_SIZE];
+} TCG_DIGEST;
+
+#define EV_IPL 13
+
+typedef struct _TCG_PCR_EVENT {
+ UINT32 PCRIndex;
+ UINT32 EventType;
+ struct _TCG_DIGEST digest;
+ UINT32 EventSize;
+ UINT8 Event[1];
+} TCG_PCR_EVENT;
+
+INTERFACE_DECL(_EFI_TCG);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG_STATUS_CHECK) (IN struct _EFI_TCG * This,
+ OUT struct _TCG_BOOT_SERVICE_CAPABILITY * ProtocolCapability,
+ OUT UINT32 * TCGFeatureFlags,
+ OUT EFI_PHYSICAL_ADDRESS * EventLogLocation,
+ OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_ALL) (IN struct _EFI_TCG * This,
+ IN UINT8 * HashData,
+ IN UINT64 HashDataLen,
+ IN TCG_ALGORITHM_ID AlgorithmId,
+ IN OUT UINT64 * HashedDataLen, IN OUT UINT8 ** HashedDataResult);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG_LOG_EVENT) (IN struct _EFI_TCG * This,
+ IN struct _TCG_PCR_EVENT * TCGLogData,
+ IN OUT UINT32 * EventNumber, IN UINT32 Flags);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG_PASS_THROUGH_TO_TPM) (IN struct _EFI_TCG * This,
+ IN UINT32 TpmInputParameterBlockSize,
+ IN UINT8 * TpmInputParameterBlock,
+ IN UINT32 TpmOutputParameterBlockSize,
+ IN UINT8 * TpmOutputParameterBlock);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG_HASH_LOG_EXTEND_EVENT) (IN struct _EFI_TCG * This,
+ IN EFI_PHYSICAL_ADDRESS HashData,
+ IN UINT64 HashDataLen,
+ IN TCG_ALGORITHM_ID AlgorithmId,
+ IN struct _TCG_PCR_EVENT * TCGLogData,
+ IN OUT UINT32 * EventNumber,
+ OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry);
+
+typedef struct _EFI_TCG {
+ EFI_TCG_STATUS_CHECK StatusCheck;
+ EFI_TCG_HASH_ALL HashAll;
+ EFI_TCG_LOG_EVENT LogEvent;
+ EFI_TCG_PASS_THROUGH_TO_TPM PassThroughToTPM;
+ EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent;
+} EFI_TCG;
+
+#define EFI_TCG2_PROTOCOL_GUID {0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }}
+
+typedef struct tdEFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL;
+
+typedef struct tdEFI_TCG2_VERSION {
+ UINT8 Major;
+ UINT8 Minor;
+} EFI_TCG2_VERSION;
+
+typedef UINT32 EFI_TCG2_EVENT_LOG_BITMAP;
+typedef UINT32 EFI_TCG2_EVENT_LOG_FORMAT;
+typedef UINT32 EFI_TCG2_EVENT_ALGORITHM_BITMAP;
+
+#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2 0x00000001
+#define EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 0x00000002
+
+typedef struct tdEFI_TCG2_BOOT_SERVICE_CAPABILITY {
+ UINT8 Size;
+ EFI_TCG2_VERSION StructureVersion;
+ EFI_TCG2_VERSION ProtocolVersion;
+ EFI_TCG2_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
+ EFI_TCG2_EVENT_LOG_BITMAP SupportedEventLogs;
+ BOOLEAN TPMPresentFlag;
+ UINT16 MaxCommandSize;
+ UINT16 MaxResponseSize;
+ UINT32 ManufacturerID;
+ UINT32 NumberOfPCRBanks;
+ EFI_TCG2_EVENT_ALGORITHM_BITMAP ActivePcrBanks;
+} EFI_TCG2_BOOT_SERVICE_CAPABILITY;
+
+#define EFI_TCG2_EVENT_HEADER_VERSION 1
+
+typedef struct {
+ UINT32 HeaderSize;
+ UINT16 HeaderVersion;
+ UINT32 PCRIndex;
+ UINT32 EventType;
+} EFI_TCG2_EVENT_HEADER;
+
+typedef struct tdEFI_TCG2_EVENT {
+ UINT32 Size;
+ EFI_TCG2_EVENT_HEADER Header;
+ UINT8 Event[1];
+} EFI_TCG2_EVENT;
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_CAPABILITY) (IN EFI_TCG2_PROTOCOL * This,
+ IN OUT EFI_TCG2_BOOT_SERVICE_CAPABILITY * ProtocolCapability);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_EVENT_LOG) (IN EFI_TCG2_PROTOCOL * This,
+ IN EFI_TCG2_EVENT_LOG_FORMAT EventLogFormat,
+ OUT EFI_PHYSICAL_ADDRESS * EventLogLocation,
+ OUT EFI_PHYSICAL_ADDRESS * EventLogLastEntry,
+ OUT BOOLEAN * EventLogTruncated);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG2_HASH_LOG_EXTEND_EVENT) (IN EFI_TCG2_PROTOCOL * This,
+ IN UINT64 Flags,
+ IN EFI_PHYSICAL_ADDRESS DataToHash,
+ IN UINT64 DataToHashLen, IN EFI_TCG2_EVENT * EfiTcgEvent);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG2_SUBMIT_COMMAND) (IN EFI_TCG2_PROTOCOL * This,
+ IN UINT32 InputParameterBlockSize,
+ IN UINT8 * InputParameterBlock,
+ IN UINT32 OutputParameterBlockSize, IN UINT8 * OutputParameterBlock);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, OUT UINT32 * ActivePcrBanks);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG2_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This, IN UINT32 ActivePcrBanks);
+
+typedef EFI_STATUS(EFIAPI * EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS) (IN EFI_TCG2_PROTOCOL * This,
+ OUT UINT32 * OperationPresent, OUT UINT32 * Response);
+
+typedef struct tdEFI_TCG2_PROTOCOL {
+ EFI_TCG2_GET_CAPABILITY GetCapability;
+ EFI_TCG2_GET_EVENT_LOG GetEventLog;
+ EFI_TCG2_HASH_LOG_EXTEND_EVENT HashLogExtendEvent;
+ EFI_TCG2_SUBMIT_COMMAND SubmitCommand;
+ EFI_TCG2_GET_ACTIVE_PCR_BANKS GetActivePcrBanks;
+ EFI_TCG2_SET_ACTIVE_PCR_BANKS SetActivePcrBanks;
+ EFI_TCG2_GET_RESULT_OF_SET_ACTIVE_PCR_BANKS GetResultOfSetActivePcrBanks;
+} EFI_TCG2;
+
+
+static EFI_STATUS tpm1_measure_to_pcr_and_event_log(const EFI_TCG *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer,
+ UINTN buffer_size, const CHAR16 *description) {
+ EFI_STATUS status;
+ TCG_PCR_EVENT *tcg_event;
+ UINT32 event_number;
+ EFI_PHYSICAL_ADDRESS event_log_last;
+ UINTN desc_len;
+
+ desc_len = (StrLen(description) + 1) * sizeof(CHAR16);
+
+ tcg_event = AllocateZeroPool(desc_len + sizeof(TCG_PCR_EVENT));
+
+ if (tcg_event == NULL)
+ return EFI_OUT_OF_RESOURCES;
+
+ tcg_event->EventSize = desc_len;
+ CopyMem((VOID *) & tcg_event->Event[0], (VOID *) description, desc_len);
+
+ tcg_event->PCRIndex = pcrindex;
+ tcg_event->EventType = EV_IPL;
+
+ event_number = 1;
+ status = uefi_call_wrapper(tcg->HashLogExtendEvent, 7,
+ tcg, buffer, buffer_size, TCG_ALG_SHA, tcg_event, &event_number, &event_log_last);
+
+ if (EFI_ERROR(status))
+ return status;
+
+ uefi_call_wrapper(BS->FreePool, 1, tcg_event);
+
+ return EFI_SUCCESS;
+}
+
+
+static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer,
+ UINT64 buffer_size, const CHAR16 *description) {
+ EFI_STATUS status;
+ EFI_TCG2_EVENT *tcg_event;
+ UINTN desc_len;
+
+ desc_len = StrLen(description) * sizeof(CHAR16);
+
+ tcg_event = AllocateZeroPool(sizeof(*tcg_event) - sizeof(tcg_event->Event) + desc_len + 1);
+
+ if (tcg_event == NULL)
+ return EFI_OUT_OF_RESOURCES;
+
+ tcg_event->Size = sizeof(EFI_TCG2_EVENT) - sizeof(tcg_event->Event) + desc_len + 1;
+ tcg_event->Header.HeaderSize = sizeof(EFI_TCG2_EVENT_HEADER);
+ tcg_event->Header.HeaderVersion = EFI_TCG2_EVENT_HEADER_VERSION;
+ tcg_event->Header.PCRIndex = pcrindex;
+ tcg_event->Header.EventType = EV_IPL;
+
+ CopyMem((VOID *) tcg_event->Event, (VOID *) description, desc_len);
+
+ status = uefi_call_wrapper(tcg->HashLogExtendEvent, 5, tcg, 0, buffer, buffer_size, tcg_event);
+
+ uefi_call_wrapper(BS->FreePool, 1, tcg_event);
+
+ if (EFI_ERROR(status))
+ return status;
+
+ return EFI_SUCCESS;
+}
+
+static EFI_TCG * tcg1_interface_check(void) {
+ EFI_GUID tpm_guid = EFI_TCG_PROTOCOL_GUID;
+ EFI_STATUS status;
+ EFI_TCG *tcg;
+ TCG_BOOT_SERVICE_CAPABILITY capability;
+ UINT32 features;
+ EFI_PHYSICAL_ADDRESS event_log_location;
+ EFI_PHYSICAL_ADDRESS event_log_last_entry;
+
+ status = LibLocateProtocol(&tpm_guid, (void **) &tcg);
+
+ if (EFI_ERROR(status))
+ return NULL;
+
+ capability.Size = (UINT8) sizeof(capability);
+ status = uefi_call_wrapper(tcg->StatusCheck, 5, tcg, &capability, &features, &event_log_location, &event_log_last_entry);
+
+ if (EFI_ERROR(status))
+ return NULL;
+
+ if (capability.TPMDeactivatedFlag)
+ return NULL;
+
+ if (!capability.TPMPresentFlag)
+ return NULL;
+
+ return tcg;
+}
+
+static EFI_TCG2 * tcg2_interface_check(void) {
+ EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID;
+ EFI_STATUS status;
+ EFI_TCG2 *tcg;
+ EFI_TCG2_BOOT_SERVICE_CAPABILITY capability;
+
+ status = LibLocateProtocol(&tpm2_guid, (void **) &tcg);
+
+ if (EFI_ERROR(status))
+ return NULL;
+
+ capability.Size = (UINT8) sizeof(capability);
+ status = uefi_call_wrapper(tcg->GetCapability, 2, tcg, &capability);
+
+ if (EFI_ERROR(status))
+ return NULL;
+
+ if (!capability.TPMPresentFlag)
+ return NULL;
+
+ return tcg;
+}
+
+EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description) {
+ EFI_TCG *tpm1;
+ EFI_TCG2 *tpm2;
+
+ tpm2 = tcg2_interface_check();
+ if (tpm2)
+ return tpm2_measure_to_pcr_and_event_log(tpm2, pcrindex, buffer, buffer_size, description);
+
+ tpm1 = tcg1_interface_check();
+ if (tpm1)
+ return tpm1_measure_to_pcr_and_event_log(tpm1, pcrindex, buffer, buffer_size, description);
+
+ /* No active TPM found, so don't return an error */
+ return EFI_SUCCESS;
+}
+
+#endif
diff --git a/src/grp-boot/systemd-boot/measure.h b/src/grp-boot/systemd-boot/measure.h
new file mode 100644
index 0000000000..a2cfe817d0
--- /dev/null
+++ b/src/grp-boot/systemd-boot/measure.h
@@ -0,0 +1,21 @@
+/*
+ * This program 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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ */
+#ifndef __SDBOOT_MEASURE_H
+#define __SDBOOT_MEASURE_H
+
+#ifndef SD_TPM_PCR
+#define SD_TPM_PCR 8
+#endif
+
+EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description);
+#endif
diff --git a/src/grp-boot/systemd-boot/splash.c b/src/grp-boot/systemd-boot/splash.c
index b1cc2c0b72..c0ef7f64fe 100644
--- a/src/grp-boot/systemd-boot/splash.c
+++ b/src/grp-boot/systemd-boot/splash.c
@@ -281,9 +281,9 @@ EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_
if (EFI_ERROR(err))
goto err;
- if(dib->x < GraphicsOutput->Mode->Info->HorizontalResolution)
+ if (dib->x < GraphicsOutput->Mode->Info->HorizontalResolution)
x_pos = (GraphicsOutput->Mode->Info->HorizontalResolution - dib->x) / 2;
- if(dib->y < GraphicsOutput->Mode->Info->VerticalResolution)
+ if (dib->y < GraphicsOutput->Mode->Info->VerticalResolution)
y_pos = (GraphicsOutput->Mode->Info->VerticalResolution - dib->y) / 2;
uefi_call_wrapper(GraphicsOutput->Blt, 10, GraphicsOutput,
diff --git a/src/grp-boot/systemd-boot/stub.c b/src/grp-boot/systemd-boot/stub.c
index 9633bc1792..1e250f34f4 100644
--- a/src/grp-boot/systemd-boot/stub.c
+++ b/src/grp-boot/systemd-boot/stub.c
@@ -20,6 +20,7 @@
#include "pefile.h"
#include "splash.h"
#include "util.h"
+#include "measure.h"
/* magic string to find in the binary image */
static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " VERSION " ####";
@@ -97,6 +98,18 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
for (i = 0; i < cmdline_len; i++)
line[i] = options[i];
cmdline = line;
+
+#ifdef SD_BOOT_LOG_TPM
+ /* Try to log any options to the TPM, escpecially manually edited options */
+ err = tpm_log_event(SD_TPM_PCR,
+ (EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions,
+ loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
+ if (EFI_ERROR(err)) {
+ Print(L"Unable to add image options measurement: %r", err);
+ uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
+ return err;
+ }
+#endif
}
/* export the device path this image is started from */
diff --git a/src/grp-coredump/coredumpctl/coredumpctl.c b/src/grp-coredump/coredumpctl/coredumpctl.c
index 5f4f710a0c..dc95da3613 100644
--- a/src/grp-coredump/coredumpctl/coredumpctl.c
+++ b/src/grp-coredump/coredumpctl/coredumpctl.c
@@ -54,7 +54,7 @@ static enum {
} arg_action = ACTION_LIST;
static const char* arg_field = NULL;
static const char *arg_directory = NULL;
-static int arg_no_pager = false;
+static bool arg_no_pager = false;
static int arg_no_legend = false;
static int arg_one = false;
static FILE* arg_output = NULL;
@@ -664,7 +664,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
#endif
} else {
if (r == -ENOENT)
- log_error("Cannot retrieve coredump from journal nor disk.");
+ log_error("Cannot retrieve coredump from journal or disk.");
else
log_error_errno(r, "Failed to retrieve COREDUMP field: %m");
goto error;
@@ -852,9 +852,7 @@ int main(int argc, char *argv[]) {
case ACTION_LIST:
case ACTION_INFO:
- if (!arg_no_pager)
- pager_open(false);
-
+ pager_open(arg_no_pager, false);
r = dump_list(j);
break;
diff --git a/src/grp-coredump/systemd-coredump/coredump.c b/src/grp-coredump/systemd-coredump/coredump.c
index 64ce54d97f..bf0e0a038b 100644
--- a/src/grp-coredump/systemd-coredump/coredump.c
+++ b/src/grp-coredump/systemd-coredump/coredump.c
@@ -49,6 +49,7 @@
#include "journald-native.h"
#include "log.h"
#include "macro.h"
+#include "missing.h"
#include "mkdir.h"
#include "parse-util.h"
#include "process-util.h"
@@ -212,6 +213,10 @@ static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) {
#define filename_escape(s) xescape((s), "./ ")
+static inline const char *coredump_tmpfile_name(const char *s) {
+ return s ? s : "(unnamed temporary file)";
+}
+
static int fix_permissions(
int fd,
const char *filename,
@@ -219,8 +224,9 @@ static int fix_permissions(
const char *context[_CONTEXT_MAX],
uid_t uid) {
+ int r;
+
assert(fd >= 0);
- assert(filename);
assert(target);
assert(context);
@@ -230,10 +236,11 @@ static int fix_permissions(
(void) fix_xattr(fd, context);
if (fsync(fd) < 0)
- return log_error_errno(errno, "Failed to sync coredump %s: %m", filename);
+ return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
- if (rename(filename, target) < 0)
- return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
+ r = link_tmpfile(fd, filename, target);
+ if (r < 0)
+ return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
return 0;
}
@@ -335,15 +342,11 @@ static int save_external_coredump(
if (r < 0)
return log_error_errno(r, "Failed to determine coredump file name: %m");
- r = tempfn_random(fn, NULL, &tmp);
- if (r < 0)
- return log_error_errno(r, "Failed to determine temporary file name: %m");
-
mkdir_p_label("/var/lib/systemd/coredump", 0755);
- fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+ fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
if (fd < 0)
- return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
+ return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn);
r = copy_bytes(input_fd, fd, max_size, false);
if (r == -EFBIG) {
@@ -358,12 +361,12 @@ static int save_external_coredump(
}
if (fstat(fd, &st) < 0) {
- log_error_errno(errno, "Failed to fstat coredump %s: %m", tmp);
+ log_error_errno(errno, "Failed to fstat coredump %s: %m", coredump_tmpfile_name(tmp));
goto fail;
}
if (lseek(fd, 0, SEEK_SET) == (off_t) -1) {
- log_error_errno(errno, "Failed to seek on %s: %m", tmp);
+ log_error_errno(errno, "Failed to seek on %s: %m", coredump_tmpfile_name(tmp));
goto fail;
}
@@ -381,21 +384,15 @@ static int save_external_coredump(
goto uncompressed;
}
- r = tempfn_random(fn_compressed, NULL, &tmp_compressed);
- if (r < 0) {
- log_error_errno(r, "Failed to determine temporary file name for %s: %m", fn_compressed);
- goto uncompressed;
- }
-
- fd_compressed = open(tmp_compressed, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
+ fd_compressed = open_tmpfile_linkable(fn_compressed, O_RDWR|O_CLOEXEC, &tmp_compressed);
if (fd_compressed < 0) {
- log_error_errno(errno, "Failed to create file %s: %m", tmp_compressed);
+ log_error_errno(fd_compressed, "Failed to create temporary file for coredump %s: %m", fn_compressed);
goto uncompressed;
}
r = compress_stream(fd, fd_compressed, -1);
if (r < 0) {
- log_error_errno(r, "Failed to compress %s: %m", tmp_compressed);
+ log_error_errno(r, "Failed to compress %s: %m", coredump_tmpfile_name(tmp_compressed));
goto fail_compressed;
}
@@ -404,7 +401,8 @@ static int save_external_coredump(
goto fail_compressed;
/* OK, this worked, we can get rid of the uncompressed version now */
- unlink_noerrno(tmp);
+ if (tmp)
+ unlink_noerrno(tmp);
*ret_filename = fn_compressed; /* compressed */
*ret_node_fd = fd_compressed; /* compressed */
@@ -417,7 +415,8 @@ static int save_external_coredump(
return 0;
fail_compressed:
- (void) unlink(tmp_compressed);
+ if (tmp_compressed)
+ (void) unlink(tmp_compressed);
}
uncompressed:
@@ -438,7 +437,8 @@ uncompressed:
return 0;
fail:
- (void) unlink(tmp);
+ if (tmp)
+ (void) unlink(tmp);
return r;
}
@@ -739,15 +739,16 @@ static int process_socket(int fd) {
.msg_iovlen = 1,
};
ssize_t n;
- int l;
+ ssize_t l;
if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) {
r = log_oom();
goto finish;
}
- if (ioctl(fd, FIONREAD, &l) < 0) {
- r = log_error_errno(errno, "FIONREAD failed: %m");
+ l = next_datagram_size_fd(fd);
+ if (l < 0) {
+ r = log_error_errno(l, "Failed to determine datagram size to read: %m");
goto finish;
}
@@ -847,7 +848,7 @@ static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd)
if (fd < 0)
return log_error_errno(errno, "Failed to create coredump socket: %m");
- if (connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to connect to coredump service: %m");
for (i = 0; i < n_iovec; i++) {
@@ -1095,7 +1096,7 @@ static int process_kernel(int argc, char* argv[]) {
IOVEC_SET_STRING(iovec[n_iovec++], core_environ);
}
- core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL);
+ core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000");
IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp);
IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1");
diff --git a/src/grp-coredump/systemd-coredump/stacktrace.c b/src/grp-coredump/systemd-coredump/stacktrace.c
index 68806992fc..cc4dad9465 100644
--- a/src/grp-coredump/systemd-coredump/stacktrace.c
+++ b/src/grp-coredump/systemd-coredump/stacktrace.c
@@ -91,7 +91,7 @@ static int frame_callback(Dwfl_Frame *frame, void *userdata) {
}
fprintf(c->f, "#%-2u 0x%016" PRIx64 " %s (%s)\n", c->n_frame, (uint64_t) pc, strna(symbol), strna(fname));
- c->n_frame ++;
+ c->n_frame++;
return DWARF_CB_OK;
}
@@ -117,7 +117,7 @@ static int thread_callback(Dwfl_Thread *thread, void *userdata) {
if (dwfl_thread_getframes(thread, frame_callback, c) < 0)
return DWARF_CB_ABORT;
- c->n_thread ++;
+ c->n_thread++;
return DWARF_CB_OK;
}
diff --git a/src/journal-remote/.gitignore b/src/grp-journal-remote/.gitignore
index 06847b65d4..06847b65d4 100644
--- a/src/journal-remote/.gitignore
+++ b/src/grp-journal-remote/.gitignore
diff --git a/src/journal-remote/browse.html b/src/grp-journal-remote/browse.html
index 3594f70c87..32848c7673 100644
--- a/src/journal-remote/browse.html
+++ b/src/grp-journal-remote/browse.html
@@ -391,7 +391,7 @@
entry = document.getElementById("tableentry");
var buf = "";
- for (var key in d){
+ for (var key in d) {
var data = d[key];
if (data == null)
diff --git a/src/journal-remote/log-generator.py b/src/grp-journal-remote/log-generator.py
index fd6964e758..fd6964e758 100755
--- a/src/journal-remote/log-generator.py
+++ b/src/grp-journal-remote/log-generator.py
diff --git a/src/journal-remote/microhttpd-util.c b/src/grp-journal-remote/microhttpd-util.c
index c65c43186f..c65c43186f 100644
--- a/src/journal-remote/microhttpd-util.c
+++ b/src/grp-journal-remote/microhttpd-util.c
diff --git a/src/journal-remote/microhttpd-util.h b/src/grp-journal-remote/microhttpd-util.h
index 70c4d29c0f..ea160f212b 100644
--- a/src/journal-remote/microhttpd-util.h
+++ b/src/grp-journal-remote/microhttpd-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <microhttpd.h>
#include <stdarg.h>
diff --git a/src/systemd-bus-proxyd/Makefile b/src/grp-journal-remote/systemd-journal-gatewayd/Makefile
index 75e98b1633..ed1dfbf301 100644
--- a/src/systemd-bus-proxyd/Makefile
+++ b/src/grp-journal-remote/systemd-journal-gatewayd/Makefile
@@ -20,37 +20,49 @@
#
# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
+include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
-systemd_bus_proxyd_SOURCES = \
- src/bus-proxyd/bus-proxyd.c
+ifneq ($(HAVE_MICROHTTPD),)
+gatewayddocumentrootdir=$(pkgdatadir)/gatewayd
-systemd_bus_proxyd_LDADD = \
- libbus-proxy-core.la \
- libshared.la
+libexec_PROGRAMS += \
+ systemd-journal-gatewayd
-nodist_systemunit_DATA += \
- units/systemd-bus-proxyd.service
+systemd_journal_gatewayd_SOURCES = \
+ src/journal-remote/journal-gatewayd.c \
+ src/journal-remote/microhttpd-util.h \
+ src/journal-remote/microhttpd-util.c
-dist_systemunit_DATA += \
- units/systemd-bus-proxyd.socket
+systemd_journal_gatewayd_LDADD = \
+ libshared.la \
+ $(MICROHTTPD_LIBS)
-nodist_userunit_DATA += \
- units/user/systemd-bus-proxyd.service
+ifneq ($(HAVE_GNUTLS),)
+systemd_journal_gatewayd_LDADD += \
+ $(GNUTLS_LIBS)
+endif # HAVE_GNUTLS
-dist_userunit_DATA += \
- units/user/systemd-bus-proxyd.socket
+systemd_journal_gatewayd_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(MICROHTTPD_CFLAGS)
-EXTRA_DIST += \
- units/systemd-bus-proxyd.service.m4.in \
- units/user/systemd-bus-proxyd.service.in
+systemd_journal_gatewayd_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DDOCUMENT_ROOT=\"$(gatewayddocumentrootdir)\"
-ifneq ($(HAVE_SMACK),)
-bus-proxyd-set-cap-hook:
- -$(SETCAP) cap_mac_admin+ei $(DESTDIR)$(libexecdir)/systemd-bus-proxyd
+dist_systemunit_DATA += \
+ units/systemd-journal-gatewayd.socket
-INSTALL_EXEC_HOOKS += bus-proxyd-set-cap-hook
-endif # HAVE_SMACK
+nodist_systemunit_DATA += \
+ units/systemd-journal-gatewayd.service
+
+dist_gatewayddocumentroot_DATA = \
+ src/journal-remote/browse.html
+
+endif # HAVE_MICROHTTPD
+
+EXTRA_DIST += \
+ units/systemd-journal-gatewayd.service.in
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/journal-remote/journal-gatewayd.c b/src/grp-journal-remote/systemd-journal-gatewayd/journal-gatewayd.c
index 0e27a80cf2..1cfb5e2c9c 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/grp-journal-remote/systemd-journal-gatewayd/journal-gatewayd.c
@@ -122,12 +122,14 @@ static int open_journal(RequestMeta *m) {
}
static int request_meta_ensure_tmp(RequestMeta *m) {
+ assert(m);
+
if (m->tmp)
rewind(m->tmp);
else {
int fd;
- fd = open_tmpfile("/tmp", O_RDWR|O_CLOEXEC);
+ fd = open_tmpfile_unlinkable("/tmp", O_RDWR|O_CLOEXEC);
if (fd < 0)
return fd;
diff --git a/src/journal-remote/Makefile b/src/grp-journal-remote/systemd-journal-remote/Makefile
index a95f6ab31a..5e730f9fa6 100644
--- a/src/journal-remote/Makefile
+++ b/src/grp-journal-remote/systemd-journal-remote/Makefile
@@ -20,7 +20,7 @@
#
# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
+include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
ifneq ($(HAVE_MICROHTTPD),)
@@ -82,32 +82,4 @@ EXTRA_DIST += \
src/journal-remote/log-generator.py
endif # HAVE_MICROHTTPD
-ifneq ($(HAVE_LIBCURL),)
-libexec_PROGRAMS += \
- systemd-journal-upload
-
-systemd_journal_upload_SOURCES = \
- src/journal-remote/journal-upload.h \
- src/journal-remote/journal-upload.c \
- src/journal-remote/journal-upload-journal.c
-
-systemd_journal_upload_CFLAGS = \
- $(AM_CFLAGS) \
- $(LIBCURL_CFLAGS)
-
-systemd_journal_upload_LDADD = \
- libshared.la \
- $(LIBCURL_LIBS)
-
-nodist_systemunit_DATA += \
- units/systemd-journal-upload.service
-
-nodist_pkgsysconf_DATA += \
- src/journal-remote/journal-upload.conf
-endif # HAVE_LIBCURL
-
-EXTRA_DIST += \
- units/systemd-journal-upload.service.in \
- src/journal-remote/journal-upload.conf.in
-
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/journal-remote/journal-remote-parse.c b/src/grp-journal-remote/systemd-journal-remote/journal-remote-parse.c
index 3864647eb7..9ba9ee3fc0 100644
--- a/src/journal-remote/journal-remote-parse.c
+++ b/src/grp-journal-remote/systemd-journal-remote/journal-remote-parse.c
@@ -485,7 +485,7 @@ int process_source(RemoteSource *source, bool compress, bool seal) {
}
target = source->size;
- while (target > 16 * LINE_CHUNK && remain < target / 2)
+ while (target > 16 * LINE_CHUNK && source->filled < target / 2)
target /= 2;
if (target < source->size) {
char *tmp;
diff --git a/src/journal-remote/journal-remote-parse.h b/src/grp-journal-remote/systemd-journal-remote/journal-remote-parse.h
index 91c5650798..4f47ea89d6 100644
--- a/src/journal-remote/journal-remote-parse.h
+++ b/src/grp-journal-remote/systemd-journal-remote/journal-remote-parse.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <systemd/sd-event.h>
#include "journal-remote-write.h"
diff --git a/src/journal-remote/journal-remote-write.c b/src/grp-journal-remote/systemd-journal-remote/journal-remote-write.c
index 5fab74e5cc..7bba52566e 100644
--- a/src/journal-remote/journal-remote-write.c
+++ b/src/grp-journal-remote/systemd-journal-remote/journal-remote-write.c
@@ -54,7 +54,7 @@ void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
**********************************************************************/
static int do_rotate(JournalFile **f, bool compress, bool seal) {
- int r = journal_file_rotate(f, compress, seal);
+ int r = journal_file_rotate(f, compress, seal, NULL);
if (r < 0) {
if (*f)
log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
diff --git a/src/journal-remote/journal-remote-write.h b/src/grp-journal-remote/systemd-journal-remote/journal-remote-write.h
index 6b645a353c..53ba45fc04 100644
--- a/src/journal-remote/journal-remote-write.h
+++ b/src/grp-journal-remote/systemd-journal-remote/journal-remote-write.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-
#include "journal-file.h"
typedef struct RemoteServer RemoteServer;
diff --git a/src/journal-remote/journal-remote.c b/src/grp-journal-remote/systemd-journal-remote/journal-remote.c
index db8772d3e6..9b4d12d336 100644
--- a/src/journal-remote/journal-remote.c
+++ b/src/grp-journal-remote/systemd-journal-remote/journal-remote.c
@@ -203,7 +203,7 @@ static int open_output(Writer *w, const char* host) {
O_RDWR|O_CREAT, 0640,
arg_compress, arg_seal,
&w->metrics,
- w->mmap,
+ w->mmap, NULL,
NULL, &w->journal);
if (r < 0)
log_error_errno(r, "Failed to open output journal %s: %m",
@@ -434,7 +434,7 @@ static int add_raw_socket(RemoteServer *s, int fd) {
return r;
fd_ = -1;
- s->active ++;
+ s->active++;
return 0;
}
@@ -742,7 +742,7 @@ static int setup_microhttpd_server(RemoteServer *s,
goto error;
}
- s->active ++;
+ s->active++;
return 0;
error:
diff --git a/src/journal-remote/journal-remote.conf.in b/src/grp-journal-remote/systemd-journal-remote/journal-remote.conf.in
index 7122d63362..7122d63362 100644
--- a/src/journal-remote/journal-remote.conf.in
+++ b/src/grp-journal-remote/systemd-journal-remote/journal-remote.conf.in
diff --git a/src/journal-remote/journal-remote.h b/src/grp-journal-remote/systemd-journal-remote/journal-remote.h
index de83388eef..58487e498a 100644
--- a/src/journal-remote/journal-remote.h
+++ b/src/grp-journal-remote/systemd-journal-remote/journal-remote.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-
#include <systemd/sd-event.h>
#include "hashmap.h"
diff --git a/src/systemd-bootchart/Makefile b/src/grp-journal-remote/systemd-journal-upload/Makefile
index 26be9339a9..4d8fba8fd0 100644
--- a/src/systemd-bootchart/Makefile
+++ b/src/grp-journal-remote/systemd-journal-upload/Makefile
@@ -20,32 +20,35 @@
#
# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
+include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
-ifneq ($(ENABLE_BOOTCHART),)
-systemd_bootchart_SOURCES = \
- src/bootchart/bootchart.c \
- src/bootchart/bootchart.h \
- src/bootchart/store.c \
- src/bootchart/store.h \
- src/bootchart/svg.c \
- src/bootchart/svg.h
+ifneq ($(HAVE_LIBCURL),)
+libexec_PROGRAMS += \
+ systemd-journal-upload
-systemd_bootchart_LDADD = \
- libshared.la
+systemd_journal_upload_SOURCES = \
+ src/journal-remote/journal-upload.h \
+ src/journal-remote/journal-upload.c \
+ src/journal-remote/journal-upload-journal.c
-libexec_PROGRAMS += \
- systemd-bootchart
+systemd_journal_upload_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(LIBCURL_CFLAGS)
-dist_pkgsysconf_DATA += \
- src/bootchart/bootchart.conf
+systemd_journal_upload_LDADD = \
+ libshared.la \
+ $(LIBCURL_LIBS)
nodist_systemunit_DATA += \
- units/systemd-bootchart.service
-endif # ENABLE_BOOTCHART
+ units/systemd-journal-upload.service
+
+nodist_pkgsysconf_DATA += \
+ src/journal-remote/journal-upload.conf
+endif
EXTRA_DIST += \
- units/systemd-bootchart.service.in
+ units/systemd-journal-upload.service.in \
+ src/journal-remote/journal-upload.conf.in
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/journal-remote/journal-upload-journal.c b/src/grp-journal-remote/systemd-journal-upload/journal-upload-journal.c
index fc8f63c9e3..aef095c8c9 100644
--- a/src/journal-remote/journal-upload-journal.c
+++ b/src/grp-journal-remote/systemd-journal-upload/journal-upload-journal.c
@@ -25,6 +25,7 @@
#include "log.h"
#include "utf8.h"
#include "util.h"
+#include <systemd/sd-daemon.h>
/**
* Write up to size bytes to buf. Return negative on error, and number of
@@ -52,7 +53,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
/* not enough space */
return pos;
- u->entry_state ++;
+ u->entry_state++;
if (pos + r == size) {
/* exactly one character short, but we don't need it */
@@ -76,7 +77,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
/* not enough space */
return pos;
- u->entry_state ++;
+ u->entry_state++;
if (r + pos == size) {
/* exactly one character short, but we don't need it */
@@ -101,7 +102,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
/* not enough space */
return pos;
- u->entry_state ++;
+ u->entry_state++;
if (r + pos == size) {
/* exactly one character short, but we don't need it */
@@ -126,7 +127,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
/* not enough space */
return pos;
- u->entry_state ++;
+ u->entry_state++;
if (r + pos == size) {
/* exactly one character short, but we don't need it */
@@ -156,7 +157,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
continue;
}
- u->entry_state ++;
+ u->entry_state++;
} /* fall through */
case ENTRY_TEXT_FIELD:
@@ -206,7 +207,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
pos += len + 1;
u->field_pos = len + 1;
- u->entry_state ++;
+ u->entry_state++;
} /* fall through */
case ENTRY_BINARY_FIELD_SIZE: {
@@ -220,7 +221,7 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
memcpy(buf + pos, &le64, 8);
pos += 8;
- u->entry_state ++;
+ u->entry_state++;
continue;
}
@@ -230,8 +231,8 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
return pos;
buf[pos++] = '\n';
- u->entry_state ++;
- u->entries_sent ++;
+ u->entry_state++;
+ u->entries_sent++;
return pos;
@@ -242,6 +243,22 @@ static ssize_t write_entry(char *buf, size_t size, Uploader *u) {
assert_not_reached("WTF?");
}
+static inline void check_update_watchdog(Uploader *u) {
+ usec_t after;
+ usec_t elapsed_time;
+
+ if (u->watchdog_usec <= 0)
+ return;
+
+ after = now(CLOCK_MONOTONIC);
+ elapsed_time = usec_sub(after, u->watchdog_timestamp);
+ if (elapsed_time > u->watchdog_usec / 2) {
+ log_debug("Update watchdog timer");
+ sd_notify(false, "WATCHDOG=1");
+ u->watchdog_timestamp = after;
+ }
+}
+
static size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void *userp) {
Uploader *u = userp;
int r;
@@ -252,6 +269,8 @@ static size_t journal_input_callback(void *buf, size_t size, size_t nmemb, void
assert(u);
assert(nmemb <= SSIZE_MAX / size);
+ check_update_watchdog(u);
+
j = u->journal;
while (j && filled < size * nmemb) {
diff --git a/src/journal-remote/journal-upload.c b/src/grp-journal-remote/systemd-journal-upload/journal-upload.c
index be3012209c..e622f6c1e1 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/grp-journal-remote/systemd-journal-upload/journal-upload.c
@@ -75,7 +75,7 @@ static void close_fd_input(Uploader *u);
curl_easy_strerror(code)); \
cmd; \
} \
- } while(0)
+ } while (0)
static size_t output_callback(char *buf,
size_t size,
@@ -463,6 +463,8 @@ static int setup_uploader(Uploader *u, const char *url, const char *state_file)
if (r < 0)
return log_error_errno(r, "Failed to set up signals: %m");
+ (void) sd_watchdog_enabled(false, &u->watchdog_usec);
+
return load_cursor_state(u);
}
@@ -494,6 +496,7 @@ static int perform_upload(Uploader *u) {
assert(u);
+ u->watchdog_timestamp = now(CLOCK_MONOTONIC);
code = curl_easy_perform(u->easy);
if (code) {
if (u->error[0])
diff --git a/src/journal-remote/journal-upload.conf.in b/src/grp-journal-remote/systemd-journal-upload/journal-upload.conf.in
index c5670682e8..c5670682e8 100644
--- a/src/journal-remote/journal-upload.conf.in
+++ b/src/grp-journal-remote/systemd-journal-upload/journal-upload.conf.in
diff --git a/src/journal-remote/journal-upload.h b/src/grp-journal-remote/systemd-journal-upload/journal-upload.h
index 40f64dfc60..4a521bf78f 100644
--- a/src/journal-remote/journal-upload.h
+++ b/src/grp-journal-remote/systemd-journal-upload/journal-upload.h
@@ -4,6 +4,7 @@
#include <systemd/sd-event.h>
#include <systemd/sd-journal.h>
+#include "time-util.h"
typedef enum {
ENTRY_CURSOR = 0, /* Nothing actually written yet. */
@@ -48,6 +49,8 @@ typedef struct Uploader {
size_t entries_sent;
char *last_cursor, *current_cursor;
+ usec_t watchdog_timestamp;
+ usec_t watchdog_usec;
} Uploader;
#define JOURNAL_UPLOAD_POLL_TIMEOUT (10 * USEC_PER_SEC)
diff --git a/src/journal/.gitignore b/src/grp-journal/.gitignore
index 04d5852547..04d5852547 100644
--- a/src/journal/.gitignore
+++ b/src/grp-journal/.gitignore
diff --git a/src/grp-journal/Makefile b/src/grp-journal/Makefile
new file mode 100644
index 0000000000..188a3487e4
--- /dev/null
+++ b/src/grp-journal/Makefile
@@ -0,0 +1,170 @@
+# -*- Mode: makefile; indent-tabs-mode: t -*-
+#
+# This file is part of systemd.
+#
+# Copyright 2010-2012 Lennart Poettering
+# Copyright 2010-2012 Kay Sievers
+# Copyright 2013 Zbigniew Jędrzejewski-Szmek
+# Copyright 2013 David Strauss
+# Copyright 2016 Luke Shumaker
+#
+# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
+include $(topsrcdir)/build-aux/Makefile.head.mk
+
+test_journal_SOURCES = \
+ src/journal/test-journal.c
+
+test_journal_LDADD = \
+ libjournal-core.la
+
+test_journal_send_SOURCES = \
+ src/journal/test-journal-send.c
+
+test_journal_send_LDADD = \
+ libjournal-core.la
+
+test_journal_syslog_SOURCES = \
+ src/journal/test-journal-syslog.c
+
+test_journal_syslog_LDADD = \
+ libjournal-core.la
+
+test_journal_match_SOURCES = \
+ src/journal/test-journal-match.c
+
+test_journal_match_LDADD = \
+ libjournal-core.la
+
+test_journal_enum_SOURCES = \
+ src/journal/test-journal-enum.c
+
+test_journal_enum_LDADD = \
+ libjournal-core.la
+
+test_journal_stream_SOURCES = \
+ src/journal/test-journal-stream.c
+
+test_journal_stream_LDADD = \
+ libjournal-core.la
+
+test_journal_flush_SOURCES = \
+ src/journal/test-journal-flush.c
+
+test_journal_flush_LDADD = \
+ libjournal-core.la
+
+test_journal_init_SOURCES = \
+ src/journal/test-journal-init.c
+
+test_journal_init_LDADD = \
+ libjournal-core.la
+
+test_journal_verify_SOURCES = \
+ src/journal/test-journal-verify.c
+
+test_journal_verify_LDADD = \
+ libjournal-core.la
+
+test_journal_interleaving_SOURCES = \
+ src/journal/test-journal-interleaving.c
+
+test_journal_interleaving_LDADD = \
+ libjournal-core.la
+
+test_mmap_cache_SOURCES = \
+ src/journal/test-mmap-cache.c
+
+test_mmap_cache_LDADD = \
+ libjournal-core.la
+
+test_catalog_SOURCES = \
+ src/journal/test-catalog.c
+
+test_catalog_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DCATALOG_DIR=\"$(abs_top_srcdir)/catalog\"
+
+test_catalog_LDADD = \
+ libjournal-core.la
+
+test_compress_SOURCES = \
+ src/journal/test-compress.c
+
+test_compress_LDADD = \
+ libshared.la
+
+test_compress_benchmark_SOURCES = \
+ src/journal/test-compress-benchmark.c
+
+test_compress_benchmark_LDADD = \
+ libshared.la
+
+test_audit_type_SOURCES = \
+ src/journal/test-audit-type.c
+
+test_audit_type_LDADD = \
+ libjournal-core.la
+
+journal-install-hook:
+ -$(MKDIR_P) $(DESTDIR)/var/log/journal
+ -chown 0:0 $(DESTDIR)/var/log/journal
+ -chmod 755 $(DESTDIR)/var/log/journal
+ -setfacl -nm g:adm:rx,d:g:adm:rx $(DESTDIR)/var/log/journal/
+ -setfacl -nm g:wheel:rx,d:g:wheel:rx $(DESTDIR)/var/log/journal/
+
+journal-uninstall-hook:
+ -rmdir $(DESTDIR)/var/log/journal/remote
+ -rmdir $(DESTDIR)/var/log/journal/
+
+INSTALL_EXEC_HOOKS += journal-install-hook
+UNINSTALL_EXEC_HOOKS += journal-uninstall-hook
+
+# ------------------------------------------------------------------------------
+# Update catalog on installation. Do not bother if installing
+# in DESTDIR, since this is likely for packaging purposes.
+catalog-update-hook:
+ -test -n "$(DESTDIR)" || $(bindir)/journalctl --update-catalog
+
+INSTALL_DATA_HOOKS += \
+ catalog-update-hook
+
+catalog-remove-hook:
+ -test -n "$(DESTDIR)" || rm -f $(catalogstatedir)/database
+
+UNINSTALL_DATA_HOOKS += \
+ catalog-remove-hook
+
+tests += \
+ test-journal \
+ test-journal-enum \
+ test-journal-send \
+ test-journal-syslog \
+ test-journal-match \
+ test-journal-stream \
+ test-journal-init \
+ test-journal-verify \
+ test-journal-interleaving \
+ test-journal-flush \
+ test-mmap-cache \
+ test-catalog \
+ test-audit-type
+
+ifneq ($(HAVE_COMPRESSION),)
+tests += \
+ test-compress \
+ test-compress-benchmark
+endif # HAVE_COMPRESSION
+
+include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/journal/catalog/systemd.be.catalog b/src/grp-journal/catalog/systemd.be.catalog
index be081d6efc..051f49492f 100644
--- a/src/journal/catalog/systemd.be.catalog
+++ b/src/grp-journal/catalog/systemd.be.catalog
@@ -53,7 +53,7 @@ Documentation: man:journald.conf(5)
Паведамленні іншых сэрвісаў засталіся.
Мяжа, пасля якой паведамленні будуць адкінуты, наладжваецца з
-дапамогай RateLimitInterval= і RateLimitBurst= у файле
+дапамогай RateLimitIntervalSec= і RateLimitBurst= у файле
/etc/systemd/journald.conf. Глядзіце journald.conf(5) для дэталей.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.be@latin.catalog b/src/grp-journal/catalog/systemd.be@latin.catalog
index 382fdb8b04..6ab361aafb 100644
--- a/src/journal/catalog/systemd.be@latin.catalog
+++ b/src/grp-journal/catalog/systemd.be@latin.catalog
@@ -53,7 +53,7 @@ Majcie na ŭvazie, što byli adkinuty paviedamliennia toĺki hetaha servisu.
Paviedamlienni inšych servisaŭ zastalisia.
Miaža, paslia jakoj paviedamlienni buduć adkinuty, naladžvajecca z
-dapamohaj RateLimitInterval= i RateLimitBurst= u fajlie
+dapamohaj RateLimitIntervalSec= i RateLimitBurst= u fajlie
/etc/systemd/journald.conf. Hliadzicie journald.conf(5) dlia detaliej.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/grp-journal/catalog/systemd.bg.catalog b/src/grp-journal/catalog/systemd.bg.catalog
new file mode 100644
index 0000000000..30246c0bbe
--- /dev/null
+++ b/src/grp-journal/catalog/systemd.bg.catalog
@@ -0,0 +1,324 @@
+# This file is part of systemd.
+#
+# Copyright 2012 Lennart Poettering
+# Copyright 2016 Alexander Shopov <ash@kambanaria.org>
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+# Message catalog for systemd's own messages
+
+# The catalog format is documented on
+# http://www.freedesktop.org/wiki/Software/systemd/catalog
+
+# For an explanation why we do all this, see https://xkcd.com/1024/
+
+-- f77379a8490b408bbe5f6940505a777b
+Subject: Журналният процес е пуснат
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Журналният процес на системата е стартирал, отворил е журналните файлове
+за запис и може да приема заявки.
+
+-- d93fb3c9c24d451a97cea615ce59c00b
+Subject: Журналният процес е спрян
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Журналният процес на системата е спрян, затворени са всички отворени
+журнални файлове.
+
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: Пространството върху диска заето от журналните файлове
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) в момента заема @CURRENT_USE_PRETTY@.
+Максималният зададен размер е @MAX_USE_PRETTY@.
+Свободни се оставят поне @DISK_KEEP_FREE_PRETTY@ (от текущо наличните @DISK_AVAILABLE_PRETTY@).
+Максималният наложен размер е @LIMIT_PRETTY@, от който @AVAILABLE_PRETTY@ са свободни.
+
+Настройките за максималния размер на журнала върху диска се
+управляват чрез директивите „SystemMaxUse=“, „SystemKeepFree=“,
+„SystemMaxFileSize=“, „RuntimeMaxUse=“, „RuntimeKeepFree=“ и
+„RuntimeMaxFileSize=“ във файла „/etc/systemd/journald.conf“.
+За повече информация прегледайте „journald.conf(5)“ от ръководството.
+
+-- a596d6fe7bfa4994828e72309e95d61e
+Subject: Съобщенията от някоя услуга не са допуснати
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:journald.conf(5)
+
+Някоя услуга генерира прекалено много съобщения за кратък период.
+Част само от нейните съобщения са отхвърляни.
+
+Съобщенията от другите услуги не са засегнати.
+
+Настройките за максималния брой съобщения, които ще се обработят, се
+управляват чрез директивите „RateLimitInterval=“ и „RateLimitBurst=“ във
+файла „/etc/systemd/journald.conf“. За повече информация прегледайте
+„journald.conf(5)“ от ръководството.
+
+-- e9bf28e6e834481bb6f48f548ad13606
+Subject: Пропуснати журнални съобщения
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Някои от съобщенията на ядрото може и да са пропуснати, защото системата не
+смогваше да ги обработи достатъчно бързо.
+
+-- fc2e22bc6ee647b6b90729ab34a250b1
+Subject: Процес № @COREDUMP_PID@ (@COREDUMP_COMM@) запази освободената памет
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:core(5)
+
+Процес № @COREDUMP_PID@ (@COREDUMP_COMM@) заби, представянето му в паметта
+бе запазено.
+
+Най-често това се дължи на грешка в забилата програма и следва да я
+докладвате на създателите на програмата.
+
+-- 8d45620c1a4348dbb17410da57c60c66
+Subject: Създадена е нова сесия № @SESSION_ID@ за потребителя „@USER_ID@“
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+За потребителя „@USER_ID@“ е създадена нова сесия № @SESSION_ID@.
+
+Водещият процес на сесията е: @LEADER@
+
+-- 3354939424b4456d9802ca8333ed424a
+Subject: Сесия № @SESSION_ID@ приключи
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Сесия № @SESSION_ID@ приключи работа.
+
+-- fcbefc5da23d428093f97c82a9290f7b
+Subject: Налично е ново работно място № @SEAT_ID@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Новото работно място № @SEAT_ID@ е настроено и готово за работа.
+
+-- e7852bfe46784ed0accde04bc864c2d5
+Subject: Работното място № @SEAT_ID@ е премахнато
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Работното място № @SEAT_ID@ вече не е налично.
+
+-- c7a787079b354eaaa9e77b371893cd27
+Subject: Смяна на системното време
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Часовникът на системата е сверен да сочи @REALTIME@ микросекунди след
+1 януари 1970.
+
+-- 45f82f4aef7a4bbf942ce861d1f20990
+Subject: Смяна на часовия пояс да е „@TIMEZONE@“
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Часовият пояс на системата е сменен на „@TIMEZONE@“.
+
+-- b07a249cd024414a82dd00cd181378ff
+Subject: Стартирането на системата завърши
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Успешно са стартирали всички услуги, които са посочени за задействане при
+стартиране на системата. Това не означава, че системата бездейства, защото
+някои от услугите може да извършват специфични действия при стартиране.
+
+Стартирането на ядрото отне @KERNEL_USEC@ микросекунди.
+
+Стартирането на RAM диска за първоначално зареждане отне @INITRD_USEC@
+микросекунди.
+
+Стартирането на потребителските програми отне @USERSPACE_USEC@ микросекунди.
+
+-- 6bbd95ee977941e497c48be27c254128
+Subject: Системата е приспана на ниво „@SLEEP@“
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Системата премина в състояние на приспиване „@SLEEP@“.
+
+-- 8811e6df2a8e40f58a94cea26f8ebf14
+Subject: Системата се събуди след приспиване на ниво„@SLEEP@“
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Системата се събуди от състояние на приспиване „@SLEEP@“.
+
+-- 98268866d1d54a499c4e98921d93bc40
+Subject: Започна процедура на спиране на системата
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Започна процедурата на Systemd за спиране на системата. Всички процеси и
+услуги се спират, всички файлови системи се демонтират.
+
+-- 7d4958e842da4a758f6c1cdc7b36dcc5
+Subject: Модул „@UNIT@“ се стартира
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Модулът „@UNIT@“ се стартира в момента
+
+-- 39f53479d3a045ac8e11786248231fbf
+Subject: Модул „@UNIT@“ вече е стартиран
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Стартирането на модул „@UNIT@“ завърши.
+
+Резултатът е: @RESULT@
+
+-- de5b426a63be47a7b6ac3eaac82e2f6f
+Subject: Модул „@UNIT@“ се спира
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Модулът „@UNIT@“ се спира в момента.
+
+-- 9d1aaa27d60140bd96365438aad20286
+Subject: Модул „@UNIT@“ вече е спрян
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Спирането на модул „@UNIT@“ завърши.
+
+-- be02cf6855d2428ba40df7e9d022f03d
+Subject: Модулът „@UNIT@“ не успя да стартира
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Модулът „@UNIT@“ не успя да стартира.
+
+Резултатът е: @RESULT@
+
+-- d34d037fff1847e6ae669a370e694725
+Subject: Модулът „@UNIT@“ започна презареждане на настройките си
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Модулът „@UNIT@“ започна презареждане на настройките си.
+
+-- 7b05ebc668384222baa8881179cfda54
+Subject: Модулът „@UNIT@“ завърши презареждането на настройките си
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Модулът „@UNIT@“ завърши презареждането на настройките си.
+
+Резултатът e: @RESULT@
+
+-- 641257651c1b4ec9a8624d7a40a9e1e7
+Subject: Програмата „@EXECUTABLE@“ не успя да се стартира
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Програмата „@EXECUTABLE@“ не успя да се стартира.
+
+Върнатият номер на грешка е: @ERRNO@
+
+-- 0027229ca0644181a76c4e92458afa2e
+Subject: Поне едно съобщение не бе препратено към syslog
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Поне едно съобщение не бе препратено към журналната услуга syslog, която
+работи успоредно с journald.
+
+Най-често това указва, че тази реализация на syslog не може да поеме текущия
+обем съобщения.
+
+-- 1dee0369c7fc4736b7099b38ecb46ee7
+Subject: Точката за монтиране не е празна
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Директорията „@WHERE@“ не е празна.
+
+Тя е указана като точка за монтиране — или като второ поле във файла
+„/etc/fstab“, или чрез директивата „Where=“ в някой от файловете за
+модул на Systemd.
+
+Това не пречи на самото монтиране, но вече съществуващите там файлове и
+директории няма да се виждат повече, освен ако ръчно не монтирате тази
+непразна директория някъде другаде.
+
+-- 24d8d4452573402496068381a6312df2
+Subject: Стартирана е виртуална машина или контейнер
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Виртуалната машина „@NAME@“ с идентификатор на водещия процес @LEADER@
+е стартирана и готова за работа.
+
+-- 58432bd3bace477cb514b56381b8a758
+Subject: Спряна е виртуална машина или контейнер
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Виртуалната машина „@NAME@“ с идентификатор на водещия процес @LEADER@
+е спряна.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: Режимът DNSSEC е изключен, защото сървърът не го поддържа
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Локалната услуга за имена (systemd-resolved.service) установи, че
+настроения сървър за DNS не поддържа DNSSEC, затова този режим е изключен.
+
+Това се случва, когато директивата „DNSSEC=allow-downgrade“ е включена във
+файла „resolved.conf“ и зададеният сървър за DNS не е съвместим с DNSSEC.
+
+Внимавайте, защото това може да позволи атака, при която трета страна ви
+връща отговори, които да предизвикат понижаването на сигурността от DNSSEC
+до DNS.
+
+Такова събитие означава, че или сървърът за DNS не е съвместим с DNSSEC,
+или някой успешно ви е атакувал за понижаване на сигурността на имената.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: Неуспешна проверка на DNSSEC
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Заявка или запис в DNS не издържа проверка с DNSSEC.
+
+Това обикновено показва вмешателство на трета страна в канала ви за връзка.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: Анулирана доверена котва в DNSSEC
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Анулирана е доверена котва за DNSSEC и трябва да настроите нова.
+
+Понякога новата идва с обновяване на системата.
diff --git a/src/journal/catalog/systemd.catalog b/src/grp-journal/catalog/systemd.catalog
index 077f182a5a..90929bca6d 100644
--- a/src/journal/catalog/systemd.catalog
+++ b/src/grp-journal/catalog/systemd.catalog
@@ -66,7 +66,7 @@ Note that only messages from the service in question have been
dropped, other services' messages are unaffected.
The limits controlling when messages are dropped may be configured
-with RateLimitInterval= and RateLimitBurst= in
+with RateLimitIntervalSec= and RateLimitBurst= in
/etc/systemd/journald.conf. See journald.conf(5) for details.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.da.catalog b/src/grp-journal/catalog/systemd.da.catalog
index bd4d742d8a..093e8139da 100644
--- a/src/journal/catalog/systemd.da.catalog
+++ b/src/grp-journal/catalog/systemd.da.catalog
@@ -52,7 +52,7 @@ Kun beskeder fra omtalte service er smidt væk. Beskeder fra andre
services er ikke påvirket.
Grænsen for hvornår beskeder bliver smidt væk kan konfigureres
-med RateLimitInterval= og RateLimitBurst= i
+med RateLimitIntervalSec= og RateLimitBurst= i
/etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.fr.catalog b/src/grp-journal/catalog/systemd.fr.catalog
index 03a457786f..0cea629c31 100644
--- a/src/journal/catalog/systemd.fr.catalog
+++ b/src/grp-journal/catalog/systemd.fr.catalog
@@ -38,6 +38,25 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Le processus du journal système a été arrêté et tous ses fichiers actifs
ont été fermés.
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: Espace disque utilisé par le journal
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:journald.conf(5)
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) utilise actuellement @CURRENT_USE_PRETTY@.
+Le maximum autorisé est défini à @MAX_USE_PRETTY@.
+Au moins @DISK_KEEP_FREE_PRETTY@ doivent être laissés libres
+(sur @DISK_AVAILABLE_PRETTY@ d'espace disque actuellement libre).
+La limite appliquée est donc @LIMIT_PRETTY@, dont @AVAILABLE_PRETTY@
+sont toujours disponibles.
+
+Les limites définissant la quantité d'espace disque que peut utiliser le
+journal peuvent être configurées avec les paramètres SystemMaxUse=,
+SystemKeepFree=, SystemMaxFileSize=, RuntimeMaxUse=, RuntimeKeepFree=,
+RuntimeMaxFileSize= dans le fichier /etc/systemd/journald.conf.
+Voir journald.conf(5) pour plus de détails.
+
-- a596d6fe7bfa4994828e72309e95d61e
Subject: Des messages d'un service ont été supprimés
Defined-By: systemd
@@ -51,7 +70,7 @@ Notez que seuls des messages de ce service ont été évincés, les messages des
autres services ne sont pas affectés.
Les limites définissant ce comportement peuvent être configurées avec les
-paramètres RateLimitInterval= et RateLimitBurst= dans le fichier
+paramètres RateLimitIntervalSec= et RateLimitBurst= dans le fichier
/etc/systemd/journald.conf. Voir journald.conf(5) pour plus de détails.
-- e9bf28e6e834481bb6f48f548ad13606
@@ -98,7 +117,8 @@ Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
-Un nouveau poste (seat) @SEAT_ID@ a été configuré et est maintenant disponible.
+Un nouveau poste (seat) @SEAT_ID@ a été configuré et est maintenant
+disponible.
-- e7852bfe46784ed0accde04bc864c2d5
Subject: Le poste (seat) @SEAT_ID@ a été retiré
@@ -228,8 +248,8 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Un ou plusieurs messages n'ont pas pu être transmis au service syslog
s'exécutant conjointement avec journald. Cela indique généralement que
-l'implémentation de syslog utilisée n'a pas été capable de suivre la cadence
-du flux de messages.
+l'implémentation de syslog utilisée n'a pas été capable de suivre
+la cadence du flux de messages.
-- 1dee0369c7fc4736b7099b38ecb46ee7
Subject: Le point de montage n'est pas vide
@@ -237,8 +257,8 @@ Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Le répertoire @WHERE@ est spécifié comme point de montage (second champ du
-fichier /etc/fstab, ou champ Where= dans une unité (unit) systemd) et n'est pas
-vide.
+fichier /etc/fstab, ou champ Where= dans une unité (unit) systemd) et n'est
+pas vide.
Cela ne perturbe pas le montage du système de fichiers, mais les fichiers
préalablement présents dans ce répertoire sont devenus inaccessibles.
Pour atteindre ces fichiers, veuillez monter manuellement le système de
@@ -258,3 +278,43 @@ Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
La machine virtuelle @NAME@ avec le PID maître @LEADER@ a été arrêtée.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: Le mode DNSSEC a été désactivé, car il n'est pas supporté par le serveur
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Le service de résolution (systemd-resolved.service) a détecté que le serveur
+DNS configuré ne supporte pas DNSSEC, et la validation DNSSEC a donc été
+désactivée.
+
+Cet évènement se produit si DNSSEC=allow-downgrade est configuré dans
+resolved.conf et que le serveur DNS configuré n'est pas compatible avec
+DNSSEC.
+Veuillez noter que ce mode permet des attaques de rétrogradation DNSSEC,
+car un attaquant peut être capable de désactiver la validation DNSSEC sur
+le système en injectant des réponses DNS dans le canal de communication.
+
+Cet évènement indique que le serveur DNS est effectivement incompatible avec
+DNSSEC, ou qu'un attaquant a peut-être conduit une telle attaque avec succès.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: La validation DNSSEC a échoué
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Une requête ou une ressource DNS n'a pas passé la validation DNSSEC.
+Ceci est généralement une indication que le canal de communication a été
+altéré.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: Une ancre de confiance DNSSEC a été révoquée
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Une ancre de confiance DNSSEC a été révoquée. Une nouvelle ancre de
+confiance doit être configurée, ou le système d'exploitation a besoin
+d'être mis à jour, pour fournir une version à jour de l'ancre de confiance.
diff --git a/src/grp-journal/catalog/systemd.hr.catalog b/src/grp-journal/catalog/systemd.hr.catalog
new file mode 100644
index 0000000000..350988dd87
--- /dev/null
+++ b/src/grp-journal/catalog/systemd.hr.catalog
@@ -0,0 +1,314 @@
+# This file is part of systemd.
+#
+# Copyright 2012 Lennart Poettering
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+# Message catalog for systemd's own messages
+# Croatian translation
+
+# Format kataloga je dokumentiran na
+# http://www.freedesktop.org/wiki/Software/systemd/catalog
+
+# Za pojašnjenje zašto ovo radimo, posjetite https://xkcd.com/1024/
+
+-- f77379a8490b408bbe5f6940505a777b
+Subject: journal je pokrenut
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Journal proces sustava se pokrenuo, otvorio je journal
+ datoteke za upis i spreman je za obradu zahtjeva.
+
+-- d93fb3c9c24d451a97cea615ce59c00b
+Subject: journal je zaustavljen
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Journal proces sustava je isključio i zatvorio sve trenutno
+aktivne journal datoteke.
+
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: Diskovni prostor koji koristi journal
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) trenutno koristi @CURRENT_USE_PRETTY@.
+Najveća dopuštena upotreba je postavljena na @MAX_USE_PRETTY@.
+Ostavljam najmanje @DISK_KEEP_FREE_PRETTY@ slobodno (trenutno dostupno @DISK_AVAILABLE_PRETTY@ diskovnog prostora).
+Prisilno ograničenje upotrebe je @LIMIT_PRETTY@, od kojeg je @AVAILABLE_PRETTY@ još dostupno.
+
+Ograničenja kontroliraju koliko diskovnog prostora koristi journal mogu
+se podesiti sa SystemMaxUse=, SystemKeepFree=, SystemMaxFileSize=,
+RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize= settings u
+/etc/systemd/journald.conf. Pogledajte journald.conf(5) za više pojedinosti.
+
+-- a596d6fe7bfa4994828e72309e95d61e
+Subject: Poruka iz usluge je potisnuta
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:journald.conf(5)
+
+Usluga je prijavila previše poruka u određenom vremenskom razdoblju. Poruke
+iz usluge su odbačene.
+
+Zapamtite da samo poruke iz usluge u upitu su
+odbačene, ostale poruke usluga nisu zahvaćene.
+
+Ograničenja koja kontroliraju kada je poruka odbačena mogu se podesiti
+sa RateLimitIntervalSec= i RateLimitBurst= u
+/etc/systemd/journald.conf. Pogledajte journald.conf(5) za više pojedinosti.
+
+-- e9bf28e6e834481bb6f48f548ad13606
+Subject: Journal poruka je propuštena
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Kernel poruka je izgubljena zato jer ih journal sustav nije mogao
+dovoljno brzo obraditi.
+
+-- fc2e22bc6ee647b6b90729ab34a250b1
+Subject: Proces @COREDUMP_PID@ (@COREDUMP_COMM@) je izbacio jezgru
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:core(5)
+
+Proces @COREDUMP_PID@ (@COREDUMP_COMM@) se srušio i izbacio jezgru.
+
+Rušenje programa je uobičajeno uzrokovano greškom u programiranju i
+trebalo bi se prijaviti razvijatelju kao greška.
+
+-- 8d45620c1a4348dbb17410da57c60c66
+Subject: Nova sesija @SESSION_ID@ je stvorena za korisnika @USER_ID@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Nova sesija sa ID @SESSION_ID@ je stvorena za korisnika @USER_ID@.
+
+Glavni proces sesije je @LEADER@.
+
+-- 3354939424b4456d9802ca8333ed424a
+Subject: Sesija @SESSION_ID@ je prekinuta
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Sesija sa ID @SESSION_ID@ je prekinuta.
+
+-- fcbefc5da23d428093f97c82a9290f7b
+Subject: Novo sjedište @SEAT_ID@ je sada dostupno
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Novo sjedište @SEAT_ID@ je podešeno i sada je dostupno.
+
+-- e7852bfe46784ed0accde04bc864c2d5
+Subject: Sjedište @SEAT_ID@ je sada uklonjeno
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
+
+Sjedište @SEAT_ID@ je uklonjeno i više nije dostupno.
+
+-- c7a787079b354eaaa9e77b371893cd27
+Subject: Vrijeme promjene
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sat sustava je promijenjen na @REALTIME@ microsekundi nakon 1. Siječnja, 1970 godine.
+
+-- 45f82f4aef7a4bbf942ce861d1f20990
+Subject: Vremenska zona je promijenjena u @TIMEZONE@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Vremenska zona je promijenjena u @TIMEZONE@.
+
+-- b07a249cd024414a82dd00cd181378ff
+Subject: Pokretanje sustava je sada završeno
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sve usluge sustava koje su zadane za pokretanje pri pokretanju sustava
+su uspješno pokrenute. Zapamtite da ovo ne znači da sada računalo
+miruje zato jer se neke usluge još uvijek mogu pokretati.
+
+Pokretanje kernela zahtijeva @KERNEL_USEC@ mikrosekundi.
+
+Pokretanje početnog RAM diska zahtijeva @INITRD_USEC@ mikrosekundi.
+
+Pokretanje prostora korisnika zahtijeva @USERSPACE_USEC@ mikrosekundi.
+
+-- 6bbd95ee977941e497c48be27c254128
+Subject: Pokrenuto je stanje spavanja @SLEEP@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sustav je sada pokrenuo stanje spavanja @SLEEP@
+
+-- 8811e6df2a8e40f58a94cea26f8ebf14
+Subject: Završeno je stanje spavanja @SLEEP@
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Sustav je sada završio stanje spavanja @SLEEP@
+
+-- 98268866d1d54a499c4e98921d93bc40
+Subject: Pokrenuto je isključivanje sustava
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Pokrenuto je isključivanje sustava. Isključivanje je sada pokrenuto,
+sve usluge sustava su prekinute i svi datotečni sustavi su odmontirani.
+
+-- 7d4958e842da4a758f6c1cdc7b36dcc5
+Subject: Jedinica @UNIT@ je započela pokretanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je započela pokretanje.
+
+-- 39f53479d3a045ac8e11786248231fbf
+Subject: Jedinica @UNIT@ je završila pokretanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je završila pokretanje.
+
+Rezultat pokretanja je @RESULT@.
+
+-- de5b426a63be47a7b6ac3eaac82e2f6f
+Subject: Jedinica @UNIT@ je započela isključivanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je započela isključivanje.
+
+-- 9d1aaa27d60140bd96365438aad20286
+Subject: Jedinica @UNIT@ je završila isključivanje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je završila isključivanje.
+
+-- be02cf6855d2428ba40df7e9d022f03d
+Subject: Jedinica @UNIT@ nije uspjela
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ nije uspjela.
+
+Rezultat je @RESULT@.
+
+-- d34d037fff1847e6ae669a370e694725
+Subject: Jedinica @UNIT@ je započela ponovno učitavati podešavanja
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je započela ponovno učitavati podešavanja
+
+-- 7b05ebc668384222baa8881179cfda54
+Subject: Jedinica @UNIT@ je završila ponovno učitavati podešavanja
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedinica @UNIT@ je završila ponovno učitavati podešavanja
+
+Rezultat je @RESULT@.
+
+-- 641257651c1b4ec9a8624d7a40a9e1e7
+Subject: Proces @EXECUTABLE@ se ne može pokrenuti
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Proces @EXECUTABLE@ se ne može pokrenuti i nije uspio.
+
+Broj greške vraćen ovim procesom je @ERRNO@.
+
+-- 0027229ca0644181a76c4e92458afa2e
+Subject: Jedna ili više poruka se ne mogu proslijediti u dnevnik sustava
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Jedna ili više poruka se ne mogu proslijediti u dnevnik sustava, usluge
+su pokrenute istovremeno s journalom. Ovo uobičajeno označava da
+implementacija dnevnika sustava ne može slijediti brzinu
+zahtjeva poruka.
+
+-- 1dee0369c7fc4736b7099b38ecb46ee7
+Subject: Točka montiranja nije prazna
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Direktorij @WHERE@ je određen za točku montiranja (drugi redak u
+/etc/fstab ili Where= redak u datoteci systemd jedinice) i nije prazan.
+To ne utječe na montiranje, ali postojeće datoteke u ovom direktoriju
+postaju nedostupne. Kako bi vidjeli datoteke preko kojih je montirano,
+ručno montirajte osnovni datotečni sustav na drugu lokaciju.
+
+-- 24d8d4452573402496068381a6312df2
+Subject: Virtualni stroj ili spremnik su pokrenuti
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Virtualni stroj @NAME@ sa vodećim @LEADER@ PID-om je
+pokrenut i spreman je za korištenje.
+
+-- 58432bd3bace477cb514b56381b8a758
+Subject: Virtualni stroj ili spremnik su isključeni
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+Virtualni stroj @NAME@ sa vodećim PID-om @LEADER@ je
+isključen.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: DNSSEC način je isključen, jer ga poslužitelj ne podržava
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Usluga razrješavanja (systemd-resolved.service) je otkrila da
+podešeni DNS poslužitelj ne podržava DNSSEC, i DNSSEC, kao rezultat
+provjera je isključena.
+
+Ovaj događaj će zauzeti mjesto ako je DNSSEC=allow-downgrade podešen u
+resolved.conf i podešeni DNS poslužitelj je nekompatibilan s DNSSEC. Zapamtite
+da korištenje ovog načina dopušta povećanje DNSSEC napada, napadač bi mogao
+isključiti DNSSEC provjeru na sustavu umetanjem DNS odgovora u
+komunikacijski kanal što rezultira povećanjem napada poput ovog.
+
+Ovaj događaj bi mogao označavati da je DNS poslužitelj uistinu nekompatibilan s
+DNSSEC ili da je napadač uspješno izvršio takav napad.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: DNSSEC provjera neuspješna
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+DNS zahtjev ili snimak resursa nije prošao DNSSEC provjeru. To uobičajeno
+označava da je komunikacijski kanal mijenjan.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: DNSSEC pouzdano sidro je opozvano
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+A DNSSEC trust anchor has been revoked. A new trust anchor has to be
+configured, or the operating system needs to be updated, to provide an updated
+DNSSEC trust anchor.
diff --git a/src/journal/catalog/systemd.hu.catalog b/src/grp-journal/catalog/systemd.hu.catalog
index 30d76916cc..68e8c2572e 100644
--- a/src/journal/catalog/systemd.hu.catalog
+++ b/src/grp-journal/catalog/systemd.hu.catalog
@@ -51,7 +51,7 @@ Ne feledje, hogy csak a kérdéses szolgáltatás üzenetei kerültek eldobásra
más szolgáltatások üzeneteit ez nem befolyásolja.
Az üzenetek eldobását vezérlő korlátok az /etc/systemd/journald.conf
-RateLimitInterval= és RateLimitBurst= beállításaival adhatók meg.
+RateLimitIntervalSec= és RateLimitBurst= beállításaival adhatók meg.
Részletekért lásd a journald.conf(5) man oldalt.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.it.catalog b/src/grp-journal/catalog/systemd.it.catalog
index 861b92b74a..b6fca48221 100644
--- a/src/journal/catalog/systemd.it.catalog
+++ b/src/grp-journal/catalog/systemd.it.catalog
@@ -46,7 +46,7 @@ Solo i messaggi del servizio indicato sono stati
eliminati, i messaggi degli altri servizi rimangono invariati.
I limiti oltre i quali i messaggi si eliminano si configurano
-con RateLimitInterval= e RateLimitBurst= in
+con RateLimitIntervalSec= e RateLimitBurst= in
/etc/systemd/journald.conf. Vedi journald.conf(5) per maggiori informazioni.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.ko.catalog b/src/grp-journal/catalog/systemd.ko.catalog
index 3c3535a94c..2fc6b60b1b 100644
--- a/src/journal/catalog/systemd.ko.catalog
+++ b/src/grp-journal/catalog/systemd.ko.catalog
@@ -55,7 +55,7 @@ Documentation: man:journald.conf(5)
다른 서비스의 메시지에는 영향을 주지 않습니다.
메시지 거절 제어 제한 값은 /etc/systemd/journald.conf 의
-RateLimitInterval= 변수와 RateLimitBurst= 변수로 설정합니다.
+RateLimitIntervalSec= 변수와 RateLimitBurst= 변수로 설정합니다.
자세한 내용은 ournald.conf(5)를 살펴보십시오.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.pl.catalog b/src/grp-journal/catalog/systemd.pl.catalog
index 6b8a31d8c4..d8059e93cd 100644
--- a/src/journal/catalog/systemd.pl.catalog
+++ b/src/grp-journal/catalog/systemd.pl.catalog
@@ -1,7 +1,7 @@
# This file is part of systemd.
#
# Copyright 2012 Lennart Poettering
-# Copyright 2014, 2015 Piotr Drąg
+# Copyright 2014, 2015, 2016 Piotr Drąg
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
@@ -40,6 +40,22 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Systemowy proces dziennika został wyłączony i zamknął wszystkie obecnie
aktywne pliki dziennika.
+-- ec387f577b844b8fa948f33cad9a75e6
+Subject: Miejsce na dysku używane przez dziennik
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+
+@JOURNAL_NAME@ (@JOURNAL_PATH@) obecnie używa @CURRENT_USE_PRETTY@.
+Maksymalnie może używać @MAX_USE_PRETTY@.
+Zostawianie co najmniej @DISK_KEEP_FREE_PRETTY@ wolnego (z obecnie dostępnego @DISK_AVAILABLE_PRETTY@ miejsca na dysku).
+Wymuszone ograniczenie użycia wynosi więc @LIMIT_PRETTY@, z czego @AVAILABLE_PRETTY@ jest nadal dostępne.
+
+Ograniczenia kontrolujące ilość miejsca na dysku używanego przez dziennik
+można konfigurować za pomocą ustawień SystemMaxUse=, SystemKeepFree=,
+SystemMaxFileSize=, RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize=
+w pliku /etc/systemd/journald.conf. Strona journald.conf(5) zawiera więcej
+informacji.
+
-- a596d6fe7bfa4994828e72309e95d61e
Subject: Ograniczono komunikaty z usługi
Defined-By: systemd
@@ -53,7 +69,7 @@ Proszę zauważyć, że tylko komunikaty z danej usługi zostały pominięte. Ni
to wpływu na komunikaty innych usług.
Ograniczenia kontrolujące pomijanie komunikatów mogą być konfigurowane
-za pomocą opcji RateLimitInterval= i RateLimitBurst= w pliku
+za pomocą opcji RateLimitIntervalSec= i RateLimitBurst= w pliku
/etc/systemd/journald.conf. Strona journald.conf(5) zawiera więcej informacji.
-- e9bf28e6e834481bb6f48f548ad13606
@@ -72,7 +88,8 @@ Documentation: man:core(5)
Proces @COREDUMP_PID@ (@COREDUMP_COMM@) uległ awarii i zrzucił plik core.
-Zwykle wskazuje to na błąd programistyczny w danym programie i powinno zostać zgłoszone jego producentowi jako błąd.
+Zwykle wskazuje to na błąd programistyczny w danym programie i powinno zostać
+zgłoszone jego producentowi jako błąd.
-- 8d45620c1a4348dbb17410da57c60c66
Subject: Utworzono nową sesję @SESSION_ID@ dla użytkownika @USER_ID@
@@ -259,3 +276,40 @@ Defined-By: systemd
Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
Maszyna wirtualna @NAME@ (PID prowadzący @LEADER@) została wyłączona.
+
+-- 36db2dfa5a9045e1bd4af5f93e1cf057
+Subject: Wyłączono tryb DNSSEC, ponieważ serwer go nie obsługuje
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8) resolved.conf(5)
+
+Usługa resolver (systemd-resolved.service) wykryła, że skonfigurowany serwer
+DNS nie obsługuje DNSSEC, w wyniku czego walidacja DNSSEC została wyłączona.
+
+To zdarzenie będzie miało miejsce, jeśli skonfigurowano DNSSEC=allow-downgrade
+w pliku resolved.conf, a skonfigurowany serwer DNS jest niezgodny z DNSSEC.
+Proszę zauważyć, że używanie tego trybu umożliwia ataki wyłączające DNSSEC,
+ponieważ atakujący będzie mógł wyłączyć walidację DNSSEC na komputerze przez
+umieszczenie odpowiednich odpowiedzi DNS w kanale komunikacji.
+
+To zdarzenie może wskazywać, że serwer DNS jest faktycznie niezgodny z DNSSEC,
+albo że atakującemu udało się upozorować atak tego typu.
+
+-- 1675d7f172174098b1108bf8c7dc8f5d
+Subject: Walidacja DNSSEC się nie powiodła
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Zapytanie DNS lub ustawiony wpis zasobu nie przeszedł walidacji DNSSEC.
+Zwykle wskazuje to, że ktoś manipulował używanym kanałem komunikacji.
+
+-- 4d4408cfd0d144859184d1e65d7c8a65
+Subject: Unieważniono kotwicę zaufania DNSSEC
+Defined-By: systemd
+Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
+Documentation: man:systemd-resolved.service(8)
+
+Kotwica zaufania DNSSEC została unieważniona. Należy skonfigurować nową, albo
+system operacyjny musi zostać zaktualizowany, aby dostarczyć zaktualizowaną
+kotwicę zaufania DNSSEC.
diff --git a/src/journal/catalog/systemd.pt_BR.catalog b/src/grp-journal/catalog/systemd.pt_BR.catalog
index d9716e30f7..8b856e8355 100644
--- a/src/journal/catalog/systemd.pt_BR.catalog
+++ b/src/grp-journal/catalog/systemd.pt_BR.catalog
@@ -53,7 +53,7 @@ Note que apenas mensagens de um serviço em questão foram descartadas; outras
mensagens dos serviços não foram afetadas.
Os controles de limites de quando as mensagens são descartadas pode ser
-configurado com RateLimitInterval= e RateLimitBurst= no
+configurado com RateLimitIntervalSec= e RateLimitBurst= no
/etc/systemd/journald.conf. Veja journald.conf(5) para detalhes.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.ru.catalog b/src/grp-journal/catalog/systemd.ru.catalog
index eedbb8aa9c..e56dbe3acc 100644
--- a/src/journal/catalog/systemd.ru.catalog
+++ b/src/grp-journal/catalog/systemd.ru.catalog
@@ -76,7 +76,7 @@ Documentation: man:journald.conf(5)
сообщения других служб не затронуты.
Предел, после которого служба журнала начинает игнорировать сообщения,
-настраивается параметрами RateLimitInterval= и RateLimitBurst= в файле
+настраивается параметрами RateLimitIntervalSec= и RateLimitBurst= в файле
/etc/systemd/journald.conf. Подробности смотрите на странице руководства
journald.conf(5).
diff --git a/src/journal/catalog/systemd.sr.catalog b/src/grp-journal/catalog/systemd.sr.catalog
index cf700c477b..cc689b7956 100644
--- a/src/journal/catalog/systemd.sr.catalog
+++ b/src/grp-journal/catalog/systemd.sr.catalog
@@ -52,7 +52,7 @@ Documentation: man:journald.conf(5)
услуге нису захваћене овим.
Ограничења која подешавају начин на који се поруке одбацују се могу подесити
-помоћу „RateLimitInterval=“ и „RateLimitBurst=“ параметара унутар датотеке
+помоћу „RateLimitIntervalSec=“ и „RateLimitBurst=“ параметара унутар датотеке
/etc/systemd/journald.conf. Погледајте journald.conf(5) за појединости.
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/journal/catalog/systemd.zh_CN.catalog b/src/grp-journal/catalog/systemd.zh_CN.catalog
index 38639109e4..ed59fc9250 100644
--- a/src/journal/catalog/systemd.zh_CN.catalog
+++ b/src/grp-journal/catalog/systemd.zh_CN.catalog
@@ -50,7 +50,7 @@ Documentation: man:journald.conf(5)
请注意只有由有问题的服务传来的消息被丢弃,
其它服务的消息不受影响。
-可以在 /etc/systemd/journald.conf 中设定 RateLimitInterval=
+可以在 /etc/systemd/journald.conf 中设定 RateLimitIntervalSec=
以及 RateLimitBurst = 的值以控制丢弃信息的限制。
请参见 journald.conf(5) 以了解详情。
diff --git a/src/journal/catalog/systemd.zh_TW.catalog b/src/grp-journal/catalog/systemd.zh_TW.catalog
index 027ffe44e5..aa5004db08 100644
--- a/src/journal/catalog/systemd.zh_TW.catalog
+++ b/src/grp-journal/catalog/systemd.zh_TW.catalog
@@ -53,7 +53,7 @@ Documentation: man:journald.conf(5)
其他服務的訊息則不受影響。
可以在 /etc/systemd/journald.conf 中設定
-RateLimitInterval= 以及 RateLimitBurst=
+RateLimitIntervalSec= 以及 RateLimitBurst=
來控制當訊息要開始被丟棄時的限制。參見 journald.conf(5) 以獲得更多資訊。
-- e9bf28e6e834481bb6f48f548ad13606
diff --git a/src/libbus-proxy-core/Makefile b/src/grp-journal/journalctl/Makefile
index f3cf4a055f..c3cdb6b27a 100644
--- a/src/libbus-proxy-core/Makefile
+++ b/src/grp-journal/journalctl/Makefile
@@ -20,23 +20,30 @@
#
# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
+include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
-noinst_LTLIBRARIES += \
- libbus-proxy-core.la
+# using _CFLAGS = in the conditional below would suppress AM_CFLAGS
+journalctl_CFLAGS = \
+ $(AM_CFLAGS)
-libbus_proxy_core_la_SOURCES = \
- src/bus-proxyd/bus-xml-policy.c \
- src/bus-proxyd/bus-xml-policy.h \
- src/bus-proxyd/driver.c \
- src/bus-proxyd/driver.h \
- src/bus-proxyd/proxy.c \
- src/bus-proxyd/proxy.h \
- src/bus-proxyd/synthesize.c \
- src/bus-proxyd/synthesize.h
+journalctl_SOURCES = \
+ src/journal/journalctl.c
-libbus_proxy_core_la_LIBADD = \
- libshared.la
+journalctl_LDADD = \
+ libshared.la \
+ libudev-core.la
+
+ifneq ($(HAVE_QRENCODE),)
+journalctl_SOURCES += \
+ src/journal/journal-qrcode.c \
+ src/journal/journal-qrcode.h
+
+journalctl_CFLAGS += \
+ $(QRENCODE_CFLAGS)
+
+journalctl_LDADD += \
+ $(QRENCODE_LIBS)
+endif # HAVE_QRENCODE
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/journal/journalctl.c b/src/grp-journal/journalctl/journalctl.c
index 1670978466..3602bd0556 100644
--- a/src/journal/journalctl.c
+++ b/src/grp-journal/journalctl/journalctl.c
@@ -95,11 +95,13 @@ static bool arg_boot = false;
static sd_id128_t arg_boot_id = {};
static int arg_boot_offset = 0;
static bool arg_dmesg = false;
+static bool arg_no_hostname = false;
static const char *arg_cursor = NULL;
static const char *arg_after_cursor = NULL;
static bool arg_show_cursor = false;
static const char *arg_directory = NULL;
static char **arg_file = NULL;
+static bool arg_file_stdin = false;
static int arg_priorities = 0xFF;
static const char *arg_verify_key = NULL;
#ifdef HAVE_GCRYPT
@@ -225,14 +227,6 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) {
return 0;
}
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(arg_pager_end);
-}
-
static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
if (arg_utc)
@@ -278,7 +272,7 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset
static void help(void) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, arg_pager_end);
printf("%s [OPTIONS...] [MATCHES...]\n\n"
"Query the journal.\n\n"
@@ -312,6 +306,7 @@ static void help(void) {
" -a --all Show all fields, including long and unprintable\n"
" -q --quiet Do not show info messages and privilege warning\n"
" --no-pager Do not pipe output into a pager\n"
+ " --no-hostname Suppress output of hostname field\n"
" -m --merge Show entries from all available journals\n"
" -D --directory=PATH Show journal files from directory\n"
" --file=PATH Show journal file\n"
@@ -378,6 +373,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VACUUM_SIZE,
ARG_VACUUM_FILES,
ARG_VACUUM_TIME,
+ ARG_NO_HOSTNAME,
};
static const struct option options[] = {
@@ -435,6 +431,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
{ "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
{ "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
+ { "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
{}
};
@@ -596,9 +593,17 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_FILE:
- r = glob_extend(&arg_file, optarg);
- if (r < 0)
- return log_error_errno(r, "Failed to add paths: %m");
+ if (streq(optarg, "-"))
+ /* An undocumented feature: we can read journal files from STDIN. We don't document
+ * this though, since after all we only support this for mmap-able, seekable files, and
+ * not for example pipes which are probably the primary usecase for reading things from
+ * STDIN. To avoid confusion we hence don't document this feature. */
+ arg_file_stdin = true;
+ else {
+ r = glob_extend(&arg_file, optarg);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add paths: %m");
+ }
break;
case ARG_ROOT:
@@ -788,6 +793,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_LIST_FIELD_NAMES;
break;
+ case ARG_NO_HOSTNAME:
+ arg_no_hostname = true;
+ break;
+
case 'x':
arg_catalog = true;
break;
@@ -864,6 +873,18 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (!strv_isempty(arg_system_units) && (arg_journal_type == SD_JOURNAL_CURRENT_USER)) {
+
+ /* Specifying --user and --unit= at the same time makes no sense (as the former excludes the user
+ * journal, but the latter excludes the system journal, thus resulting in empty output). Let's be nice
+ * to users, and automatically turn --unit= into --user-unit= if combined with --user. */
+ r = strv_extend_strv(&arg_user_units, arg_system_units, true);
+ if (r < 0)
+ return -ENOMEM;
+
+ arg_system_units = strv_free(arg_system_units);
+ }
+
return 1;
}
@@ -988,18 +1009,18 @@ static void boot_id_free_all(BootId *l) {
}
}
-static int discover_next_boot(
- sd_journal *j,
- BootId **boot,
+static int discover_next_boot(sd_journal *j,
+ sd_id128_t previous_boot_id,
bool advance_older,
- bool read_realtime) {
+ BootId **ret) {
- int r;
- char match[9+32+1] = "_BOOT_ID=";
_cleanup_free_ BootId *next_boot = NULL;
+ char match[9+32+1] = "_BOOT_ID=";
+ sd_id128_t boot_id;
+ int r;
assert(j);
- assert(boot);
+ assert(ret);
/* We expect the journal to be on the last position of a boot
* (in relation to the direction we are going), so that the next
@@ -1012,29 +1033,40 @@ static int discover_next_boot(
* we can actually advance to a *different* boot. */
sd_journal_flush_matches(j);
- if (advance_older)
- r = sd_journal_previous(j);
- else
- r = sd_journal_next(j);
- if (r < 0)
- return r;
- else if (r == 0)
- return 0; /* End of journal, yay. */
+ do {
+ if (advance_older)
+ r = sd_journal_previous(j);
+ else
+ r = sd_journal_next(j);
+ if (r < 0)
+ return r;
+ else if (r == 0)
+ return 0; /* End of journal, yay. */
+
+ r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
+ if (r < 0)
+ return r;
+
+ /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
+ * normally, this will only require a single iteration, as we seeked to the last entry of the previous
+ * boot entry already. However, it might happen that the per-journal-field entry arrays are less
+ * complete than the main entry array, and hence might reference an entry that's not actually the last
+ * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
+ * speed things up, but let's not trust that it is complete, and hence, manually advance as
+ * necessary. */
+
+ } while (sd_id128_equal(boot_id, previous_boot_id));
next_boot = new0(BootId, 1);
if (!next_boot)
return -ENOMEM;
- r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id);
+ next_boot->id = boot_id;
+
+ r = sd_journal_get_realtime_usec(j, &next_boot->first);
if (r < 0)
return r;
- if (read_realtime) {
- r = sd_journal_get_realtime_usec(j, &next_boot->first);
- if (r < 0)
- return r;
- }
-
/* Now seek to the last occurrence of this boot ID. */
sd_id128_to_string(next_boot->id, match + 9);
r = sd_journal_add_match(j, match, sizeof(match) - 1);
@@ -1057,13 +1089,11 @@ static int discover_next_boot(
else if (r == 0)
return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */
- if (read_realtime) {
- r = sd_journal_get_realtime_usec(j, &next_boot->last);
- if (r < 0)
- return r;
- }
+ r = sd_journal_get_realtime_usec(j, &next_boot->last);
+ if (r < 0)
+ return r;
- *boot = next_boot;
+ *ret = next_boot;
next_boot = NULL;
return 0;
@@ -1072,47 +1102,48 @@ static int discover_next_boot(
static int get_boots(
sd_journal *j,
BootId **boots,
- BootId *query_ref_boot,
+ sd_id128_t *query_ref_boot,
int ref_boot_offset) {
bool skip_once;
int r, count = 0;
BootId *head = NULL, *tail = NULL;
const bool advance_older = query_ref_boot && ref_boot_offset <= 0;
+ sd_id128_t previous_boot_id;
assert(j);
/* Adjust for the asymmetry that offset 0 is
* the last (and current) boot, while 1 is considered the
* (chronological) first boot in the journal. */
- skip_once = query_ref_boot && sd_id128_is_null(query_ref_boot->id) && ref_boot_offset < 0;
+ skip_once = query_ref_boot && sd_id128_is_null(*query_ref_boot) && ref_boot_offset < 0;
/* Advance to the earliest/latest occurrence of our reference
* boot ID (taking our lookup direction into account), so that
* discover_next_boot() can do its job.
* If no reference is given, the journal head/tail will do,
* they're "virtual" boots after all. */
- if (query_ref_boot && !sd_id128_is_null(query_ref_boot->id)) {
+ if (query_ref_boot && !sd_id128_is_null(*query_ref_boot)) {
char match[9+32+1] = "_BOOT_ID=";
sd_journal_flush_matches(j);
- sd_id128_to_string(query_ref_boot->id, match + 9);
+ sd_id128_to_string(*query_ref_boot, match + 9);
r = sd_journal_add_match(j, match, sizeof(match) - 1);
if (r < 0)
return r;
if (advance_older)
- r = sd_journal_seek_head(j);
+ r = sd_journal_seek_head(j); /* seek to oldest */
else
- r = sd_journal_seek_tail(j);
+ r = sd_journal_seek_tail(j); /* seek to newest */
if (r < 0)
return r;
if (advance_older)
- r = sd_journal_next(j);
+ r = sd_journal_next(j); /* read the oldest entry */
else
- r = sd_journal_previous(j);
+ r = sd_journal_previous(j); /* read the most recently added entry */
if (r < 0)
return r;
else if (r == 0)
@@ -1121,21 +1152,31 @@ static int get_boots(
count = 1;
goto finish;
}
+
+ /* At this point the read pointer is positioned at the oldest/newest occurence of the reference boot
+ * ID. After flushing the matches, one more invocation of _previous()/_next() will hence place us at
+ * the following entry, which must then have an older/newer boot ID */
} else {
+
if (advance_older)
- r = sd_journal_seek_tail(j);
+ r = sd_journal_seek_tail(j); /* seek to newest */
else
- r = sd_journal_seek_head(j);
+ r = sd_journal_seek_head(j); /* seek to oldest */
if (r < 0)
return r;
- /* No sd_journal_next/previous here. */
+ /* No sd_journal_next()/_previous() here.
+ *
+ * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
+ * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
+ * entry we have. */
}
+ previous_boot_id = SD_ID128_NULL;
for (;;) {
_cleanup_free_ BootId *current = NULL;
- r = discover_next_boot(j, &current, advance_older, !query_ref_boot);
+ r = discover_next_boot(j, previous_boot_id, advance_older, &current);
if (r < 0) {
boot_id_free_all(head);
return r;
@@ -1144,6 +1185,8 @@ static int get_boots(
if (!current)
break;
+ previous_boot_id = current->id;
+
if (query_ref_boot) {
if (!skip_once)
ref_boot_offset += advance_older ? 1 : -1;
@@ -1151,7 +1194,7 @@ static int get_boots(
if (ref_boot_offset == 0) {
count = 1;
- query_ref_boot->id = current->id;
+ *query_ref_boot = current->id;
break;
}
} else {
@@ -1183,7 +1226,7 @@ static int list_boots(sd_journal *j) {
if (count == 0)
return count;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, arg_pager_end);
/* numbers are one less, but we need an extra char for the sign */
w = DECIMAL_STR_WIDTH(count - 1) + 1;
@@ -1207,8 +1250,8 @@ static int list_boots(sd_journal *j) {
static int add_boot(sd_journal *j) {
char match[9+32+1] = "_BOOT_ID=";
+ sd_id128_t ref_boot_id;
int r;
- BootId ref_boot_id = {};
assert(j);
@@ -1218,7 +1261,7 @@ static int add_boot(sd_journal *j) {
if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
return add_match_this_boot(j, arg_machine);
- ref_boot_id.id = arg_boot_id;
+ ref_boot_id = arg_boot_id;
r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset);
assert(r <= 1);
if (r <= 0) {
@@ -1234,7 +1277,7 @@ static int add_boot(sd_journal *j) {
return r == 0 ? -ENODATA : r;
}
- sd_id128_to_string(ref_boot_id.id, match + 9);
+ sd_id128_to_string(ref_boot_id, match + 9);
r = sd_journal_add_match(j, match, sizeof(match) - 1);
if (r < 0)
@@ -1363,7 +1406,7 @@ static int add_units(sd_journal *j) {
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
- count ++;
+ count++;
}
}
@@ -1383,7 +1426,7 @@ static int add_units(sd_journal *j) {
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
- count ++;
+ count++;
}
}
@@ -1408,7 +1451,7 @@ static int add_units(sd_journal *j) {
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
- count ++;
+ count++;
}
}
@@ -1428,7 +1471,7 @@ static int add_units(sd_journal *j) {
r = sd_journal_add_disjunction(j);
if (r < 0)
return r;
- count ++;
+ count++;
}
}
@@ -1847,7 +1890,7 @@ static int access_check(sd_journal *j) {
break;
default:
- log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path);
+ log_warning_errno(err, "An error was encountered while opening journal file or directory %s, ignoring file: %m", path);
break;
}
}
@@ -2061,7 +2104,7 @@ int main(int argc, char *argv[]) {
} else {
bool oneline = arg_action == ACTION_LIST_CATALOG;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, arg_pager_end);
if (optind < argc)
r = catalog_list_items(stdout, database, oneline, argv + optind);
@@ -2103,11 +2146,61 @@ int main(int argc, char *argv[]) {
if (arg_directory)
r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
- else if (arg_file)
+ else if (arg_file_stdin) {
+ int ifd = STDIN_FILENO;
+ r = sd_journal_open_files_fd(&j, &ifd, 1, 0);
+ } else if (arg_file)
r = sd_journal_open_files(&j, (const char**) arg_file, 0);
- else if (arg_machine)
- r = sd_journal_open_container(&j, arg_machine, 0);
- else
+ else if (arg_machine) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ int fd;
+
+ if (geteuid() != 0) {
+ /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
+ * the container, thus we need root privileges to override them. */
+ log_error("Using the --machine= switch requires root privileges.");
+ r = -EPERM;
+ goto finish;
+ }
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0) {
+ log_error_errno(r, "Failed to open system bus: %m");
+ goto finish;
+ }
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "OpenMachineRootDirectory",
+ &error,
+ &reply,
+ "s", arg_machine);
+ if (r < 0) {
+ log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
+ goto finish;
+ }
+
+ r = sd_bus_message_read(reply, "h", &fd);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ goto finish;
+ }
+
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (fd < 0) {
+ r = log_error_errno(errno, "Failed to duplicate file descriptor: %m");
+ goto finish;
+ }
+
+ r = sd_journal_open_directory_fd(&j, fd, SD_JOURNAL_OS_ROOT);
+ if (r < 0)
+ safe_close(fd);
+ } else
r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
if (r < 0) {
log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
@@ -2181,7 +2274,7 @@ int main(int argc, char *argv[]) {
SD_JOURNAL_FOREACH_FIELD(j, field) {
printf("%s\n", field);
- n_shown ++;
+ n_shown++;
}
r = 0;
@@ -2273,7 +2366,7 @@ int main(int argc, char *argv[]) {
else
printf("%.*s\n", (int) size, (const char*) data);
- n_shown ++;
+ n_shown++;
}
r = 0;
@@ -2283,6 +2376,10 @@ int main(int argc, char *argv[]) {
/* Opening the fd now means the first sd_journal_wait() will actually wait */
if (arg_follow) {
r = sd_journal_get_fd(j);
+ if (r == -EMEDIUMTYPE) {
+ log_error_errno(r, "The --follow switch is not supported in conjunction with reading from STDIN.");
+ goto finish;
+ }
if (r < 0) {
log_error_errno(r, "Failed to get journal fd: %m");
goto finish;
@@ -2368,7 +2465,7 @@ int main(int argc, char *argv[]) {
}
if (!arg_follow)
- pager_open_if_enabled();
+ pager_open(arg_no_pager, arg_pager_end);
if (!arg_quiet) {
usec_t start, end;
@@ -2452,7 +2549,8 @@ int main(int argc, char *argv[]) {
arg_full * OUTPUT_FULL_WIDTH |
colors_enabled() * OUTPUT_COLOR |
arg_catalog * OUTPUT_CATALOG |
- arg_utc * OUTPUT_UTC;
+ arg_utc * OUTPUT_UTC |
+ arg_no_hostname * OUTPUT_NO_HOSTNAME;
r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
need_seek = true;
diff --git a/src/grp-journal/libjournal-core/Makefile b/src/grp-journal/libjournal-core/Makefile
new file mode 100644
index 0000000000..d55aebfb49
--- /dev/null
+++ b/src/grp-journal/libjournal-core/Makefile
@@ -0,0 +1,56 @@
+# -*- Mode: makefile; indent-tabs-mode: t -*-
+#
+# This file is part of systemd.
+#
+# Copyright 2010-2012 Lennart Poettering
+# Copyright 2010-2012 Kay Sievers
+# Copyright 2013 Zbigniew Jędrzejewski-Szmek
+# Copyright 2013 David Strauss
+# Copyright 2016 Luke Shumaker
+#
+# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
+include $(topsrcdir)/build-aux/Makefile.head.mk
+
+libjournal_core_la_SOURCES = \
+ src/journal/journald-kmsg.c \
+ src/journal/journald-kmsg.h \
+ src/journal/journald-syslog.c \
+ src/journal/journald-syslog.h \
+ src/journal/journald-stream.c \
+ src/journal/journald-stream.h \
+ src/journal/journald-server.c \
+ src/journal/journald-server.h \
+ src/journal/journald-console.c \
+ src/journal/journald-console.h \
+ src/journal/journald-wall.c \
+ src/journal/journald-wall.h \
+ src/journal/journald-native.c \
+ src/journal/journald-native.h \
+ src/journal/journald-audit.c \
+ src/journal/journald-audit.h \
+ src/journal/journald-rate-limit.c \
+ src/journal/journald-rate-limit.h \
+ src/journal/journal-internal.h
+
+nodist_libjournal_core_la_SOURCES = \
+ src/journal/journald-gperf.c
+
+libjournal_core_la_LIBADD = \
+ libshared.la
+
+noinst_LTLIBRARIES += \
+ libjournal-core.la
+
+include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/journal/cat.c b/src/grp-journal/libjournal-core/cat.c
index 93ab6e7f96..93ab6e7f96 100644
--- a/src/journal/cat.c
+++ b/src/grp-journal/libjournal-core/cat.c
diff --git a/src/journal/journal-qrcode.c b/src/grp-journal/libjournal-core/journal-qrcode.c
index e38730d65c..e38730d65c 100644
--- a/src/journal/journal-qrcode.c
+++ b/src/grp-journal/libjournal-core/journal-qrcode.c
diff --git a/src/journal/journal-qrcode.h b/src/grp-journal/libjournal-core/journal-qrcode.h
index 34a779d5be..34a779d5be 100644
--- a/src/journal/journal-qrcode.h
+++ b/src/grp-journal/libjournal-core/journal-qrcode.h
diff --git a/src/journal/journald-audit.c b/src/grp-journal/libjournal-core/journald-audit.c
index b2eb8a33ef..a433c91c54 100644
--- a/src/journal/journald-audit.c
+++ b/src/grp-journal/libjournal-core/journald-audit.c
@@ -63,7 +63,7 @@ static int map_simple_field(const char *field, const char **p, struct iovec **io
(*iov)[*n_iov].iov_base = c;
(*iov)[*n_iov].iov_len = l;
- (*n_iov) ++;
+ (*n_iov)++;
*p = e;
c = NULL;
@@ -142,7 +142,7 @@ static int map_string_field_internal(const char *field, const char **p, struct i
(*iov)[*n_iov].iov_base = c;
(*iov)[*n_iov].iov_len = l;
- (*n_iov) ++;
+ (*n_iov)++;
*p = e;
c = NULL;
@@ -200,7 +200,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec **
}
strcpy(t, "=");
- e ++;
+ e++;
r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
if (r < 0)
diff --git a/src/journal/journald-audit.h b/src/grp-journal/libjournal-core/journald-audit.h
index 8c7457778c..8c7457778c 100644
--- a/src/journal/journald-audit.h
+++ b/src/grp-journal/libjournal-core/journald-audit.h
diff --git a/src/journal/journald-console.c b/src/grp-journal/libjournal-core/journald-console.c
index fcc9f25814..fcc9f25814 100644
--- a/src/journal/journald-console.c
+++ b/src/grp-journal/libjournal-core/journald-console.c
diff --git a/src/journal/journald-console.h b/src/grp-journal/libjournal-core/journald-console.h
index dda07e2c28..dda07e2c28 100644
--- a/src/journal/journald-console.h
+++ b/src/grp-journal/libjournal-core/journald-console.h
diff --git a/src/journal/journald-gperf.gperf b/src/grp-journal/libjournal-core/journald-gperf.gperf
index c154610c54..7fecd7a964 100644
--- a/src/journal/journald-gperf.gperf
+++ b/src/grp-journal/libjournal-core/journald-gperf.gperf
@@ -19,7 +19,9 @@ Journal.Storage, config_parse_storage, 0, offsetof(Server, storage
Journal.Compress, config_parse_bool, 0, offsetof(Server, compress)
Journal.Seal, config_parse_bool, 0, offsetof(Server, seal)
Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec)
+# The following is a legacy name for compatibility
Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, rate_limit_interval)
+Journal.RateLimitIntervalSec,config_parse_sec, 0, offsetof(Server, rate_limit_interval)
Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_limit_burst)
Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use)
Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size)
diff --git a/src/journal/journald-kmsg.c b/src/grp-journal/libjournal-core/journald-kmsg.c
index 1ac57bb361..3712636de2 100644
--- a/src/journal/journald-kmsg.c
+++ b/src/grp-journal/libjournal-core/journald-kmsg.c
@@ -201,7 +201,7 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) {
if (*k != ' ')
break;
- k ++, l --;
+ k++, l--;
e = memchr(k, '\n', l);
if (!e)
diff --git a/src/journal/journald-kmsg.h b/src/grp-journal/libjournal-core/journald-kmsg.h
index dab49f1e8c..dab49f1e8c 100644
--- a/src/journal/journald-kmsg.h
+++ b/src/grp-journal/libjournal-core/journald-kmsg.h
diff --git a/src/journal/journald-native.c b/src/grp-journal/libjournal-core/journald-native.c
index 3d8f05996b..0a1ce205c2 100644
--- a/src/journal/journald-native.c
+++ b/src/grp-journal/libjournal-core/journald-native.c
@@ -206,7 +206,7 @@ void server_process_native_message(
allow_object_pid(ucred)) {
char buf[DECIMAL_STR_MAX(pid_t)];
memcpy(buf, p + strlen("OBJECT_PID="), l - strlen("OBJECT_PID="));
- char_array_0(buf);
+ buf[l-strlen("OBJECT_PID=")] = '\0';
/* ignore error */
parse_pid(buf, &object_pid);
@@ -448,24 +448,24 @@ void server_process_native_file(
}
int server_open_native_socket(Server*s) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/socket",
+ };
static const int one = 1;
int r;
assert(s);
if (s->native_fd < 0) {
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/socket",
- };
-
s->native_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->native_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->native_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->native_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
diff --git a/src/journal/journald-native.h b/src/grp-journal/libjournal-core/journald-native.h
index c13b80aa4f..c13b80aa4f 100644
--- a/src/journal/journald-native.h
+++ b/src/grp-journal/libjournal-core/journald-native.h
diff --git a/src/journal/journald-rate-limit.c b/src/grp-journal/libjournal-core/journald-rate-limit.c
index 6f6a90fe4e..fce799a6ce 100644
--- a/src/journal/journald-rate-limit.c
+++ b/src/grp-journal/libjournal-core/journald-rate-limit.c
@@ -104,7 +104,7 @@ static void journal_rate_limit_group_free(JournalRateLimitGroup *g) {
LIST_REMOVE(lru, g->parent->lru, g);
LIST_REMOVE(bucket, g->parent->buckets[g->hash % BUCKETS_MAX], g);
- g->parent->n_groups --;
+ g->parent->n_groups--;
}
free(g->id);
@@ -168,7 +168,7 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r,
LIST_PREPEND(lru, r->lru, g);
if (!g->lru_next)
r->lru_tail = g;
- r->n_groups ++;
+ r->n_groups++;
g->parent = r;
return g;
diff --git a/src/journal/journald-rate-limit.h b/src/grp-journal/libjournal-core/journald-rate-limit.h
index bb0abb7ee9..bb0abb7ee9 100644
--- a/src/journal/journald-rate-limit.h
+++ b/src/grp-journal/libjournal-core/journald-rate-limit.h
diff --git a/src/journal/journald-server.c b/src/grp-journal/libjournal-core/journald-server.c
index 4f53bf01c3..cc29443e66 100644
--- a/src/journal/journald-server.c
+++ b/src/grp-journal/libjournal-core/journald-server.c
@@ -251,15 +251,15 @@ static int open_journal(
assert(ret);
if (reliably)
- r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f);
+ r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f);
else
- r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f);
+ r = journal_file_open(-1, fname, flags, 0640, s->compress, seal, metrics, s->mmap, s->deferred_closes, NULL, &f);
if (r < 0)
return r;
r = journal_file_enable_post_change_timer(f, s->event, POST_CHANGE_TIMER_INTERVAL_USEC);
if (r < 0) {
- journal_file_close(f);
+ (void) journal_file_close(f);
return r;
}
@@ -302,7 +302,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
/* Too many open? Then let's close one */
f = ordered_hashmap_steal_first(s->user_journals);
assert(f);
- journal_file_close(f);
+ (void) journal_file_close(f);
}
r = open_journal(s, true, p, O_RDWR|O_CREAT, s->seal, &s->system_metrics, &f);
@@ -313,7 +313,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f);
if (r < 0) {
- journal_file_close(f);
+ (void) journal_file_close(f);
return s->system_journal;
}
@@ -333,7 +333,7 @@ static int do_rotate(
if (!*f)
return -EINVAL;
- r = journal_file_rotate(f, s->compress, seal);
+ r = journal_file_rotate(f, s->compress, seal, s->deferred_closes);
if (r < 0)
if (*f)
log_error_errno(r, "Failed to rotate %s: %m", (*f)->path);
@@ -364,6 +364,13 @@ void server_rotate(Server *s) {
/* Old file has been closed and deallocated */
ordered_hashmap_remove(s->user_journals, k);
}
+
+ /* Perform any deferred closes which aren't still offlining. */
+ SET_FOREACH(f, s->deferred_closes, i)
+ if (!journal_file_is_offlining(f)) {
+ (void) set_remove(s->deferred_closes, f);
+ (void) journal_file_close(f);
+ }
}
void server_sync(Server *s) {
@@ -372,13 +379,13 @@ void server_sync(Server *s) {
int r;
if (s->system_journal) {
- r = journal_file_set_offline(s->system_journal);
+ r = journal_file_set_offline(s->system_journal, false);
if (r < 0)
log_warning_errno(r, "Failed to sync system journal, ignoring: %m");
}
ORDERED_HASHMAP_FOREACH(f, s->user_journals, i) {
- r = journal_file_set_offline(f);
+ r = journal_file_set_offline(f, false);
if (r < 0)
log_warning_errno(r, "Failed to sync user journal, ignoring: %m");
}
@@ -485,38 +492,36 @@ static void server_cache_hostname(Server *s) {
}
static bool shall_try_append_again(JournalFile *f, int r) {
-
- /* -E2BIG Hit configured limit
- -EFBIG Hit fs limit
- -EDQUOT Quota limit hit
- -ENOSPC Disk full
- -EIO I/O error of some kind (mmap)
- -EHOSTDOWN Other machine
- -EBUSY Unclean shutdown
- -EPROTONOSUPPORT Unsupported feature
- -EBADMSG Corrupted
- -ENODATA Truncated
- -ESHUTDOWN Already archived
- -EIDRM Journal file has been deleted */
-
- if (r == -E2BIG || r == -EFBIG || r == -EDQUOT || r == -ENOSPC)
+ switch(r) {
+ case -E2BIG: /* Hit configured limit */
+ case -EFBIG: /* Hit fs limit */
+ case -EDQUOT: /* Quota limit hit */
+ case -ENOSPC: /* Disk full */
log_debug("%s: Allocation limit reached, rotating.", f->path);
- else if (r == -EHOSTDOWN)
+ return true;
+ case -EIO: /* I/O error of some kind (mmap) */
+ log_warning("%s: IO error, rotating.", f->path);
+ return true;
+ case -EHOSTDOWN: /* Other machine */
log_info("%s: Journal file from other machine, rotating.", f->path);
- else if (r == -EBUSY)
+ return true;
+ case -EBUSY: /* Unclean shutdown */
log_info("%s: Unclean shutdown, rotating.", f->path);
- else if (r == -EPROTONOSUPPORT)
+ return true;
+ case -EPROTONOSUPPORT: /* Unsupported feature */
log_info("%s: Unsupported feature, rotating.", f->path);
- else if (r == -EBADMSG || r == -ENODATA || r == ESHUTDOWN)
+ return true;
+ case -EBADMSG: /* Corrupted */
+ case -ENODATA: /* Truncated */
+ case -ESHUTDOWN: /* Already archived */
log_warning("%s: Journal file corrupted, rotating.", f->path);
- else if (r == -EIO)
- log_warning("%s: IO error, rotating.", f->path);
- else if (r == -EIDRM)
+ return true;
+ case -EIDRM: /* Journal file has been deleted */
log_warning("%s: Journal file has been deleted, rotating.", f->path);
- else
+ return true;
+ default:
return false;
-
- return true;
+ }
}
static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned n, int priority) {
@@ -1400,7 +1405,7 @@ static int server_parse_proc_cmdline(Server *s) {
}
p = line;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, 0);
@@ -1655,7 +1660,7 @@ static int server_connect_notify(Server *s) {
it. Specifically: given that PID 1 might block on
dbus-daemon during IPC, and dbus-daemon is logging to us,
and might hence block on us, we might end up in a deadlock
- if we block on sending PID 1 notification messages -- by
+ if we block on sending PID 1 notification messages — by
generating a full blocking circle. To avoid this, let's
create a non-blocking socket, and connect it to the
notification socket, and then wait for POLLOUT before we
@@ -1691,7 +1696,7 @@ static int server_connect_notify(Server *s) {
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));
+ r = connect(s->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "Failed to connect to notify socket: %m");
@@ -1765,6 +1770,10 @@ int server_init(Server *s) {
if (!s->mmap)
return log_oom();
+ s->deferred_closes = set_new(NULL);
+ if (!s->deferred_closes)
+ return log_oom();
+
r = sd_event_default(&s->event);
if (r < 0)
return log_error_errno(r, "Failed to create event loop: %m");
@@ -1918,17 +1927,22 @@ void server_done(Server *s) {
JournalFile *f;
assert(s);
+ if (s->deferred_closes) {
+ journal_file_close_set(s->deferred_closes);
+ set_free(s->deferred_closes);
+ }
+
while (s->stdout_streams)
stdout_stream_free(s->stdout_streams);
if (s->system_journal)
- journal_file_close(s->system_journal);
+ (void) journal_file_close(s->system_journal);
if (s->runtime_journal)
- journal_file_close(s->runtime_journal);
+ (void) journal_file_close(s->runtime_journal);
while ((f = ordered_hashmap_steal_first(s->user_journals)))
- journal_file_close(f);
+ (void) journal_file_close(f);
ordered_hashmap_free(s->user_journals);
diff --git a/src/journal/journald-server.h b/src/grp-journal/libjournal-core/journald-server.h
index cb8a5bbe9b..bebb056aa7 100644
--- a/src/journal/journald-server.h
+++ b/src/grp-journal/libjournal-core/journald-server.h
@@ -130,6 +130,8 @@ struct Server {
MMapCache *mmap;
+ Set *deferred_closes;
+
struct udev *udev;
uint64_t *kernel_seqnum;
diff --git a/src/journal/journald-stream.c b/src/grp-journal/libjournal-core/journald-stream.c
index 583b1305ae..99d856301c 100644
--- a/src/journal/journald-stream.c
+++ b/src/grp-journal/libjournal-core/journald-stream.c
@@ -96,7 +96,7 @@ void stdout_stream_free(StdoutStream *s) {
if (s->server) {
assert(s->server->n_stdout_streams > 0);
- s->server->n_stdout_streams --;
+ s->server->n_stdout_streams--;
LIST_REMOVE(stdout_stream, s->server->stdout_streams, s);
if (s->in_notify_queue)
@@ -511,7 +511,7 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {
stream->server = s;
LIST_PREPEND(stdout_stream, s->stdout_streams, stream);
- s->n_stdout_streams ++;
+ s->n_stdout_streams++;
if (ret)
*ret = stream;
@@ -700,23 +700,22 @@ fail:
}
int server_open_stdout_socket(Server *s) {
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/stdout",
+ };
int r;
assert(s);
if (s->stdout_fd < 0) {
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/stdout",
- };
-
s->stdout_fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->stdout_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->stdout_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->stdout_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
diff --git a/src/journal/journald-stream.h b/src/grp-journal/libjournal-core/journald-stream.h
index db4c67fae3..db4c67fae3 100644
--- a/src/journal/journald-stream.h
+++ b/src/grp-journal/libjournal-core/journald-stream.h
diff --git a/src/journal/journald-syslog.c b/src/grp-journal/libjournal-core/journald-syslog.c
index 480a1cc405..86fe81d179 100644
--- a/src/journal/journald-syslog.c
+++ b/src/grp-journal/libjournal-core/journald-syslog.c
@@ -52,8 +52,7 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
.msg_iov = (struct iovec *) iovec,
.msg_iovlen = n_iovec,
.msg_name = (struct sockaddr*) &sa.sa,
- .msg_namelen = offsetof(union sockaddr_union, un.sun_path)
- + strlen("/run/systemd/journal/syslog"),
+ .msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
struct cmsghdr *cmsg;
union {
@@ -316,12 +315,12 @@ static void syslog_skip_date(char **buf) {
}
void server_process_syslog_message(
- Server *s,
- const char *buf,
- const struct ucred *ucred,
- const struct timeval *tv,
- const char *label,
- size_t label_len) {
+ Server *s,
+ const char *buf,
+ const struct ucred *ucred,
+ const struct timeval *tv,
+ const char *label,
+ size_t label_len) {
char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)],
syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)];
@@ -365,14 +364,12 @@ void server_process_syslog_message(
if (identifier) {
syslog_identifier = strjoina("SYSLOG_IDENTIFIER=", identifier);
- if (syslog_identifier)
- IOVEC_SET_STRING(iovec[n++], syslog_identifier);
+ IOVEC_SET_STRING(iovec[n++], syslog_identifier);
}
if (pid) {
syslog_pid = strjoina("SYSLOG_PID=", pid);
- if (syslog_pid)
- IOVEC_SET_STRING(iovec[n++], syslog_pid);
+ IOVEC_SET_STRING(iovec[n++], syslog_pid);
}
message = strjoina("MESSAGE=", buf);
@@ -383,24 +380,24 @@ void server_process_syslog_message(
}
int server_open_syslog_socket(Server *s) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/dev-log",
+ };
static const int one = 1;
int r;
assert(s);
if (s->syslog_fd < 0) {
- static const union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/dev-log",
- };
-
s->syslog_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (s->syslog_fd < 0)
return log_error_errno(errno, "socket() failed: %m");
- unlink(sa.un.sun_path);
+ (void) unlink(sa.un.sun_path);
- r = bind(s->syslog_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = bind(s->syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
@@ -437,6 +434,7 @@ int server_open_syslog_socket(Server *s) {
void server_maybe_warn_forward_syslog_missed(Server *s) {
usec_t n;
+
assert(s);
if (s->n_forward_syslog_missed <= 0)
diff --git a/src/journal/journald-syslog.h b/src/grp-journal/libjournal-core/journald-syslog.h
index 46ad715314..46ad715314 100644
--- a/src/journal/journald-syslog.h
+++ b/src/grp-journal/libjournal-core/journald-syslog.h
diff --git a/src/journal/journald-wall.c b/src/grp-journal/libjournal-core/journald-wall.c
index 4d91fafffe..4d91fafffe 100644
--- a/src/journal/journald-wall.c
+++ b/src/grp-journal/libjournal-core/journald-wall.c
diff --git a/src/journal/journald-wall.h b/src/grp-journal/libjournal-core/journald-wall.h
index ebc2b89fa8..ebc2b89fa8 100644
--- a/src/journal/journald-wall.h
+++ b/src/grp-journal/libjournal-core/journald-wall.h
diff --git a/src/journal/journald.conf b/src/grp-journal/libjournal-core/journald.conf
index 7beb96c671..2541b949be 100644
--- a/src/journal/journald.conf
+++ b/src/grp-journal/libjournal-core/journald.conf
@@ -17,7 +17,7 @@
#Seal=yes
#SplitMode=uid
#SyncIntervalSec=5m
-#RateLimitInterval=30s
+#RateLimitIntervalSec=30s
#RateLimitBurst=1000
#SystemMaxUse=
#SystemKeepFree=
diff --git a/src/journal/test-audit-type.c b/src/grp-journal/libjournal-core/test-audit-type.c
index 88a2e6d9d9..88a2e6d9d9 100644
--- a/src/journal/test-audit-type.c
+++ b/src/grp-journal/libjournal-core/test-audit-type.c
diff --git a/src/journal/test-catalog.c b/src/grp-journal/libjournal-core/test-catalog.c
index 6f2f9f5561..f939fcdc2a 100644
--- a/src/journal/test-catalog.c
+++ b/src/grp-journal/libjournal-core/test-catalog.c
@@ -103,6 +103,8 @@ static void test_catalog_import_one(void) {
assert_se(hashmap_size(h) == 1);
HASHMAP_FOREACH(payload, h, j) {
+ printf("expect: %s\n", expect);
+ printf("actual: %s\n", payload);
assert_se(streq(expect, payload));
}
}
diff --git a/src/journal/test-compress-benchmark.c b/src/grp-journal/libjournal-core/test-compress-benchmark.c
index 5b2d130cd6..6f6d71435d 100644
--- a/src/journal/test-compress-benchmark.c
+++ b/src/grp-journal/libjournal-core/test-compress-benchmark.c
@@ -105,6 +105,8 @@ static void test_compress_decompress(const char* label, const char* type,
int r;
size = permute(i);
+ if (size == 0)
+ continue;
log_debug("%s %zu %zu", type, i, size);
@@ -162,7 +164,7 @@ int main(int argc, char *argv[]) {
arg_duration = x * USEC_PER_SEC;
}
if (argc == 3)
- (void) safe_atolu(argv[2], &arg_start);
+ (void) safe_atozu(argv[2], &arg_start);
else
arg_start = getpid();
diff --git a/src/journal/test-compress.c b/src/grp-journal/libjournal-core/test-compress.c
index 68c9a4d76c..68c9a4d76c 100644
--- a/src/journal/test-compress.c
+++ b/src/grp-journal/libjournal-core/test-compress.c
diff --git a/src/journal/test-journal-enum.c b/src/grp-journal/libjournal-core/test-journal-enum.c
index ffdc317e1d..54df59f477 100644
--- a/src/journal/test-journal-enum.c
+++ b/src/grp-journal/libjournal-core/test-journal-enum.c
@@ -44,7 +44,7 @@ int main(int argc, char *argv[]) {
printf("%.*s\n", (int) l, (char*) d);
- n ++;
+ n++;
if (n >= 10)
break;
}
diff --git a/src/journal/test-journal-flush.c b/src/grp-journal/libjournal-core/test-journal-flush.c
index 3dee462e74..7e9814f8fa 100644
--- a/src/journal/test-journal-flush.c
+++ b/src/grp-journal/libjournal-core/test-journal-flush.c
@@ -38,7 +38,7 @@ int main(int argc, char *argv[]) {
assert_se(mkdtemp(dn));
fn = strappend(dn, "/test.journal");
- r = journal_file_open(fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, &new_journal);
+ r = journal_file_open(-1, fn, O_CREAT|O_RDWR, 0644, false, false, NULL, NULL, NULL, NULL, &new_journal);
assert_se(r >= 0);
r = sd_journal_open(&j, 0);
@@ -66,7 +66,7 @@ int main(int argc, char *argv[]) {
sd_journal_close(j);
- journal_file_close(new_journal);
+ (void) journal_file_close(new_journal);
unlink(fn);
assert_se(rmdir(dn) == 0);
diff --git a/src/journal/test-journal-init.c b/src/grp-journal/libjournal-core/test-journal-init.c
index e6713034dd..e6713034dd 100644
--- a/src/journal/test-journal-init.c
+++ b/src/grp-journal/libjournal-core/test-journal-init.c
diff --git a/src/journal/test-journal-interleaving.c b/src/grp-journal/libjournal-core/test-journal-interleaving.c
index b47182dbfd..d09ef011a6 100644
--- a/src/journal/test-journal-interleaving.c
+++ b/src/grp-journal/libjournal-core/test-journal-interleaving.c
@@ -52,12 +52,12 @@ noreturn static void log_assert_errno(const char *text, int eno, const char *fil
static JournalFile *test_open(const char *name) {
JournalFile *f;
- assert_ret(journal_file_open(name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, &f));
+ assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, false, NULL, NULL, NULL, NULL, &f));
return f;
}
static void test_close(JournalFile *f) {
- journal_file_close (f);
+ (void) journal_file_close (f);
}
static void append_number(JournalFile *f, int n, uint64_t *seqnum) {
@@ -216,8 +216,8 @@ static void test_sequence_numbers(void) {
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
- assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0644,
- true, false, NULL, NULL, NULL, &one) == 0);
+ assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644,
+ true, false, NULL, NULL, NULL, NULL, &one) == 0);
append_number(one, 1, &seqnum);
printf("seqnum=%"PRIu64"\n", seqnum);
@@ -233,8 +233,8 @@ static void test_sequence_numbers(void) {
memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
- assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0644,
- true, false, NULL, NULL, one, &two) == 0);
+ assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644,
+ true, false, NULL, NULL, NULL, one, &two) == 0);
assert_se(two->header->state == STATE_ONLINE);
assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id));
@@ -264,8 +264,8 @@ static void test_sequence_numbers(void) {
/* restart server */
seqnum = 0;
- assert_se(journal_file_open("two.journal", O_RDWR, 0,
- true, false, NULL, NULL, NULL, &two) == 0);
+ assert_se(journal_file_open(-1, "two.journal", O_RDWR, 0,
+ true, false, NULL, NULL, NULL, NULL, &two) == 0);
assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
diff --git a/src/journal/test-journal-match.c b/src/grp-journal/libjournal-core/test-journal-match.c
index 5ee2adb827..5ee2adb827 100644
--- a/src/journal/test-journal-match.c
+++ b/src/grp-journal/libjournal-core/test-journal-match.c
diff --git a/src/journal/test-journal-send.c b/src/grp-journal/libjournal-core/test-journal-send.c
index 169082f9a4..169082f9a4 100644
--- a/src/journal/test-journal-send.c
+++ b/src/grp-journal/libjournal-core/test-journal-send.c
diff --git a/src/journal/test-journal-stream.c b/src/grp-journal/libjournal-core/test-journal-stream.c
index 57c6c0872d..0a1da47861 100644
--- a/src/journal/test-journal-stream.c
+++ b/src/grp-journal/libjournal-core/test-journal-stream.c
@@ -92,9 +92,9 @@ int main(int argc, char *argv[]) {
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
- assert_se(journal_file_open("one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &one) == 0);
- assert_se(journal_file_open("two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &two) == 0);
- assert_se(journal_file_open("three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &three) == 0);
+ assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &one) == 0);
+ assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &two) == 0);
+ assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &three) == 0);
for (i = 0; i < N_ENTRIES; i++) {
char *p, *q;
@@ -133,9 +133,9 @@ int main(int argc, char *argv[]) {
free(q);
}
- journal_file_close(one);
- journal_file_close(two);
- journal_file_close(three);
+ (void) journal_file_close(one);
+ (void) journal_file_close(two);
+ (void) journal_file_close(three);
assert_se(sd_journal_open_directory(&j, t, 0) >= 0);
diff --git a/src/journal/test-journal-syslog.c b/src/grp-journal/libjournal-core/test-journal-syslog.c
index 4ff7f3ec2e..4ff7f3ec2e 100644
--- a/src/journal/test-journal-syslog.c
+++ b/src/grp-journal/libjournal-core/test-journal-syslog.c
diff --git a/src/journal/test-journal-verify.c b/src/grp-journal/libjournal-core/test-journal-verify.c
index a26c624f41..3d2312fc55 100644
--- a/src/journal/test-journal-verify.c
+++ b/src/grp-journal/libjournal-core/test-journal-verify.c
@@ -55,12 +55,12 @@ static int raw_verify(const char *fn, const char *verification_key) {
JournalFile *f;
int r;
- r = journal_file_open(fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f);
+ r = journal_file_open(-1, fn, O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f);
if (r < 0)
return r;
r = journal_file_verify(f, verification_key, NULL, NULL, NULL, false);
- journal_file_close(f);
+ (void) journal_file_close(f);
return r;
}
@@ -88,7 +88,7 @@ int main(int argc, char *argv[]) {
log_info("Generating...");
- assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0);
+ assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
for (n = 0; n < N_ENTRIES; n++) {
struct iovec iovec;
@@ -107,11 +107,11 @@ int main(int argc, char *argv[]) {
free(test);
}
- journal_file_close(f);
+ (void) journal_file_close(f);
log_info("Verifying...");
- assert_se(journal_file_open("test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, &f) == 0);
+ assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0);
/* journal_file_print_header(f); */
journal_file_dump(f);
@@ -123,7 +123,7 @@ int main(int argc, char *argv[]) {
format_timestamp(b, sizeof(b), to),
format_timespan(c, sizeof(c), total > to ? total - to : 0, 0));
- journal_file_close(f);
+ (void) journal_file_close(f);
if (verification_key) {
log_info("Toggling bits...");
diff --git a/src/journal/test-journal.c b/src/grp-journal/libjournal-core/test-journal.c
index 0334b1cd1a..2543d64b5b 100644
--- a/src/journal/test-journal.c
+++ b/src/grp-journal/libjournal-core/test-journal.c
@@ -42,7 +42,7 @@ static void test_non_empty(void) {
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
- assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f) == 0);
+ assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f) == 0);
dual_timestamp_get(&ts);
@@ -104,10 +104,10 @@ static void test_non_empty(void) {
assert_se(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0);
- journal_file_rotate(&f, true, true);
- journal_file_rotate(&f, true, true);
+ journal_file_rotate(&f, true, true, NULL);
+ journal_file_rotate(&f, true, true, NULL);
- journal_file_close(f);
+ (void) journal_file_close(f);
log_info("Done...");
@@ -131,13 +131,13 @@ static void test_empty(void) {
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
- assert_se(journal_file_open("test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, &f1) == 0);
+ assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, false, NULL, NULL, NULL, NULL, &f1) == 0);
- assert_se(journal_file_open("test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, &f2) == 0);
+ assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, false, NULL, NULL, NULL, NULL, &f2) == 0);
- assert_se(journal_file_open("test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, &f3) == 0);
+ assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, true, NULL, NULL, NULL, NULL, &f3) == 0);
- assert_se(journal_file_open("test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, &f4) == 0);
+ assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, true, NULL, NULL, NULL, NULL, &f4) == 0);
journal_file_print_header(f1);
puts("");
@@ -158,10 +158,10 @@ static void test_empty(void) {
assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
- journal_file_close(f1);
- journal_file_close(f2);
- journal_file_close(f3);
- journal_file_close(f4);
+ (void) journal_file_close(f1);
+ (void) journal_file_close(f2);
+ (void) journal_file_close(f3);
+ (void) journal_file_close(f4);
}
int main(int argc, char *argv[]) {
diff --git a/src/journal/test-mmap-cache.c b/src/grp-journal/libjournal-core/test-mmap-cache.c
index 009aabf55e..009aabf55e 100644
--- a/src/journal/test-mmap-cache.c
+++ b/src/grp-journal/libjournal-core/test-mmap-cache.c
diff --git a/src/grp-journal/systemd-journald/Makefile b/src/grp-journal/systemd-journald/Makefile
new file mode 100644
index 0000000000..53046d1ce3
--- /dev/null
+++ b/src/grp-journal/systemd-journald/Makefile
@@ -0,0 +1,94 @@
+# -*- Mode: makefile; indent-tabs-mode: t -*-
+#
+# This file is part of systemd.
+#
+# Copyright 2010-2012 Lennart Poettering
+# Copyright 2010-2012 Kay Sievers
+# Copyright 2013 Zbigniew Jędrzejewski-Szmek
+# Copyright 2013 David Strauss
+# Copyright 2016 Luke Shumaker
+#
+# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
+include $(topsrcdir)/build-aux/Makefile.head.mk
+
+systemd_journald_SOURCES = \
+ src/journal/journald.c \
+ src/journal/journald-server.h
+
+systemd_journald_LDADD = \
+ libjournal-core.la \
+ libshared.la
+
+systemd_cat_SOURCES = \
+ src/journal/cat.c
+
+systemd_cat_LDADD = \
+ libjournal-core.la
+
+
+libexec_PROGRAMS += \
+ systemd-journald
+
+bin_PROGRAMS += \
+ journalctl
+
+bin_PROGRAMS += \
+ systemd-cat
+
+dist_systemunit_DATA += \
+ units/systemd-journald.socket \
+ units/systemd-journald-dev-log.socket \
+ units/systemd-journald-audit.socket
+
+nodist_systemunit_DATA += \
+ units/systemd-journald.service \
+ units/systemd-journal-flush.service \
+ units/systemd-journal-catalog-update.service
+
+dist_pkgsysconf_DATA += \
+ src/journal/journald.conf
+
+dist_catalog_DATA = \
+ catalog/systemd.bg.catalog \
+ catalog/systemd.be.catalog \
+ catalog/systemd.be@latin.catalog \
+ catalog/systemd.fr.catalog \
+ catalog/systemd.it.catalog \
+ catalog/systemd.pl.catalog \
+ catalog/systemd.pt_BR.catalog \
+ catalog/systemd.ru.catalog \
+ catalog/systemd.zh_CN.catalog \
+ catalog/systemd.zh_TW.catalog \
+ catalog/systemd.catalog
+
+SOCKETS_TARGET_WANTS += \
+ systemd-journald.socket \
+ systemd-journald-dev-log.socket \
+ systemd-journald-audit.socket
+
+SYSINIT_TARGET_WANTS += \
+ systemd-journald.service \
+ systemd-journal-flush.service \
+ systemd-journal-catalog-update.service
+
+EXTRA_DIST += \
+ units/systemd-journald.service.in \
+ units/systemd-journal-flush.service.in \
+ units/systemd-journal-catalog-update.service.in
+
+gperf_gperf_sources += \
+ src/journal/journald-gperf.gperf
+
+include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/journal/journald.c b/src/grp-journal/systemd-journald/journald.c
index 1afe44fa8e..1afe44fa8e 100644
--- a/src/journal/journald.c
+++ b/src/grp-journal/systemd-journald/journald.c
diff --git a/src/grp-machine/libmachine-core/Makefile b/src/grp-machine/libmachine-core/Makefile
index f37ec9772b..3881224746 100644
--- a/src/grp-machine/libmachine-core/Makefile
+++ b/src/grp-machine/libmachine-core/Makefile
@@ -30,7 +30,9 @@ libmachine_core_la_SOURCES = \
src/machine/machine-dbus.c \
src/machine/machine-dbus.h \
src/machine/image-dbus.c \
- src/machine/image-dbus.h
+ src/machine/image-dbus.h \
+ src/machine/operation.c \
+ src/machine/operation.h
libmachine_core_la_LIBADD = \
libshared.la
diff --git a/src/grp-machine/libmachine-core/image-dbus.c b/src/grp-machine/libmachine-core/image-dbus.c
index 73f5112c4d..0eed9b81bb 100644
--- a/src/grp-machine/libmachine-core/image-dbus.c
+++ b/src/grp-machine/libmachine-core/image-dbus.c
@@ -20,9 +20,11 @@
#include "alloc-util.h"
#include "bus-label.h"
#include "bus-util.h"
+#include "fd-util.h"
#include "image-dbus.h"
#include "io-util.h"
#include "machine-image.h"
+#include "process-util.h"
#include "strv.h"
#include "user-util.h"
@@ -33,13 +35,18 @@ int bus_image_method_remove(
void *userdata,
sd_bus_error *error) {
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
Image *image = userdata;
Manager *m = image->userdata;
+ pid_t child;
int r;
assert(message);
assert(image);
+ if (m->n_operations >= OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
+
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
@@ -54,11 +61,35 @@ int bus_image_method_remove(
if (r == 0)
return 1; /* Will call us back */
- r = image_remove(image);
- if (r < 0)
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ if (child == 0) {
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ r = image_remove(image);
+ if (r < 0) {
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ if (r < 0) {
+ (void) sigkill_wait(child);
return r;
+ }
- return sd_bus_reply_method_return(message, NULL);
+ errno_pipe_fd[0] = -1;
+
+ return 1;
}
int bus_image_method_rename(
@@ -107,13 +138,19 @@ int bus_image_method_clone(
void *userdata,
sd_bus_error *error) {
+ _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
Image *image = userdata;
Manager *m = image->userdata;
const char *new_name;
int r, read_only;
+ pid_t child;
assert(message);
assert(image);
+ assert(m);
+
+ if (m->n_operations >= OPERATIONS_MAX)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
r = sd_bus_message_read(message, "sb", &new_name, &read_only);
if (r < 0)
@@ -136,11 +173,35 @@ int bus_image_method_clone(
if (r == 0)
return 1; /* Will call us back */
- r = image_clone(image, new_name, read_only);
- if (r < 0)
+ if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+ if (child == 0) {
+ errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
+
+ r = image_clone(image, new_name, read_only);
+ if (r < 0) {
+ (void) write(errno_pipe_fd[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
+
+ r = operation_new(m, NULL, child, message, errno_pipe_fd[0]);
+ if (r < 0) {
+ (void) sigkill_wait(child);
return r;
+ }
- return sd_bus_reply_method_return(message, NULL);
+ errno_pipe_fd[0] = -1;
+
+ return 1;
}
int bus_image_method_mark_read_only(
diff --git a/src/grp-machine/libmachine-core/machine-dbus.c b/src/grp-machine/libmachine-core/machine-dbus.c
index 71f20b3f07..7b9aa66d63 100644
--- a/src/grp-machine/libmachine-core/machine-dbus.c
+++ b/src/grp-machine/libmachine-core/machine-dbus.c
@@ -20,6 +20,7 @@
#include <errno.h>
#include <string.h>
#include <sys/mount.h>
+#include <sys/wait.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
@@ -45,6 +46,7 @@
#include "mkdir.h"
#include "path-util.h"
#include "process-util.h"
+#include "signal-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "user-util.h"
@@ -165,7 +167,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
}
- if (signo <= 0 || signo >= _NSIG)
+ if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
r = bus_verify_polkit_async(
@@ -728,7 +730,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
return r;
/* Name and mode */
- unit = strjoina("container-shell@", p, ".service", NULL);
+ unit = strjoina("container-shell@", p, ".service");
r = sd_bus_message_append(tm, "ss", unit, "fail");
if (r < 0)
return r;
@@ -1083,52 +1085,11 @@ finish:
return r;
}
-static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- MachineOperation *o = userdata;
- int r;
-
- assert(o);
- assert(si);
-
- o->pid = 0;
-
- if (si->si_code != CLD_EXITED) {
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
- goto fail;
- }
-
- if (si->si_status != EXIT_SUCCESS) {
- if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
- r = sd_bus_error_set_errnof(&error, r, "%m");
- else
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
-
- goto fail;
- }
-
- r = sd_bus_reply_method_return(o->message, NULL);
- if (r < 0)
- log_error_errno(r, "Failed to reply to message: %m");
-
- machine_operation_unref(o);
- return 0;
-
-fail:
- r = sd_bus_reply_method_error(o->message, &error);
- if (r < 0)
- log_error_errno(r, "Failed to reply to message: %m");
-
- machine_operation_unref(o);
- return 0;
-}
-
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
_cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
_cleanup_close_ int hostfd = -1;
Machine *m = userdata;
- MachineOperation *o;
bool copy_from;
pid_t child;
char *t;
@@ -1137,7 +1098,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
assert(message);
assert(m);
- if (m->n_operations >= MACHINE_OPERATIONS_MAX)
+ if (m->manager->n_operations >= OPERATIONS_MAX)
return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
if (m->class != MACHINE_CONTAINER)
@@ -1247,29 +1208,107 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
- /* Copying might take a while, hence install a watch the
- * child, and return */
+ /* Copying might take a while, hence install a watch on the child, and return */
- o = new0(MachineOperation, 1);
- if (!o)
- return log_oom();
-
- o->pid = child;
- o->message = sd_bus_message_ref(message);
- o->errno_fd = errno_pipe_fd[0];
+ r = operation_new(m->manager, m, child, message, errno_pipe_fd[0]);
+ if (r < 0) {
+ (void) sigkill_wait(child);
+ return r;
+ }
errno_pipe_fd[0] = -1;
- r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
- if (r < 0) {
- machine_operation_unref(o);
- return log_oom();
+ return 1;
+}
+
+int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_close_ int fd = -1;
+ Machine *m = userdata;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-machines",
+ NULL,
+ false,
+ UID_INVALID,
+ &m->manager->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ switch (m->class) {
+
+ case MACHINE_HOST:
+ fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ if (fd < 0)
+ return -errno;
+
+ break;
+
+ case MACHINE_CONTAINER: {
+ _cleanup_close_ int mntns_fd = -1, root_fd = -1;
+ _cleanup_close_pair_ int pair[2] = { -1, -1 };
+ siginfo_t si;
+ pid_t child;
+
+ r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ return -errno;
+
+ child = fork();
+ if (child < 0)
+ return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+
+ if (child == 0) {
+ _cleanup_close_ int dfd = -1;
+
+ pair[0] = safe_close(pair[0]);
+
+ r = namespace_enter(-1, mntns_fd, -1, -1, root_fd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ if (dfd < 0)
+ _exit(EXIT_FAILURE);
+
+ r = send_one_fd(pair[1], dfd, 0);
+ dfd = safe_close(dfd);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m");
+ if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+
+ fd = receive_one_fd(pair[0], MSG_DONTWAIT);
+ if (fd < 0)
+ return fd;
+
+ break;
}
- LIST_PREPEND(operations, m->operations, o);
- m->n_operations++;
- o->machine = m;
+ default:
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening the root directory is only supported on container machines.");
+ }
- return 1;
+ return sd_bus_reply_method_return(message, "h", fd);
}
const sd_bus_vtable machine_vtable[] = {
@@ -1295,6 +1334,7 @@ const sd_bus_vtable machine_vtable[] = {
SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("OpenRootDirectory", NULL, "h", bus_machine_method_open_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
diff --git a/src/grp-machine/libmachine-core/machine-dbus.h b/src/grp-machine/libmachine-core/machine-dbus.h
index 224f36529f..d3faf5cb07 100644
--- a/src/grp-machine/libmachine-core/machine-dbus.h
+++ b/src/grp-machine/libmachine-core/machine-dbus.h
@@ -38,6 +38,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu
int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_machine_method_open_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error);
int machine_send_signal(Machine *m, bool new_machine);
int machine_send_create_reply(Machine *m, sd_bus_error *error);
diff --git a/src/grp-machine/libmachine-core/machine.c b/src/grp-machine/libmachine-core/machine.c
index 468fc1fecf..135f47dafc 100644
--- a/src/grp-machine/libmachine-core/machine.c
+++ b/src/grp-machine/libmachine-core/machine.c
@@ -89,7 +89,7 @@ void machine_free(Machine *m) {
assert(m);
while (m->operations)
- machine_operation_unref(m->operations);
+ operation_free(m->operations);
if (m->in_gc_queue)
LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
@@ -299,17 +299,10 @@ int machine_load(Machine *m) {
m->class = c;
}
- if (realtime) {
- unsigned long long l;
- if (sscanf(realtime, "%llu", &l) > 0)
- m->timestamp.realtime = l;
- }
-
- if (monotonic) {
- unsigned long long l;
- if (sscanf(monotonic, "%llu", &l) > 0)
- m->timestamp.monotonic = l;
- }
+ if (realtime)
+ timestamp_deserialize(realtime, &m->timestamp.realtime);
+ if (monotonic)
+ timestamp_deserialize(monotonic, &m->timestamp.monotonic);
if (netif) {
size_t allocated = 0, nr = 0;
@@ -317,7 +310,7 @@ int machine_load(Machine *m) {
int *ni = NULL;
p = netif;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL;
int ifi;
@@ -603,28 +596,6 @@ int machine_open_terminal(Machine *m, const char *path, int mode) {
}
}
-MachineOperation *machine_operation_unref(MachineOperation *o) {
- if (!o)
- return NULL;
-
- sd_event_source_unref(o->event_source);
-
- safe_close(o->errno_fd);
-
- if (o->pid > 1)
- (void) kill(o->pid, SIGKILL);
-
- sd_bus_message_unref(o->message);
-
- if (o->machine) {
- LIST_REMOVE(operations, o->machine->operations, o);
- o->machine->n_operations--;
- }
-
- free(o);
- return NULL;
-}
-
void machine_release_unit(Machine *m) {
assert(m);
diff --git a/src/grp-machine/libmachine-core/machine.h b/src/grp-machine/libmachine-core/machine.h
index 1d8cc5911a..e5d75361a9 100644
--- a/src/grp-machine/libmachine-core/machine.h
+++ b/src/grp-machine/libmachine-core/machine.h
@@ -20,11 +20,11 @@
***/
typedef struct Machine Machine;
-typedef struct MachineOperation MachineOperation;
typedef enum KillWho KillWho;
#include "list.h"
#include "machined.h"
+#include "operation.h"
typedef enum MachineState {
MACHINE_OPENING, /* Machine is being registered */
@@ -49,17 +49,6 @@ enum KillWho {
_KILL_WHO_INVALID = -1
};
-#define MACHINE_OPERATIONS_MAX 64
-
-struct MachineOperation {
- Machine *machine;
- pid_t pid;
- sd_bus_message *message;
- int errno_fd;
- sd_event_source *event_source;
- LIST_FIELDS(MachineOperation, operations);
-};
-
struct Machine {
Manager *manager;
@@ -88,10 +77,9 @@ struct Machine {
int *netif;
unsigned n_netif;
- LIST_FIELDS(Machine, gc_queue);
+ LIST_HEAD(Operation, operations);
- MachineOperation *operations;
- unsigned n_operations;
+ LIST_FIELDS(Machine, gc_queue);
};
Machine* machine_new(Manager *manager, MachineClass class, const char *name);
@@ -109,8 +97,6 @@ void machine_release_unit(Machine *m);
MachineState machine_get_state(Machine *u);
-MachineOperation *machine_operation_unref(MachineOperation *o);
-
const char* machine_class_to_string(MachineClass t) _const_;
MachineClass machine_class_from_string(const char *s) _pure_;
diff --git a/src/grp-machine/libmachine-core/machined-dbus.c b/src/grp-machine/libmachine-core/machined-dbus.c
index 96f2c4769e..41f138882b 100644
--- a/src/grp-machine/libmachine-core/machined-dbus.c
+++ b/src/grp-machine/libmachine-core/machined-dbus.c
@@ -706,6 +706,26 @@ static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_e
return bus_machine_method_copy(message, machine, error);
}
+static int method_open_machine_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ Machine *machine;
+ const char *name;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return r;
+
+ machine = hashmap_get(m->machines, name);
+ if (!machine)
+ return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
+
+ return bus_machine_method_open_root_directory(message, machine, error);
+}
+
static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(image_unrefp) Image* i = NULL;
const char *name;
@@ -802,6 +822,93 @@ static int method_mark_image_read_only(sd_bus_message *message, void *userdata,
return bus_image_method_mark_read_only(message, i, error);
}
+static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ enum {
+ REMOVE_ALL,
+ REMOVE_HIDDEN,
+ } mode;
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
+ Manager *m = userdata;
+ Image *image;
+ const char *mm;
+ Iterator i;
+ int r;
+
+ assert(message);
+
+ r = sd_bus_message_read(message, "s", &mm);
+ if (r < 0)
+ return r;
+
+ if (streq(mm, "all"))
+ mode = REMOVE_ALL;
+ else if (streq(mm, "hidden"))
+ mode = REMOVE_HIDDEN;
+ else
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm);
+
+ r = bus_verify_polkit_async(
+ message,
+ CAP_SYS_ADMIN,
+ "org.freedesktop.machine1.manage-machines",
+ NULL,
+ false,
+ UID_INVALID,
+ &m->polkit_registry,
+ error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* Will call us back */
+
+ images = hashmap_new(&string_hash_ops);
+ if (!images)
+ return -ENOMEM;
+
+ r = image_discover(images);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ HASHMAP_FOREACH(image, images, i) {
+
+ /* We can't remove vendor images (i.e. those in /usr) */
+ if (IMAGE_IS_VENDOR(image))
+ continue;
+
+ if (IMAGE_IS_HOST(image))
+ continue;
+
+ if (mode == REMOVE_HIDDEN && !IMAGE_IS_HIDDEN(image))
+ continue;
+
+ r = image_remove(image);
+ if (r == -EBUSY) /* keep images that are currently being used. */
+ continue;
+ if (r < 0)
+ return sd_bus_error_set_errnof(error, r, "Failed to remove image %s: %m", image->name);
+
+ r = sd_bus_message_append(reply, "(st)", image->name, image->usage_exclusive);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
uint64_t limit;
@@ -1138,12 +1245,14 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("OpenMachineRootDirectory", "s", "h", method_open_machine_root_directory, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CleanPool", "s", "a(st)", method_clean_pool, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -1212,7 +1321,7 @@ int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_err
r = unit_name_from_dbus_path(path, &unit);
if (r == -EINVAL) /* not for a unit */
return 0;
- if (r < 0){
+ if (r < 0) {
log_oom();
return 0;
}
diff --git a/src/grp-machine/libmachine-core/machined.h b/src/grp-machine/libmachine-core/machined.h
index 0fe50aaa66..777571ebc0 100644
--- a/src/grp-machine/libmachine-core/machined.h
+++ b/src/grp-machine/libmachine-core/machined.h
@@ -32,6 +32,7 @@ typedef struct Manager Manager;
#include "image-dbus.h"
#include "machine-dbus.h"
#include "machine.h"
+#include "operation.h"
struct Manager {
sd_event *event;
@@ -49,6 +50,9 @@ struct Manager {
LIST_HEAD(Machine, machine_gc_queue);
Machine *host_machine;
+
+ LIST_HEAD(Operation, operations);
+ unsigned n_operations;
};
Manager *manager_new(void);
diff --git a/src/grp-machine/libmachine-core/operation.c b/src/grp-machine/libmachine-core/operation.c
new file mode 100644
index 0000000000..e6ddc41a55
--- /dev/null
+++ b/src/grp-machine/libmachine-core/operation.c
@@ -0,0 +1,131 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "operation.h"
+#include "process-util.h"
+
+static int operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ Operation *o = userdata;
+ int r;
+
+ assert(o);
+ assert(si);
+
+ log_debug("Operating " PID_FMT " is now complete with with code=%s status=%i",
+ o->pid,
+ sigchld_code_to_string(si->si_code), si->si_status);
+
+ o->pid = 0;
+
+ if (si->si_code != CLD_EXITED) {
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child died abnormally.");
+ goto fail;
+ }
+
+ if (si->si_status != EXIT_SUCCESS) {
+ if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
+ r = sd_bus_error_set_errnof(&error, r, "%m");
+ else
+ r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Child failed.");
+
+ goto fail;
+ }
+
+ r = sd_bus_reply_method_return(o->message, NULL);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ operation_free(o);
+ return 0;
+
+fail:
+ r = sd_bus_reply_method_error(o->message, &error);
+ if (r < 0)
+ log_error_errno(r, "Failed to reply to message: %m");
+
+ operation_free(o);
+ return 0;
+}
+
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd) {
+ Operation *o;
+ int r;
+
+ assert(manager);
+ assert(child > 1);
+ assert(message);
+ assert(errno_fd >= 0);
+
+ o = new0(Operation, 1);
+ if (!o)
+ return -ENOMEM;
+
+ r = sd_event_add_child(manager->event, &o->event_source, child, WEXITED, operation_done, o);
+ if (r < 0) {
+ free(o);
+ return r;
+ }
+
+ o->pid = child;
+ o->message = sd_bus_message_ref(message);
+ o->errno_fd = errno_fd;
+
+ LIST_PREPEND(operations, manager->operations, o);
+ manager->n_operations++;
+ o->manager = manager;
+
+ if (machine) {
+ LIST_PREPEND(operations_by_machine, machine->operations, o);
+ o->machine = machine;
+ }
+
+ log_debug("Started new operation " PID_FMT ".", child);
+
+ /* At this point we took ownership of both the child and the errno file descriptor! */
+
+ return 0;
+}
+
+Operation *operation_free(Operation *o) {
+ if (!o)
+ return NULL;
+
+ sd_event_source_unref(o->event_source);
+
+ safe_close(o->errno_fd);
+
+ if (o->pid > 1)
+ (void) sigkill_wait(o->pid);
+
+ sd_bus_message_unref(o->message);
+
+ if (o->manager) {
+ LIST_REMOVE(operations, o->manager->operations, o);
+ o->manager->n_operations--;
+ }
+
+ if (o->machine)
+ LIST_REMOVE(operations_by_machine, o->machine->operations, o);
+
+ free(o);
+ return NULL;
+}
diff --git a/src/libcore/bus-endpoint.h b/src/grp-machine/libmachine-core/operation.h
index f2fbc4701c..9397cd5f6d 100644
--- a/src/libcore/bus-endpoint.h
+++ b/src/grp-machine/libmachine-core/operation.h
@@ -3,7 +3,7 @@
/***
This file is part of systemd.
- Copyright 2014 Daniel Mack
+ Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -19,24 +19,29 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct BusEndpoint BusEndpoint;
-typedef struct BusEndpointPolicy BusEndpointPolicy;
+#include <sys/types.h>
-#include "bus-policy.h"
-#include "hashmap.h"
+#include <systemd/sd-bus.h>
+#include <systemd/sd-event.h>
-struct BusEndpointPolicy {
- char *name;
- BusPolicyAccess access;
-};
+#include "list.h"
-struct BusEndpoint {
- Hashmap *policy_hash;
-};
+typedef struct Operation Operation;
-int bus_endpoint_new(BusEndpoint **ep);
-void bus_endpoint_free(BusEndpoint *endpoint);
+#include "machined.h"
-int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access);
+#define OPERATIONS_MAX 64
+
+struct Operation {
+ Manager *manager;
+ Machine *machine;
+ pid_t pid;
+ sd_bus_message *message;
+ int errno_fd;
+ sd_event_source *event_source;
+ LIST_FIELDS(Operation, operations);
+ LIST_FIELDS(Operation, operations_by_machine);
+};
-int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep);
+int operation_new(Manager *manager, Machine *machine, pid_t child, sd_bus_message *message, int errno_fd);
+Operation *operation_free(Operation *o);
diff --git a/src/grp-machine/machinectl/machinectl.c b/src/grp-machine/machinectl/machinectl.c
index fb743ab6cb..92ffa8b83d 100644
--- a/src/grp-machine/machinectl/machinectl.c
+++ b/src/grp-machine/machinectl/machinectl.c
@@ -33,6 +33,7 @@
#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
@@ -61,6 +62,7 @@
static char **arg_property = NULL;
static bool arg_all = false;
+static bool arg_value = false;
static bool arg_full = false;
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -80,14 +82,6 @@ static const char* arg_format = NULL;
static const char *arg_uid = NULL;
static char **arg_setenv = NULL;
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
static void polkit_agent_open_if_enabled(void) {
/* Open the polkit agent as a child process if necessary */
@@ -135,17 +129,16 @@ static int list_machines(int argc, char *argv[], void *userdata) {
assert(bus);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "ListMachines",
- &error,
- &reply,
- NULL);
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "ListMachines",
+ &error,
+ &reply,
+ NULL);
if (r < 0) {
log_error("Could not get machines: %s", bus_error_message(&error, -r));
return r;
@@ -180,7 +173,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
if (l > max_service)
max_service = l;
- n_machines ++;
+ n_machines++;
}
if (r < 0)
return bus_log_parse_error(r);
@@ -238,17 +231,16 @@ static int list_images(int argc, char *argv[], void *userdata) {
assert(bus);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "ListImages",
- &error,
- &reply,
- "");
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "ListImages",
+ &error,
+ &reply,
+ "");
if (r < 0) {
log_error("Could not get images: %s", bus_error_message(&error, -r));
return r;
@@ -340,8 +332,8 @@ static int list_images(int argc, char *argv[], void *userdata) {
}
static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *path = NULL;
const char *cgroup;
int r;
@@ -350,9 +342,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
assert(bus);
assert(unit);
- if (arg_transport == BUS_TRANSPORT_REMOTE)
- return 0;
-
path = unit_dbus_path_from_name(unit);
if (!path)
return log_oom();
@@ -366,16 +355,14 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
&error,
&reply,
"s");
- if (r < 0) {
- log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
- return r;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &cgroup);
if (r < 0)
return bus_log_parse_error(r);
- if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
+ if (isempty(cgroup))
return 0;
c = columns();
@@ -384,7 +371,21 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
else
c = 0;
- show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
+ r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
+ if (r == -EBADR) {
+
+ if (arg_transport == BUS_TRANSPORT_REMOTE)
+ return 0;
+
+ /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
+
+ if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
+ return 0;
+
+ show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
+
return 0;
}
@@ -688,7 +689,7 @@ static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line
*new_line = true;
- r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
+ r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all);
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
@@ -707,7 +708,7 @@ static int show_machine(int argc, char *argv[], void *userdata) {
properties = !strstr(argv[0], "status");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (properties && argc <= 1) {
@@ -721,15 +722,14 @@ static int show_machine(int argc, char *argv[], void *userdata) {
for (i = 1; i < argc; i++) {
const char *path = NULL;
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.machine1",
- "/org/freedesktop/machine1",
- "org.freedesktop.machine1.Manager",
- "GetMachine",
- &error,
- &reply,
- "s", argv[i]);
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "GetMachine",
+ &error,
+ &reply,
+ "s", argv[i]);
if (r < 0) {
log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
return r;
@@ -937,7 +937,7 @@ static int show_image_properties(sd_bus *bus, const char *path, bool *new_line)
*new_line = true;
- r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
+ r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_value, arg_all);
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
@@ -956,7 +956,7 @@ static int show_image(int argc, char *argv[], void *userdata) {
properties = !strstr(argv[0], "status");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (argc <= 1) {
@@ -1076,6 +1076,7 @@ static int terminate_machine(int argc, char *argv[], void *userdata) {
static int copy_files(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_free_ char *abs_host_path = NULL;
char *dest, *host_path, *container_path;
sd_bus *bus = userdata;
@@ -1099,19 +1100,28 @@ static int copy_files(int argc, char *argv[], void *userdata) {
host_path = abs_host_path;
}
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- copy_from ? "CopyFromMachine" : "CopyToMachine",
- &error,
- NULL,
+ copy_from ? "CopyFromMachine" : "CopyToMachine");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(
+ m,
"sss",
argv[1],
copy_from ? container_path : host_path,
copy_from ? host_path : container_path);
if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r));
return 0;
@@ -1393,7 +1403,6 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
}
static int remove_image(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
@@ -1402,19 +1411,27 @@ static int remove_image(int argc, char *argv[], void *userdata) {
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
- r = sd_bus_call_method(
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "RemoveImage",
- &error,
- NULL,
- "s", argv[i]);
- if (r < 0) {
- log_error("Could not remove image: %s", bus_error_message(&error, -r));
- return r;
- }
+ "RemoveImage");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "s", argv[i]);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not remove image: %s", bus_error_message(&error, r));
}
return 0;
@@ -1446,24 +1463,30 @@ static int rename_image(int argc, char *argv[], void *userdata) {
static int clone_image(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
sd_bus *bus = userdata;
int r;
polkit_agent_open_if_enabled();
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "CloneImage",
- &error,
- NULL,
- "ssb", argv[1], argv[2], arg_read_only);
- if (r < 0) {
- log_error("Could not clone image: %s", bus_error_message(&error, -r));
- return r;
- }
+ "CloneImage");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append(m, "ssb", argv[1], argv[2], arg_read_only);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* This is a slow operation, hence turn off any method call timeouts */
+ r = sd_bus_call(bus, m, USEC_INFINITY, &error, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Could not clone image: %s", bus_error_message(&error, r));
return 0;
}
@@ -1579,6 +1602,8 @@ static int start_machine(int argc, char *argv[], void *userdata) {
static int enable_machine(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
int carries_install_info = 0;
const char *method = NULL;
sd_bus *bus = userdata;
@@ -1639,9 +1664,9 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
return bus_log_parse_error(r);
}
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
if (r < 0)
- return r;
+ goto finish;
r = sd_bus_call_method(
bus,
@@ -1654,10 +1679,15 @@ static int enable_machine(int argc, char *argv[], void *userdata) {
NULL);
if (r < 0) {
log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
- return r;
+ goto finish;
}
- return 0;
+ r = 0;
+
+finish:
+ unit_file_changes_free(changes, n_changes);
+
+ return r;
}
static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) {
@@ -1763,7 +1793,7 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
- log_error("Failed transfer image: %s", bus_error_message(&error, -r));
+ log_error("Failed to transfer image: %s", bus_error_message(&error, -r));
return r;
}
@@ -2189,17 +2219,16 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
double progress;
int r;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
- r = sd_bus_call_method(
- bus,
- "org.freedesktop.import1",
- "/org/freedesktop/import1",
- "org.freedesktop.import1.Manager",
- "ListTransfers",
- &error,
- &reply,
- NULL);
+ r = sd_bus_call_method(bus,
+ "org.freedesktop.import1",
+ "/org/freedesktop/import1",
+ "org.freedesktop.import1.Manager",
+ "ListTransfers",
+ &error,
+ &reply,
+ NULL);
if (r < 0) {
log_error("Could not get transfers: %s", bus_error_message(&error, -r));
return r;
@@ -2236,7 +2265,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) {
if (id > max_id)
max_id = id;
- n_transfers ++;
+ n_transfers++;
}
if (r < 0)
return bus_log_parse_error(r);
@@ -2349,6 +2378,50 @@ static int set_limit(int argc, char *argv[], void *userdata) {
return 0;
}
+static int clean_images(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ uint64_t usage, total = 0;
+ char fb[FORMAT_BYTES_MAX];
+ sd_bus *bus = userdata;
+ const char *name;
+ unsigned c = 0;
+ int r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.machine1",
+ "/org/freedesktop/machine1",
+ "org.freedesktop.machine1.Manager",
+ "CleanPool",
+ &error,
+ &reply,
+ "s", arg_all ? "all" : "hidden");
+ if (r < 0)
+ return log_error_errno(r, "Could not clean pool: %s", bus_error_message(&error, r));
+
+ r = sd_bus_message_enter_container(reply, 'a', "(st)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) {
+ log_info("Removed image '%s'. Freed exclusive disk space: %s",
+ name, format_bytes(fb, sizeof(fb), usage));
+
+ total += usage;
+ c++;
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ log_info("Removed %u images in total. Total freed exclusive disk space %s.",
+ c, format_bytes(fb, sizeof(fb), total));
+
+ return 0;
+}
+
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
@@ -2364,11 +2437,12 @@ static int help(int argc, char *argv[], void *userdata) {
" -p --property=NAME Show only properties by this name\n"
" -q --quiet Suppress output\n"
" -a --all Show all properties, including empty ones\n"
+ " --value When showing properties, only print the value\n"
" -l --full Do not ellipsize output\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
" --uid=USER Specify user ID to invoke shell as\n"
- " --setenv=VAR=VALUE Add an environment variable for shell\n"
+ " -E --setenv=VAR=VALUE Add an environment variable for shell\n"
" --read-only Create read-only bind mount\n"
" --mkdir Create directory before bind mounting, if missing\n"
" -n --lines=INTEGER Number of journal entries to show\n"
@@ -2405,7 +2479,8 @@ static int help(int argc, char *argv[], void *userdata) {
" rename NAME NAME Rename an image\n"
" read-only NAME [BOOL] Mark or unmark image read-only\n"
" remove NAME... Remove an image\n"
- " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n"
+ " set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n"
+ " clean Remove hidden (or all) images\n\n"
"Image Transfer Commands:\n"
" pull-tar URL [NAME] Download a TAR container image\n"
" pull-raw URL [NAME] Download a RAW container or VM image\n"
@@ -2426,6 +2501,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
+ ARG_VALUE,
ARG_KILL_WHO,
ARG_READ_ONLY,
ARG_MKDIR,
@@ -2434,7 +2510,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FORCE,
ARG_FORMAT,
ARG_UID,
- ARG_SETENV,
};
static const struct option options[] = {
@@ -2442,6 +2517,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "property", required_argument, NULL, 'p' },
{ "all", no_argument, NULL, 'a' },
+ { "value", no_argument, NULL, ARG_VALUE },
{ "full", no_argument, NULL, 'l' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
@@ -2459,16 +2535,38 @@ static int parse_argv(int argc, char *argv[]) {
{ "force", no_argument, NULL, ARG_FORCE },
{ "format", required_argument, NULL, ARG_FORMAT },
{ "uid", required_argument, NULL, ARG_UID },
- { "setenv", required_argument, NULL, ARG_SETENV },
+ { "setenv", required_argument, NULL, 'E' },
{}
};
+ bool reorder = false;
int c, r;
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
+ for (;;) {
+ const char * const option_string = "+hp:als:H:M:qn:o:";
+
+ c = getopt_long(argc, argv, option_string + reorder, options, NULL);
+ if (c < 0) {
+ /* We generally are fine with the fact that getopt_long() reorders the command line, and looks
+ * for switches after the main verb. However, for "shell" we really don't want that, since we
+ * want that switches passed after that are passed to the program to execute, and not processed
+ * by us. To make this possible, we'll first invoke getopt_long() with reordering disabled
+ * (i.e. with the "+" prefix in the option string), and as soon as we hit the end (i.e. the
+ * verb) we check if that's "shell". If it is, we exit the loop, since we don't want any
+ * further options processed. However, if it is anything else, we process the same argument
+ * again, but this time allow reordering. */
+
+ if (!reorder && optind < argc && !streq(argv[optind], "shell")) {
+ reorder = true;
+ optind--;
+ continue;
+ }
+
+ break;
+ }
switch (c) {
@@ -2493,6 +2591,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_all = true;
break;
+ case ARG_VALUE:
+ arg_value = true;
+ break;
+
case 'l':
arg_full = true;
break;
@@ -2583,7 +2685,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_uid = optarg;
break;
- case ARG_SETENV:
+ case 'E':
if (!env_assignment_is_valid(optarg)) {
log_error("Environment assignment invalid: %s", optarg);
return -EINVAL;
@@ -2600,6 +2702,7 @@ static int parse_argv(int argc, char *argv[]) {
default:
assert_not_reached("Unhandled option");
}
+ }
return 1;
}
@@ -2639,6 +2742,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
{ "set-limit", 2, 3, 0, set_limit },
+ { "clean", VERB_ANY, 1, 0, clean_images },
{}
};
diff --git a/src/grp-machine/nss-mymachines/nss-mymachines.c b/src/grp-machine/nss-mymachines/nss-mymachines.c
index 9d401b39dd..da09035fe7 100644
--- a/src/grp-machine/nss-mymachines/nss-mymachines.c
+++ b/src/grp-machine/nss-mymachines/nss-mymachines.c
@@ -66,7 +66,7 @@ static int count_addresses(sd_bus_message *m, int af, unsigned *ret) {
if (af != AF_UNSPEC && family != af)
continue;
- c ++;
+ c++;
}
if (r < 0)
return r;
diff --git a/src/grp-machine/systemd-machined/machined.c b/src/grp-machine/systemd-machined/machined.c
index 6ada8671f8..151f0983ec 100644
--- a/src/grp-machine/systemd-machined/machined.c
+++ b/src/grp-machine/systemd-machined/machined.c
@@ -70,6 +70,11 @@ void manager_free(Manager *m) {
assert(m);
+ while (m->operations)
+ operation_free(m->operations);
+
+ assert(m->n_operations == 0);
+
while ((machine = hashmap_first(m->machines)))
machine_free(machine);
@@ -336,6 +341,9 @@ int manager_startup(Manager *m) {
static bool check_idle(void *userdata) {
Manager *m = userdata;
+ if (m->operations)
+ return false;
+
manager_gc(m, true);
return hashmap_isempty(m->machines);
diff --git a/src/grp-resolve/nss-resolve/nss-resolve.c b/src/grp-resolve/nss-resolve/nss-resolve.c
index d369f1b0c8..4c2101d856 100644
--- a/src/grp-resolve/nss-resolve/nss-resolve.c
+++ b/src/grp-resolve/nss-resolve/nss-resolve.c
@@ -90,7 +90,7 @@ static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
if (af != AF_UNSPEC && family != af)
continue;
- c ++;
+ c++;
}
if (r < 0)
return r;
@@ -117,13 +117,6 @@ enum nss_status _nss_resolve_gethostbyname4_r(
int *errnop, int *h_errnop,
int32_t *ttlp) {
- enum nss_status (*fallback)(
- const char *name,
- struct gaih_addrtuple **pat,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop,
- int32_t *ttlp);
-
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
@@ -275,15 +268,15 @@ enum nss_status _nss_resolve_gethostbyname4_r(
return NSS_STATUS_SUCCESS;
fallback:
- fallback = (enum nss_status (*)(const char *name,
- struct gaih_addrtuple **pat,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop,
- int32_t *ttlp))
- find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r");
+ {
+ _nss_gethostbyname4_r_t fallback;
+
+ fallback = (_nss_gethostbyname4_r_t)
+ find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r");
- if (fallback)
- return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp);
+ if (fallback)
+ return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp);
+ }
fail:
*errnop = -r;
@@ -300,15 +293,6 @@ enum nss_status _nss_resolve_gethostbyname3_r(
int32_t *ttlp,
char **canonp) {
- enum nss_status (*fallback)(
- const char *name,
- int af,
- struct hostent *result,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop,
- int32_t *ttlp,
- char **canonp);
-
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *r_name, *r_aliases, *r_addr, *r_addr_list;
@@ -480,16 +464,14 @@ enum nss_status _nss_resolve_gethostbyname3_r(
return NSS_STATUS_SUCCESS;
fallback:
- fallback = (enum nss_status (*)(const char *name,
- int af,
- struct hostent *result,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop,
- int32_t *ttlp,
- char **canonp))
- find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r");
- if (fallback)
- return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
+ {
+ _nss_gethostbyname3_r_t fallback;
+
+ fallback = (_nss_gethostbyname3_r_t)
+ find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r");
+ if (fallback)
+ return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
+ }
fail:
*errnop = -r;
@@ -505,15 +487,6 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
int *errnop, int *h_errnop,
int32_t *ttlp) {
- enum nss_status (*fallback)(
- const void* addr, socklen_t len,
- int af,
- struct hostent *result,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop,
- int32_t *ttlp);
-
-
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char *r_name, *r_aliases, *r_addr, *r_addr_list;
@@ -682,17 +655,15 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
return NSS_STATUS_SUCCESS;
fallback:
- fallback = (enum nss_status (*)(
- const void* addr, socklen_t len,
- int af,
- struct hostent *result,
- char *buffer, size_t buflen,
- int *errnop, int *h_errnop,
- int32_t *ttlp))
- find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r");
-
- if (fallback)
- return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp);
+ {
+ _nss_gethostbyaddr2_r_t fallback;
+
+ fallback = (_nss_gethostbyaddr2_r_t)
+ find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r");
+
+ if (fallback)
+ return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp);
+ }
fail:
*errnop = -r;
diff --git a/src/grp-resolve/systemd-resolved/Makefile b/src/grp-resolve/systemd-resolved/Makefile
index 4e34240a43..f025608eab 100644
--- a/src/grp-resolve/systemd-resolved/Makefile
+++ b/src/grp-resolve/systemd-resolved/Makefile
@@ -23,8 +23,35 @@
include $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
+
+$(outdir)/dns_type-list.txt: src/resolve/dns-type.h
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(SED) -n -r 's/.* DNS_TYPE_(\w+).*/\1/p' <$< >$@
+
+$(outdir)/dns_type-to-name.h: src/resolve/dns_type-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" } {printf " case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print " default: return NULL;\n\t}\n}\n" }' <$< >$@
+
+$(outdir)/dns_type-from-name.gperf: src/resolve/dns_type-list.txt
+ $(AM_V_at)$(MKDIR_P) $(dir $@)
+ $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct dns_type_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { s=$$1; sub(/_/, "-", s); printf "%s, ", $$s; printf "DNS_TYPE_%s\n", $$1 }' <$< >$@
+
ifneq ($(ENABLE_RESOLVED),)
+basic_dns_sources = \
+ src/resolve/resolved-dns-dnssec.c \
+ src/resolve/resolved-dns-dnssec.h \
+ src/resolve/resolved-dns-packet.c \
+ src/resolve/resolved-dns-packet.h \
+ src/resolve/resolved-dns-rr.c \
+ src/resolve/resolved-dns-rr.h \
+ src/resolve/resolved-dns-answer.c \
+ src/resolve/resolved-dns-answer.h \
+ src/resolve/resolved-dns-question.c \
+ src/resolve/resolved-dns-question.h \
+ src/resolve/dns-type.c \
+ src/resolve/dns-type.h
+
systemd_resolved_SOURCES = \
src/resolve/resolved.c \
src/resolve/resolved-manager.c \
@@ -44,14 +71,7 @@ systemd_resolved_SOURCES = \
src/resolve/resolved-mdns.h \
src/resolve/resolved-mdns.c \
src/resolve/resolved-def.h \
- src/resolve/resolved-dns-rr.h \
- src/resolve/resolved-dns-rr.c \
- src/resolve/resolved-dns-question.h \
- src/resolve/resolved-dns-question.c \
- src/resolve/resolved-dns-answer.h \
- src/resolve/resolved-dns-answer.c \
- src/resolve/resolved-dns-packet.h \
- src/resolve/resolved-dns-packet.c \
+ $(basic_dns_sources) \
src/resolve/resolved-dns-query.h \
src/resolve/resolved-dns-query.c \
src/resolve/resolved-dns-synthesize.h \
@@ -70,14 +90,12 @@ systemd_resolved_SOURCES = \
src/resolve/resolved-dns-zone.c \
src/resolve/resolved-dns-stream.h \
src/resolve/resolved-dns-stream.c \
- src/resolve/resolved-dns-dnssec.h \
- src/resolve/resolved-dns-dnssec.c \
src/resolve/resolved-dns-trust-anchor.h \
src/resolve/resolved-dns-trust-anchor.c \
src/resolve/resolved-etc-hosts.h \
src/resolve/resolved-etc-hosts.c \
- src/resolve/dns-type.c \
- src/resolve/dns-type.h
+ src/shared/gcrypt-util.c \
+ src/shared/gcrypt-util.h
nodist_systemd_resolved_SOURCES = \
src/resolve/dns_type-from-name.h \
@@ -137,18 +155,9 @@ lib_LTLIBRARIES += \
systemd_resolve_SOURCES = \
src/resolve/resolve-tool.c \
- src/resolve/resolved-dns-dnssec.c \
- src/resolve/resolved-dns-dnssec.h \
- src/resolve/resolved-dns-packet.c \
- src/resolve/resolved-dns-packet.h \
- src/resolve/resolved-dns-rr.c \
- src/resolve/resolved-dns-rr.h \
- src/resolve/resolved-dns-answer.c \
- src/resolve/resolved-dns-answer.h \
- src/resolve/resolved-dns-question.c \
- src/resolve/resolved-dns-question.h \
- src/resolve/dns-type.c \
- src/resolve/dns-type.h
+ $(basic_dns_sources) \
+ src/shared/gcrypt-util.c \
+ src/shared/gcrypt-util.h
nodist_systemd_resolve_SOURCES = \
src/resolve/dns_type-from-name.h \
@@ -160,27 +169,57 @@ systemd_resolve_LDADD = \
bin_PROGRAMS += \
systemd-resolve
+dist_bashcompletion_data += \
+ shell-completion/bash/systemd-resolve
+
+dist_zshcompletion_data += \
+ shell-completion/zsh/_systemd-resolve
+
tests += \
- test-dns-domain \
+ test-dns-packet \
+ test-resolve-tables \
test-dnssec
manual_tests += \
test-dnssec-complex
+test_resolve_tables_SOURCES = \
+ src/resolve/test-resolve-tables.c \
+ src/resolve/dns_type-from-name.h \
+ src/resolve/dns_type-to-name.h \
+ $(basic_dns_sources) \
+ src/shared/test-tables.h
+
+test_resolve_tables_LDADD = \
+ libshared.la
+
+test_dns_packet_SOURCES = \
+ src/resolve/test-dns-packet.c \
+ $(basic_dns_sources)
+
+test_dns_packet_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DRESOLVE_TEST_DIR=\"$(abs_top_srcdir)/src/resolve/test-data\"
+
+test_dns_packet_LDADD = \
+ libshared.la
+
+EXTRA_DIST += \
+ src/resolve/test-data/_openpgpkey.fedoraproject.org.pkts \
+ src/resolve/test-data/fedoraproject.org.pkts \
+ src/resolve/test-data/gandi.net.pkts \
+ src/resolve/test-data/google.com.pkts \
+ src/resolve/test-data/root.pkts \
+ src/resolve/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts \
+ src/resolve/test-data/teamits.com.pkts \
+ src/resolve/test-data/zbyszek@fedoraproject.org.pkts \
+ src/resolve/test-data/_443._tcp.fedoraproject.org.pkts \
+ src/resolve/test-data/kyhwana.org.pkts \
+ src/resolve/test-data/fake-caa.pkts
+
test_dnssec_SOURCES = \
src/resolve/test-dnssec.c \
- src/resolve/resolved-dns-packet.c \
- src/resolve/resolved-dns-packet.h \
- src/resolve/resolved-dns-rr.c \
- src/resolve/resolved-dns-rr.h \
- src/resolve/resolved-dns-answer.c \
- src/resolve/resolved-dns-answer.h \
- src/resolve/resolved-dns-question.c \
- src/resolve/resolved-dns-question.h \
- src/resolve/resolved-dns-dnssec.c \
- src/resolve/resolved-dns-dnssec.h \
- src/resolve/dns-type.c \
- src/resolve/dns-type.h
+ $(basic_dns_sources)
test_dnssec_LDADD = \
libshared.la
diff --git a/src/grp-resolve/systemd-resolved/RFCs b/src/grp-resolve/systemd-resolved/RFCs
index 22004a00cd..09c85f9518 100644
--- a/src/grp-resolve/systemd-resolved/RFCs
+++ b/src/grp-resolve/systemd-resolved/RFCs
@@ -8,7 +8,7 @@ D = Comprehensively Implemented, by a dependency of resolved
Y https://tools.ietf.org/html/rfc1034 → DOMAIN NAMES - CONCEPTS AND FACILITIES
Y https://tools.ietf.org/html/rfc1035 → DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION
? https://tools.ietf.org/html/rfc1101 → DNS Encoding of Network Names and Other Types
-Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts -- Application and Support
+Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts — Application and Support
~ https://tools.ietf.org/html/rfc1464 → Using the Domain Name System To Store Arbitrary String Attributes
Y https://tools.ietf.org/html/rfc1536 → Common DNS Implementation Errors and Suggested Fixes
Y https://tools.ietf.org/html/rfc1876 → A Means for Expressing Location Information in the Domain Name System
diff --git a/src/grp-resolve/systemd-resolved/dns-type.c b/src/grp-resolve/systemd-resolved/dns-type.c
index b2f479cae5..78d9d5733f 100644
--- a/src/grp-resolve/systemd-resolved/dns-type.c
+++ b/src/grp-resolve/systemd-resolved/dns-type.c
@@ -193,6 +193,23 @@ bool dns_type_is_obsolete(uint16_t type) {
DNS_TYPE_NULL);
}
+bool dns_type_needs_authentication(uint16_t type) {
+
+ /* Returns true for all (non-obsolete) RR types where records are not useful if they aren't
+ * authenticated. I.e. everything that contains crypto keys. */
+
+ return IN_SET(type,
+ DNS_TYPE_CERT,
+ DNS_TYPE_SSHFP,
+ DNS_TYPE_IPSECKEY,
+ DNS_TYPE_DS,
+ DNS_TYPE_DNSKEY,
+ DNS_TYPE_TLSA,
+ DNS_TYPE_CDNSKEY,
+ DNS_TYPE_OPENPGPKEY,
+ DNS_TYPE_CAA);
+}
+
int dns_type_to_af(uint16_t t) {
switch (t) {
diff --git a/src/grp-resolve/systemd-resolved/dns-type.h b/src/grp-resolve/systemd-resolved/dns-type.h
index a6c1630021..7b79d29d7e 100644
--- a/src/grp-resolve/systemd-resolved/dns-type.h
+++ b/src/grp-resolve/systemd-resolved/dns-type.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "macro.h"
/* DNS record types, taken from
@@ -124,6 +124,9 @@ enum {
_DNS_CLASS_INVALID = -1
};
+#define _DNS_CLASS_STRING_MAX (sizeof "CLASS" + DECIMAL_STR_MAX(uint16_t))
+#define _DNS_TYPE_STRING_MAX (sizeof "CLASS" + DECIMAL_STR_MAX(uint16_t))
+
bool dns_type_is_pseudo(uint16_t type);
bool dns_type_is_valid_query(uint16_t type);
bool dns_type_is_valid_rr(uint16_t type);
@@ -132,7 +135,8 @@ bool dns_type_is_dnssec(uint16_t type);
bool dns_type_is_obsolete(uint16_t type);
bool dns_type_may_wildcard(uint16_t type);
bool dns_type_apex_only(uint16_t type);
-int dns_type_to_af(uint16_t t);
+bool dns_type_needs_authentication(uint16_t type);
+int dns_type_to_af(uint16_t type);
bool dns_class_is_pseudo(uint16_t class);
bool dns_class_is_valid_rr(uint16_t class);
@@ -141,7 +145,7 @@ bool dns_class_is_valid_rr(uint16_t class);
const char *dns_type_to_string(int type);
int dns_type_from_string(const char *s);
-const char *dns_class_to_string(uint16_t type);
+const char *dns_class_to_string(uint16_t class);
int dns_class_from_string(const char *name);
/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.2 */
@@ -152,3 +156,6 @@ const char *tlsa_selector_to_string(uint8_t selector);
/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.4 */
const char *tlsa_matching_type_to_string(uint8_t selector);
+
+/* https://tools.ietf.org/html/rfc6844#section-5.1 */
+#define CAA_FLAG_CRITICAL (1u << 7)
diff --git a/src/grp-resolve/systemd-resolved/resolve-tool.c b/src/grp-resolve/systemd-resolved/resolve-tool.c
index 3f1b6e32f1..fbf7b0e4f6 100644
--- a/src/grp-resolve/systemd-resolved/resolve-tool.c
+++ b/src/grp-resolve/systemd-resolved/resolve-tool.c
@@ -28,6 +28,7 @@
#include "bus-util.h"
#include "escape.h"
#include "in-addr-util.h"
+#include "gcrypt-util.h"
#include "parse-util.h"
#include "resolved-def.h"
#include "resolved-dns-packet.h"
@@ -42,14 +43,54 @@ static uint16_t arg_class = 0;
static bool arg_legend = true;
static uint64_t arg_flags = 0;
+typedef enum ServiceFamily {
+ SERVICE_FAMILY_TCP,
+ SERVICE_FAMILY_UDP,
+ SERVICE_FAMILY_SCTP,
+ _SERVICE_FAMILY_INVALID = -1,
+} ServiceFamily;
+static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP;
+
+typedef enum RawType {
+ RAW_NONE,
+ RAW_PAYLOAD,
+ RAW_PACKET,
+} RawType;
+static RawType arg_raw = RAW_NONE;
+
static enum {
MODE_RESOLVE_HOST,
MODE_RESOLVE_RECORD,
MODE_RESOLVE_SERVICE,
+ MODE_RESOLVE_OPENPGP,
+ MODE_RESOLVE_TLSA,
MODE_STATISTICS,
MODE_RESET_STATISTICS,
} arg_mode = MODE_RESOLVE_HOST;
+static ServiceFamily service_family_from_string(const char *s) {
+ if (s == NULL || streq(s, "tcp"))
+ return SERVICE_FAMILY_TCP;
+ if (streq(s, "udp"))
+ return SERVICE_FAMILY_UDP;
+ if (streq(s, "sctp"))
+ return SERVICE_FAMILY_SCTP;
+ return _SERVICE_FAMILY_INVALID;
+}
+
+static const char* service_family_to_string(ServiceFamily service) {
+ switch(service) {
+ case SERVICE_FAMILY_TCP:
+ return "_tcp";
+ case SERVICE_FAMILY_UDP:
+ return "_udp";
+ case SERVICE_FAMILY_SCTP:
+ return "_sctp";
+ default:
+ assert_not_reached("invalid service");
+ }
+}
+
static void print_source(uint64_t flags, usec_t rtt) {
char rtt_str[FORMAT_TIMESTAMP_MAX];
@@ -328,6 +369,50 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres
return 0;
}
+static int output_rr_packet(const void *d, size_t l, int ifindex) {
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+ int r;
+ char ifname[IF_NAMESIZE] = "";
+
+ r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
+ if (r < 0)
+ return log_oom();
+
+ p->refuse_compression = true;
+
+ r = dns_packet_append_blob(p, d, l, NULL);
+ if (r < 0)
+ return log_oom();
+
+ r = dns_packet_read_rr(p, &rr, NULL, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse RR: %m");
+
+ if (arg_raw == RAW_PAYLOAD) {
+ void *data;
+ ssize_t k;
+
+ k = dns_resource_record_payload(rr, &data);
+ if (k < 0)
+ return log_error_errno(k, "Cannot dump RR: %m");
+ fwrite(data, 1, k, stdout);
+ } else {
+ const char *s;
+
+ s = dns_resource_record_to_string(rr);
+ if (!s)
+ return log_oom();
+
+ if (ifindex > 0 && !if_indextoname(ifindex, ifname))
+ log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
+
+ printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
+ }
+
+ return 0;
+}
+
static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -336,6 +421,7 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
uint64_t flags;
int r;
usec_t ts;
+ bool needs_authentication = false;
assert(name);
@@ -373,9 +459,6 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
return bus_log_parse_error(r);
while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
- _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
- const char *s;
uint16_t c, t;
int ifindex;
const void *d;
@@ -395,29 +478,20 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
if (r < 0)
return bus_log_parse_error(r);
- r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
- if (r < 0)
- return log_oom();
-
- p->refuse_compression = true;
+ if (arg_raw == RAW_PACKET) {
+ uint64_t u64 = htole64(l);
- r = dns_packet_append_blob(p, d, l, NULL);
- if (r < 0)
- return log_oom();
-
- r = dns_packet_read_rr(p, &rr, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to parse RR: %m");
+ fwrite(&u64, sizeof(u64), 1, stdout);
+ fwrite(d, 1, l, stdout);
+ } else {
+ r = output_rr_packet(d, l, ifindex);
+ if (r < 0)
+ return r;
+ }
- s = dns_resource_record_to_string(rr);
- if (!s)
- return log_oom();
+ if (dns_type_needs_authentication(t))
+ needs_authentication = true;
- ifname[0] = 0;
- if (ifindex > 0 && !if_indextoname(ifindex, ifname))
- log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
-
- printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
n++;
}
if (r < 0)
@@ -438,6 +512,18 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
print_source(flags, ts);
+ if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
+ fflush(stdout);
+
+ fprintf(stderr, "\n%s"
+ "WARNING: The resources shown contain cryptographic key data which could not be\n"
+ " authenticated. It is not suitable to authenticate any communication.\n"
+ " This is usually indication that DNSSEC authentication was not enabled\n"
+ " or is not available for the selected protocol or DNS servers.%s\n",
+ ansi_highlight_red(),
+ ansi_normal());
+ }
+
return 0;
}
@@ -545,15 +631,10 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) {
} else
n = p;
- if (type == 0)
- type = arg_type;
- if (type == 0)
- type = DNS_TYPE_A;
-
- if (class == 0)
- class = arg_class;
if (class == 0)
- class = DNS_CLASS_IN;
+ class = arg_class ?: DNS_CLASS_IN;
+ if (type == 0)
+ type = arg_type ?: DNS_TYPE_A;
return resolve_record(bus, n, class, type);
@@ -763,6 +844,68 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
return 0;
}
+static int resolve_openpgp(sd_bus *bus, const char *address) {
+ const char *domain, *full;
+ int r;
+ _cleanup_free_ char *hashed = NULL;
+
+ assert(bus);
+ assert(address);
+
+ domain = strrchr(address, '@');
+ if (!domain) {
+ log_error("Address does not contain '@': \"%s\"", address);
+ return -EINVAL;
+ } else if (domain == address || domain[1] == '\0') {
+ log_error("Address starts or ends with '@': \"%s\"", address);
+ return -EINVAL;
+ }
+ domain++;
+
+ r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
+ if (r < 0)
+ return log_error_errno(r, "Hashing failed: %m");
+
+ full = strjoina(hashed, "._openpgpkey.", domain);
+ log_debug("Looking up \"%s\".", full);
+
+ return resolve_record(bus, full,
+ arg_class ?: DNS_CLASS_IN,
+ arg_type ?: DNS_TYPE_OPENPGPKEY);
+}
+
+static int resolve_tlsa(sd_bus *bus, const char *address) {
+ const char *port;
+ uint16_t port_num = 443;
+ _cleanup_free_ char *full = NULL;
+ int r;
+
+ assert(bus);
+ assert(address);
+
+ port = strrchr(address, ':');
+ if (port) {
+ r = safe_atou16(port + 1, &port_num);
+ if (r < 0 || port_num == 0)
+ return log_error_errno(r, "Invalid port \"%s\".", port + 1);
+
+ address = strndupa(address, port - address);
+ }
+
+ r = asprintf(&full, "_%u.%s.%s",
+ port_num,
+ service_family_to_string(arg_service_family),
+ address);
+ if (r < 0)
+ return log_oom();
+
+ log_debug("Looking up \"%s\".", full);
+
+ return resolve_record(bus, full,
+ arg_class ?: DNS_CLASS_IN,
+ arg_type ?: DNS_TYPE_TLSA);
+}
+
static int show_statistics(sd_bus *bus) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -931,26 +1074,34 @@ static void help_dns_classes(void) {
}
static void help(void) {
- printf("%s [OPTIONS...] NAME...\n"
- "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n"
+ printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
+ "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
+ "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
+ "%1$s [OPTIONS...] --statistics\n"
+ "%1$s [OPTIONS...] --reset-statistics\n"
+ "\n"
"Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " -4 Resolve IPv4 addresses\n"
- " -6 Resolve IPv6 addresses\n"
- " -i --interface=INTERFACE Look on interface\n"
- " -p --protocol=PROTOCOL|help Look via protocol\n"
- " -t --type=TYPE|help Query RR with DNS type\n"
- " -c --class=CLASS|help Query RR with DNS class\n"
- " --service Resolve service (SRV)\n"
- " --service-address=BOOL Do [not] resolve address for services\n"
- " --service-txt=BOOL Do [not] resolve TXT records for services\n"
- " --cname=BOOL Do [not] follow CNAME redirects\n"
- " --search=BOOL Do [not] use search domains\n"
- " --legend=BOOL Do [not] print column headers and meta information\n"
- " --statistics Show resolver statistics\n"
- " --reset-statistics Reset resolver statistics\n"
- , program_invocation_short_name, program_invocation_short_name);
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " -4 Resolve IPv4 addresses\n"
+ " -6 Resolve IPv6 addresses\n"
+ " -i --interface=INTERFACE Look on interface\n"
+ " -p --protocol=PROTO|help Look via protocol\n"
+ " -t --type=TYPE|help Query RR with DNS type\n"
+ " -c --class=CLASS|help Query RR with DNS class\n"
+ " --service Resolve service (SRV)\n"
+ " --service-address=BOOL Resolve address for services (default: yes)\n"
+ " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
+ " --openpgp Query OpenPGP public key\n"
+ " --tlsa Query TLS public key\n"
+ " --cname=BOOL Follow CNAME redirects (default: yes)\n"
+ " --search=BOOL Use search domains for single-label names\n"
+ " (default: yes)\n"
+ " --raw[=payload|packet] Dump the answer as binary data\n"
+ " --legend=BOOL Print headers and additional info (default: yes)\n"
+ " --statistics Show resolver statistics\n"
+ " --reset-statistics Reset resolver statistics\n"
+ , program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
@@ -961,6 +1112,9 @@ static int parse_argv(int argc, char *argv[]) {
ARG_CNAME,
ARG_SERVICE_ADDRESS,
ARG_SERVICE_TXT,
+ ARG_OPENPGP,
+ ARG_TLSA,
+ ARG_RAW,
ARG_SEARCH,
ARG_STATISTICS,
ARG_RESET_STATISTICS,
@@ -978,6 +1132,9 @@ static int parse_argv(int argc, char *argv[]) {
{ "service", no_argument, NULL, ARG_SERVICE },
{ "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
{ "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
+ { "openpgp", no_argument, NULL, ARG_OPENPGP },
+ { "tlsa", optional_argument, NULL, ARG_TLSA },
+ { "raw", optional_argument, NULL, ARG_RAW },
{ "search", required_argument, NULL, ARG_SEARCH },
{ "statistics", no_argument, NULL, ARG_STATISTICS, },
{ "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
@@ -1087,44 +1244,63 @@ static int parse_argv(int argc, char *argv[]) {
arg_mode = MODE_RESOLVE_SERVICE;
break;
+ case ARG_OPENPGP:
+ arg_mode = MODE_RESOLVE_OPENPGP;
+ break;
+
+ case ARG_TLSA:
+ arg_mode = MODE_RESOLVE_TLSA;
+ arg_service_family = service_family_from_string(optarg);
+ if (arg_service_family < 0) {
+ log_error("Unknown service family \"%s\".", optarg);
+ return -EINVAL;
+ }
+ break;
+
+ case ARG_RAW:
+ if (on_tty()) {
+ log_error("Refusing to write binary data to tty.");
+ return -ENOTTY;
+ }
+
+ if (optarg == NULL || streq(optarg, "payload"))
+ arg_raw = RAW_PAYLOAD;
+ else if (streq(optarg, "packet"))
+ arg_raw = RAW_PACKET;
+ else {
+ log_error("Unknown --raw specifier \"%s\".", optarg);
+ return -EINVAL;
+ }
+
+ arg_legend = false;
+ break;
+
case ARG_CNAME:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --cname= argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_CNAME;
- else
- arg_flags &= ~SD_RESOLVED_NO_CNAME;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
break;
case ARG_SERVICE_ADDRESS:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --service-address= argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_ADDRESS;
- else
- arg_flags &= ~SD_RESOLVED_NO_ADDRESS;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
break;
case ARG_SERVICE_TXT:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --service-txt= argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_TXT;
- else
- arg_flags &= ~SD_RESOLVED_NO_TXT;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
break;
case ARG_SEARCH:
r = parse_boolean(optarg);
if (r < 0)
return log_error_errno(r, "Failed to parse --search argument.");
- if (r == 0)
- arg_flags |= SD_RESOLVED_NO_SEARCH;
- else
- arg_flags &= ~SD_RESOLVED_NO_SEARCH;
+ SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
break;
case ARG_STATISTICS:
@@ -1147,7 +1323,7 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) {
+ if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
log_error("--service and --type= may not be combined.");
return -EINVAL;
}
@@ -1246,6 +1422,42 @@ int main(int argc, char **argv) {
break;
+ case MODE_RESOLVE_OPENPGP:
+ if (argc < optind + 1) {
+ log_error("E-mail address required.");
+ r = -EINVAL;
+ goto finish;
+
+ }
+
+ r = 0;
+ while (optind < argc) {
+ int k;
+
+ k = resolve_openpgp(bus, argv[optind++]);
+ if (k < 0)
+ r = k;
+ }
+ break;
+
+ case MODE_RESOLVE_TLSA:
+ if (argc < optind + 1) {
+ log_error("Domain name required.");
+ r = -EINVAL;
+ goto finish;
+
+ }
+
+ r = 0;
+ while (optind < argc) {
+ int k;
+
+ k = resolve_tlsa(bus, argv[optind++]);
+ if (k < 0)
+ r = k;
+ }
+ break;
+
case MODE_STATISTICS:
if (argc > optind) {
log_error("Too many arguments.");
diff --git a/src/grp-resolve/systemd-resolved/resolved-bus.c b/src/grp-resolve/systemd-resolved/resolved-bus.c
index fc5e6beca0..33f7c61557 100644
--- a/src/grp-resolve/systemd-resolved/resolved-bus.c
+++ b/src/grp-resolve/systemd-resolved/resolved-bus.c
@@ -23,6 +23,7 @@
#include "dns-domain.h"
#include "resolved-bus.h"
#include "resolved-def.h"
+#include "resolved-dns-synthesize.h"
#include "resolved-link-bus.h"
static int reply_query_state(DnsQuery *q) {
@@ -139,6 +140,7 @@ static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifin
static void bus_method_resolve_hostname_complete(DnsQuery *q) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_free_ char *normalized = NULL;
DnsResourceRecord *rr;
unsigned added = 0;
int ifindex, r;
@@ -186,7 +188,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
if (!canonical)
canonical = dns_resource_record_ref(rr);
- added ++;
+ added++;
}
if (added <= 0) {
@@ -198,11 +200,17 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {
if (r < 0)
goto finish;
+ /* The key names are not necessarily normalized, make sure that they are when we return them to our bus
+ * clients. */
+ r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+ if (r < 0)
+ goto finish;
+
/* Return the precise spelling and uppercasing and CNAME target reported by the server */
assert(canonical);
r = sd_bus_message_append(
reply, "st",
- DNS_RESOURCE_KEY_NAME(canonical->key),
+ normalized,
SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));
if (r < 0)
goto finish;
@@ -233,6 +241,65 @@ static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus
return 0;
}
+static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname, int family, uint64_t flags) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_free_ char *canonical = NULL;
+ union in_addr_union parsed;
+ int r, ff;
+
+ /* Check if the hostname is actually already an IP address formatted as string. In that case just parse it,
+ * let's not attempt to look it up. */
+
+ r = in_addr_from_string_auto(hostname, &ff, &parsed);
+ if (r < 0) /* not an address */
+ return 0;
+
+ if (family != AF_UNSPEC && ff != family)
+ return sd_bus_reply_method_errorf(m, BUS_ERROR_NO_SUCH_RR, "The specified address is not of the requested family.");
+
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(iiay)");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'r', "iiay");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "ii", ifindex, ff);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_array(reply, 'y', &parsed, FAMILY_ADDRESS_SIZE(ff));
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ /* When an IP address is specified we just return it as canonical name, in order to avoid a DNS
+ * look-up. However, we reformat it to make sure it's in a truly canonical form (i.e. on IPv6 the inner
+ * omissions are always done the same way). */
+ r = in_addr_to_string(ff, &parsed, &canonical);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(reply, "st", canonical,
+ SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true));
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL);
+}
+
static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
Manager *m = userdata;
@@ -254,15 +321,19 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata,
if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
- r = dns_name_is_valid(hostname);
+ r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
if (r < 0)
return r;
- if (r == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
- r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error);
+ r = parse_as_address(message, ifindex, hostname, family, flags);
+ if (r != 0)
+ return r;
+
+ r = dns_name_is_valid(hostname);
if (r < 0)
return r;
+ if (r == 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname);
r = dns_question_new_address(&question_utf8, family, hostname, false);
if (r < 0)
@@ -331,24 +402,31 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {
question = dns_query_question_for_protocol(q, q->answer_protocol);
DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) {
+ _cleanup_free_ char *normalized = NULL;
+
r = dns_question_matches_rr(question, rr, NULL);
if (r < 0)
goto finish;
if (r == 0)
continue;
- r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name);
+ r = dns_name_normalize(rr->ptr.name, &normalized);
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_append(reply, "(is)", ifindex, normalized);
if (r < 0)
goto finish;
- added ++;
+ added++;
}
if (added <= 0) {
_cleanup_free_ char *ip = NULL;
- in_addr_to_string(q->request_family, &q->request_address, &ip);
- r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip));
+ (void) in_addr_to_string(q->request_family, &q->request_address, &ip);
+ r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR,
+ "Address '%s' does not have any RR of requested type", strnull(ip));
goto finish;
}
@@ -510,7 +588,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {
if (r < 0)
goto finish;
- added ++;
+ added++;
}
if (added <= 0) {
@@ -607,6 +685,7 @@ fail:
static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL;
+ _cleanup_free_ char *normalized = NULL;
DnsQuery *aux;
int r;
@@ -663,10 +742,14 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
if (r < 0)
return r;
+ r = dns_name_normalize(rr->srv.name, &normalized);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_append(
reply,
"qqqs",
- rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name);
+ rr->srv.priority, rr->srv.weight, rr->srv.port, normalized);
if (r < 0)
return r;
@@ -712,9 +795,17 @@ static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr)
if (r < 0)
return r;
+ if (canonical) {
+ normalized = mfree(normalized);
+
+ r = dns_name_normalize(dns_resource_key_name(canonical->key), &normalized);
+ if (r < 0)
+ return r;
+ }
+
/* Note that above we appended the hostname as encoded in the
* SRV, and here the canonical hostname this maps to. */
- r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name);
+ r = sd_bus_message_append(reply, "s", normalized);
if (r < 0)
return r;
@@ -869,7 +960,7 @@ static void resolve_service_all_complete(DnsQuery *q) {
goto finish;
assert(canonical);
- r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain);
+ r = dns_service_split(dns_resource_key_name(canonical->key), &name, &type, &domain);
if (r < 0)
goto finish;
@@ -1004,9 +1095,9 @@ static void bus_method_resolve_service_complete(DnsQuery *q) {
}
if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) {
- q->block_all_complete ++;
+ q->block_all_complete++;
r = resolve_service_hostname(q, rr, ifindex);
- q->block_all_complete --;
+ q->block_all_complete--;
if (r < 0)
goto finish;
@@ -1047,7 +1138,6 @@ finish:
static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL;
const char *name, *type, *domain;
- _cleanup_free_ char *n = NULL;
Manager *m = userdata;
int family, ifindex;
uint64_t flags;
@@ -1198,7 +1288,7 @@ static int bus_property_get_dns_servers(
return sd_bus_message_close_container(reply);
}
-static int bus_property_get_search_domains(
+static int bus_property_get_domains(
sd_bus *bus,
const char *path,
const char *interface,
@@ -1396,8 +1486,8 @@ static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userda
return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
}
-static int bus_method_set_link_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return call_link_method(userdata, message, bus_link_method_set_search_domains, error);
+static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return call_link_method(userdata, message, bus_link_method_set_domains, error);
}
static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1449,7 +1539,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0),
SD_BUS_PROPERTY("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0),
- SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0),
+ SD_BUS_PROPERTY("Domains", "a(isb)", bus_property_get_domains, 0, 0),
SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0),
SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0),
SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0),
@@ -1462,7 +1552,7 @@ static const sd_bus_vtable resolve_vtable[] = {
SD_BUS_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0),
SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0),
- SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_search_domains, 0),
+ SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, 0),
SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0),
SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0),
SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0),
diff --git a/src/grp-resolve/systemd-resolved/resolved-conf.c b/src/grp-resolve/systemd-resolved/resolved-conf.c
index bb93fbfda2..990dc03b60 100644
--- a/src/grp-resolve/systemd-resolved/resolved-conf.c
+++ b/src/grp-resolve/systemd-resolved/resolved-conf.c
@@ -59,7 +59,7 @@ int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, con
assert(m);
assert(string);
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&string, &word, NULL, 0);
@@ -114,7 +114,7 @@ int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
assert(m);
assert(string);
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES);
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-answer.c b/src/grp-resolve/systemd-resolved/resolved-dns-answer.c
index 7eb303ab95..0dadf8b1dd 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-answer.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-answer.c
@@ -330,7 +330,7 @@ int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) {
if (rr->key->type != DNS_TYPE_NSEC3)
continue;
- p = DNS_RESOURCE_KEY_NAME(rr->key);
+ p = dns_resource_key_name(rr->key);
r = dns_name_parent(&p);
if (r < 0)
return r;
@@ -363,7 +363,7 @@ int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceReco
if (r > 0) {
if (soa) {
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(soa->key));
+ r = dns_name_endswith(dns_resource_key_name(rr->key), dns_resource_key_name(soa->key));
if (r < 0)
return r;
if (r > 0)
@@ -538,7 +538,7 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) {
dns_resource_record_unref((*a)->items[i].rr);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
- (*a)->n_rrs --;
+ (*a)->n_rrs--;
continue;
} else
@@ -624,7 +624,7 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) {
dns_resource_record_unref((*a)->items[i].rr);
memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1));
- (*a)->n_rrs --;
+ (*a)->n_rrs--;
continue;
} else
@@ -757,7 +757,7 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free) {
assert(a);
/* Tries to extend the DnsAnswer object. And if that's not
- * possibly, since we are not the sole owner, then allocate a
+ * possible, since we are not the sole owner, then allocate a
* new, appropriately sized one. Either way, after this call
* the object will only have a single reference, and has room
* for at least the specified number of RRs. */
@@ -840,13 +840,13 @@ bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
if (rr->key->class != cname->key->class)
continue;
- r = dns_name_change_suffix(cname->cname.name, rr->dname.name, DNS_RESOURCE_KEY_NAME(rr->key), &n);
+ r = dns_name_change_suffix(cname->cname.name, rr->dname.name, dns_resource_key_name(rr->key), &n);
if (r < 0)
return r;
if (r == 0)
continue;
- r = dns_name_equal(n, DNS_RESOURCE_KEY_NAME(cname->key));
+ r = dns_name_equal(n, dns_resource_key_name(cname->key));
if (r < 0)
return r;
if (r > 0)
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-answer.h b/src/grp-resolve/systemd-resolved/resolved-dns-answer.h
index 8f9c15eab4..0679c610f5 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-answer.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-answer.h
@@ -30,7 +30,7 @@ typedef struct DnsAnswerItem DnsAnswerItem;
* can qualify A and AAAA RRs referring to a local link with the
* right ifindex.
*
- * Note that we usually encode the the empty DnsAnswer object as a simple NULL. */
+ * Note that we usually encode the empty DnsAnswer object as a simple NULL. */
typedef enum DnsAnswerFlags {
DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-cache.c b/src/grp-resolve/systemd-resolved/resolved-dns-cache.c
index 9bcc71724e..77c42d7aad 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-cache.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-cache.c
@@ -17,6 +17,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <net/if.h>
+
+#include "af-list.h"
#include "alloc-util.h"
#include "dns-domain.h"
#include "resolved-dns-answer.h"
@@ -180,6 +183,7 @@ void dns_cache_prune(DnsCache *c) {
for (;;) {
DnsCacheItem *i;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
i = prioq_peek(c->by_expiry);
if (!i)
@@ -192,8 +196,12 @@ void dns_cache_prune(DnsCache *c) {
break;
/* Depending whether this is an mDNS shared entry
- * either remove only this one RR or the whole
- * RRset */
+ * either remove only this one RR or the whole RRset */
+ log_debug("Removing %scache entry for %s (expired "USEC_FMT"s ago)",
+ i->shared_owner ? "shared " : "",
+ dns_resource_key_to_string(i->key, key_str, sizeof key_str),
+ (t - i->until) / USEC_PER_SEC);
+
if (i->shared_owner)
dns_cache_item_unlink_and_free(c, i);
else {
@@ -375,8 +383,8 @@ static int dns_cache_put_positive(
const union in_addr_union *owner_address) {
_cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL;
- _cleanup_free_ char *key_str = NULL;
DnsCacheItem *existing;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX], ifname[IF_NAMESIZE];
int r, k;
assert(c);
@@ -392,18 +400,9 @@ static int dns_cache_put_positive(
/* New TTL is 0? Delete this specific entry... */
if (rr->ttl <= 0) {
k = dns_cache_remove_by_rr(c, rr);
-
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(rr->key, &key_str);
- if (r < 0)
- return r;
-
- if (k > 0)
- log_debug("Removed zero TTL entry from cache: %s", key_str);
- else
- log_debug("Not caching zero TTL cache entry: %s", key_str);
- }
-
+ log_debug("%s: %s",
+ k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry",
+ dns_resource_key_to_string(rr->key, key_str, sizeof key_str));
return 0;
}
@@ -450,11 +449,18 @@ static int dns_cache_put_positive(
return r;
if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(i->key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Added positive cache entry for %s", key_str);
+ _cleanup_free_ char *t = NULL;
+
+ (void) in_addr_to_string(i->owner_family, &i->owner_address, &t);
+
+ log_debug("Added positive %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s",
+ i->authenticated ? "authenticated" : "unauthenticated",
+ i->shared_owner ? " shared" : "",
+ dns_resource_key_to_string(i->key, key_str, sizeof key_str),
+ (i->until - timestamp) / USEC_PER_SEC,
+ i->ifindex == 0 ? "*" : strna(if_indextoname(i->ifindex, ifname)),
+ af_to_name_short(i->owner_family),
+ strna(t));
}
i = NULL;
@@ -473,7 +479,7 @@ static int dns_cache_put_negative(
const union in_addr_union *owner_address) {
_cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL;
- _cleanup_free_ char *key_str = NULL;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
int r;
assert(c);
@@ -490,14 +496,8 @@ static int dns_cache_put_negative(
return 0;
if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) {
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s", key_str);
- }
-
+ log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
return 0;
}
@@ -524,7 +524,7 @@ static int dns_cache_put_negative(
if (i->type == DNS_CACHE_NXDOMAIN) {
/* NXDOMAIN entries should apply equally to all types, so we use ANY as
* a pseudo type for this purpose here. */
- i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(key));
+ i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, dns_resource_key_name(key));
if (!i->key)
return -ENOMEM;
@@ -542,13 +542,10 @@ static int dns_cache_put_negative(
if (r < 0)
return r;
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(i->key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Added %s cache entry for %s", i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", key_str);
- }
+ log_debug("Added %s cache entry for %s "USEC_FMT"s",
+ i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN",
+ dns_resource_key_to_string(i->key, key_str, sizeof key_str),
+ (i->until - timestamp) / USEC_PER_SEC);
i = NULL;
return 0;
@@ -628,16 +625,10 @@ int dns_cache_put(
dns_cache_remove_previous(c, key, answer);
if (dns_answer_size(answer) <= 0) {
- if (log_get_max_level() >= LOG_DEBUG) {
- _cleanup_free_ char *key_str = NULL;
-
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Not caching negative entry without a SOA record: %s", key_str);
- }
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
+ log_debug("Not caching negative entry without a SOA record: %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
return 0;
}
@@ -649,7 +640,7 @@ int dns_cache_put(
cache_keys = dns_answer_size(answer);
if (key)
- cache_keys ++;
+ cache_keys++;
/* Make some space for our new entries */
dns_cache_make_space(c, cache_keys);
@@ -759,7 +750,7 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D
if (i)
return i;
- n = DNS_RESOURCE_KEY_NAME(k);
+ n = dns_resource_key_name(k);
/* Check if we have an NXDOMAIN cache item for the name, notice that we use
* the pseudo-type ANY for NXDOMAIN cache items. */
@@ -801,10 +792,10 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D
int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret, bool *authenticated) {
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
unsigned n = 0;
int r;
bool nxdomain = false;
- _cleanup_free_ char *key_str = NULL;
DnsCacheItem *j, *first, *nsec = NULL;
bool have_authenticated = false, have_non_authenticated = false;
@@ -814,19 +805,12 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
assert(ret);
assert(authenticated);
- if (key->type == DNS_TYPE_ANY ||
- key->class == DNS_CLASS_ANY) {
-
+ if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) {
/* If we have ANY lookups we don't use the cache, so
* that the caller refreshes via the network. */
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Ignoring cache for ANY lookup: %s", key_str);
- }
+ log_debug("Ignoring cache for ANY lookup: %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
c->n_miss++;
@@ -839,13 +823,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
if (!first) {
/* If one question cannot be answered we need to refresh */
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("Cache miss for %s", key_str);
- }
+ log_debug("Cache miss for %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
c->n_miss++;
@@ -873,13 +852,8 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
/* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC RRs from
* the lower-zone of a zone cut, but the DS RRs are on the upper zone. */
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("NSEC NODATA cache hit for %s", key_str);
- }
+ log_debug("NSEC NODATA cache hit for %s",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
/* We only found an NSEC record that matches our name.
* If it says the type doesn't exist report
@@ -900,16 +874,10 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
return 0;
}
- if (log_get_max_level() >= LOG_DEBUG) {
- r = dns_resource_key_to_string(key, &key_str);
- if (r < 0)
- return r;
-
- log_debug("%s cache hit for %s",
- n > 0 ? "Positive" :
- nxdomain ? "NXDOMAIN" : "NODATA",
- key_str);
- }
+ log_debug("%s cache hit for %s",
+ n > 0 ? "Positive" :
+ nxdomain ? "NXDOMAIN" : "NODATA",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
if (n <= 0) {
c->n_hit++;
@@ -1019,7 +987,7 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
if (r < 0)
return r;
- ancount ++;
+ ancount++;
}
}
@@ -1031,7 +999,6 @@ int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) {
void dns_cache_dump(DnsCache *cache, FILE *f) {
Iterator iterator;
DnsCacheItem *i;
- int r;
if (!cache)
return;
@@ -1057,14 +1024,9 @@ void dns_cache_dump(DnsCache *cache, FILE *f) {
fputs(t, f);
fputc('\n', f);
} else {
- _cleanup_free_ char *z = NULL;
- r = dns_resource_key_to_string(j->key, &z);
- if (r < 0) {
- log_oom();
- continue;
- }
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
- fputs(z, f);
+ fputs(dns_resource_key_to_string(j->key, key_str, sizeof key_str), f);
fputs(" -- ", f);
fputs(j->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", f);
fputc('\n', f);
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c b/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c
index 7123d2d3a8..a54aed3a63 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-dnssec.c
@@ -23,6 +23,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
+#include "gcrypt-util.h"
#include "hexdecoct.h"
#include "resolved-dns-dnssec.h"
#include "resolved-dns-packet.h"
@@ -126,19 +127,6 @@ int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) {
#ifdef HAVE_GCRYPT
-static void initialize_libgcrypt(void) {
- const char *p;
-
- if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
- return;
-
- p = gcry_check_version("1.4.5");
- assert(p);
-
- gcry_control(GCRYCTL_DISABLE_SECMEM);
- gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
-}
-
static int rr_compare(const void *a, const void *b) {
DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b;
size_t m;
@@ -479,7 +467,7 @@ static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) {
if (rrsig->rrsig.inception > rrsig->rrsig.expiration)
return -EINVAL;
- name = DNS_RESOURCE_KEY_NAME(rrsig->key);
+ name = dns_resource_key_name(rrsig->key);
n_key_labels = dns_name_count_labels(name);
if (n_key_labels < 0)
@@ -635,9 +623,9 @@ int dnssec_verify_rrset(
assert(rrsig->key->type == DNS_TYPE_RRSIG);
assert(dnskey->key->type == DNS_TYPE_DNSKEY);
- /* Verifies the the RRSet matching the specified "key" in "a",
+ /* Verifies that the RRSet matches the specified "key" in "a",
* using the signature "rrsig" and the key "dnskey". It's
- * assumed the RRSIG and DNSKEY match. */
+ * assumed that RRSIG and DNSKEY match. */
md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm);
if (md_algorithm == -EOPNOTSUPP) {
@@ -663,7 +651,7 @@ int dnssec_verify_rrset(
return 0;
}
- name = DNS_RESOURCE_KEY_NAME(key);
+ name = dns_resource_key_name(key);
/* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */
if (dns_type_apex_only(rrsig->rrsig.type_covered)) {
@@ -737,7 +725,7 @@ int dnssec_verify_rrset(
qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare);
/* OK, the RRs are now in canonical order. Let's calculate the digest */
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
hash_size = gcry_md_get_algo_dlen(md_algorithm);
assert(hash_size > 0);
@@ -863,7 +851,7 @@ int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnske
if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag)
return 0;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer);
+ return dns_name_equal(dns_resource_key_name(dnskey->key), rrsig->rrsig.signer);
}
int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) {
@@ -879,7 +867,7 @@ int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig)
if (rrsig->rrsig.type_covered != key->type)
return 0;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key));
+ return dns_name_equal(dns_resource_key_name(rrsig->key), dns_resource_key_name(key));
}
int dnssec_verify_rrset_search(
@@ -1070,7 +1058,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag)
return 0;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type);
if (md_algorithm < 0)
@@ -1082,7 +1070,7 @@ int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds,
if (ds->ds.digest_size != hash_size)
return 0;
- r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name));
+ r = dnssec_canonicalize(dns_resource_key_name(dnskey->key), owner_name, sizeof(owner_name));
if (r < 0)
return r;
@@ -1132,7 +1120,7 @@ int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *vali
if (ds->key->class != dnskey->key->class)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key));
+ r = dns_name_equal(dns_resource_key_name(dnskey->key), dns_resource_key_name(ds->key));
if (r < 0)
return r;
if (r == 0)
@@ -1189,7 +1177,7 @@ int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) {
if (algorithm < 0)
return algorithm;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
hash_size = gcry_md_get_algo_dlen(algorithm);
assert(hash_size > 0);
@@ -1284,14 +1272,14 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) {
if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0)
return 0;
- a = DNS_RESOURCE_KEY_NAME(rr->key);
+ a = dns_resource_key_name(rr->key);
r = dns_name_parent(&a); /* strip off hash */
if (r < 0)
return r;
if (r == 0)
return 0;
- b = DNS_RESOURCE_KEY_NAME(nsec3->key);
+ b = dns_resource_key_name(nsec3->key);
r = dns_name_parent(&b); /* strip off hash */
if (r < 0)
return r;
@@ -1365,7 +1353,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
* any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3
* records from a given zone in a response must use the same
* parameters. */
- zone = DNS_RESOURCE_KEY_NAME(key);
+ zone = dns_resource_key_name(key);
for (;;) {
DNS_ANSWER_FOREACH_FLAGS(zone_rr, flags, answer) {
r = nsec3_is_good(zone_rr, NULL);
@@ -1374,7 +1362,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
if (r == 0)
continue;
- r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr->key), 1, zone);
+ r = dns_name_equal_skip(dns_resource_key_name(zone_rr->key), 1, zone);
if (r < 0)
return r;
if (r > 0)
@@ -1394,7 +1382,7 @@ static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecR
found_zone:
/* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */
- p = DNS_RESOURCE_KEY_NAME(key);
+ p = dns_resource_key_name(key);
for (;;) {
_cleanup_free_ char *hashed_domain = NULL;
@@ -1417,7 +1405,7 @@ found_zone:
if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr->key), hashed_domain);
+ r = dns_name_equal(dns_resource_key_name(enclosure_rr->key), hashed_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1516,7 +1504,7 @@ found_closest_encloser:
if (r < 0)
return r;
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain);
+ r = dns_name_between(dns_resource_key_name(rr->key), next_closer_domain, next_hashed_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1528,7 +1516,7 @@ found_closest_encloser:
no_closer = true;
}
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain);
+ r = dns_name_equal(dns_resource_key_name(rr->key), wildcard_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1537,7 +1525,7 @@ found_closest_encloser:
wildcard_rr = rr;
}
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain, next_hashed_domain);
+ r = dns_name_between(dns_resource_key_name(rr->key), wildcard_domain, next_hashed_domain);
if (r < 0)
return r;
if (r > 0) {
@@ -1616,7 +1604,7 @@ static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) {
if (rr->n_skip_labels_source != 1)
return 0;
- n = DNS_RESOURCE_KEY_NAME(rr->key);
+ n = dns_resource_key_name(rr->key);
r = dns_label_unescape(&n, label, sizeof(label));
if (r <= 0)
return r;
@@ -1655,7 +1643,7 @@ static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) {
return r;
/* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */
- r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
+ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
if (r < 0)
return r;
@@ -1674,7 +1662,7 @@ static int dnssec_nsec_from_parent_zone(DnsResourceRecord *rr, const char *name)
if (r <= 0)
return r;
- r = dns_name_equal(name, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(name, dns_resource_key_name(rr->key));
if (r <= 0)
return r;
@@ -1697,7 +1685,7 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
/* Checks whether the "Next Closer" is witin the space covered by the specified RR. */
- r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
+ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
if (r < 0)
return r;
@@ -1718,7 +1706,7 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
/* p is now the "Next Closer". */
- return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), p, rr->nsec.next_domain_name);
+ return dns_name_between(dns_resource_key_name(rr->key), p, rr->nsec.next_domain_name);
}
static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) {
@@ -1737,7 +1725,7 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
* NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either...
*/
- r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
+ r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
if (r < 0)
return r;
@@ -1746,8 +1734,8 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
if (r <= 0)
return r;
- wc = strjoina("*.", common_suffix, NULL);
- return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wc, rr->nsec.next_domain_name);
+ wc = strjoina("*.", common_suffix);
+ return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
}
int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
@@ -1762,7 +1750,7 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
/* Look for any NSEC/NSEC3 RRs that say something about the specified key. */
- name = DNS_RESOURCE_KEY_NAME(key);
+ name = dns_resource_key_name(key);
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
@@ -1782,7 +1770,7 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
continue;
/* Check if this is a direct match. If so, we have encountered a NODATA case */
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), name);
+ r = dns_name_equal(dns_resource_key_name(rr->key), name);
if (r < 0)
return r;
if (r == 0) {
@@ -1912,7 +1900,7 @@ static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const cha
if (r == 0)
continue;
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), name, rr->nsec.next_domain_name);
+ r = dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name);
if (r < 0)
return r;
@@ -1955,7 +1943,7 @@ static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const cha
if (r < 0)
return r;
- r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), hashed_domain, next_hashed_domain);
+ r = dns_name_between(dns_resource_key_name(rr->key), hashed_domain, next_hashed_domain);
if (r < 0)
return r;
@@ -1989,7 +1977,7 @@ static int dnssec_test_positive_wildcard_nsec3(
/* Run a positive NSEC3 wildcard proof. Specifically:
*
- * A proof that the the "next closer" of the generating wildcard does not exist.
+ * A proof that the "next closer" of the generating wildcard does not exist.
*
* Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for
* empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-packet.c b/src/grp-resolve/systemd-resolved/resolved-dns-packet.c
index c940dd8929..b7907bb511 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-packet.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-packet.c
@@ -28,6 +28,19 @@
#define EDNS0_OPT_DO (1<<15)
+typedef struct DnsPacketRewinder {
+ DnsPacket *packet;
+ size_t saved_rindex;
+} DnsPacketRewinder;
+
+static void rewind_dns_packet(DnsPacketRewinder *rewinder) {
+ if (rewinder->packet)
+ dns_packet_rewind(rewinder->packet, rewinder->saved_rindex);
+}
+
+#define INIT_REWINDER(rewinder, p) do { rewinder.packet = p; rewinder.saved_rindex = p->rindex; } while (0)
+#define CANCEL_REWINDER(rewinder) do { rewinder.packet = NULL; } while (0)
+
int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
DnsPacket *p;
size_t a;
@@ -431,8 +444,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_
((uint8_t*) d)[0] = (uint8_t) size;
- if (size > 0)
- memcpy(((uint8_t*) d) + 1, s, size);
+ memcpy_safe(((uint8_t*) d) + 1, s, size);
return 0;
}
@@ -565,7 +577,7 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start)
saved_size = p->size;
- r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, true, NULL);
+ r = dns_packet_append_name(p, dns_resource_key_name(k), true, true, NULL);
if (r < 0)
goto fail;
@@ -1072,6 +1084,18 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star
r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL);
break;
+ case DNS_TYPE_CAA:
+ r = dns_packet_append_uint8(p, rr->caa.flags, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_string(p, rr->caa.tag, NULL);
+ if (r < 0)
+ goto fail;
+
+ r = dns_packet_append_blob(p, rr->caa.value, rr->caa.value_size, NULL);
+ break;
+
case DNS_TYPE_OPT:
case DNS_TYPE_OPENPGPKEY:
case _DNS_TYPE_INVALID: /* unparseable */
@@ -1230,80 +1254,67 @@ int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
}
int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
const void *d;
char *t;
uint8_t c;
int r;
assert(p);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read(p, c, &d, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (memchr(d, 0, c)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (memchr(d, 0, c))
+ return -EBADMSG;
t = strndup(d, c);
- if (!t) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!t)
+ return -ENOMEM;
if (!utf8_is_valid(t)) {
free(t);
- r = -EBADMSG;
- goto fail;
+ return -EBADMSG;
}
*ret = t;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) {
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
uint8_t c;
int r;
assert(p);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read(p, c, ret, NULL);
if (r < 0)
- goto fail;
+ return r;
if (size)
*size = c;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
int dns_packet_read_name(
@@ -1312,7 +1323,8 @@ int dns_packet_read_name(
bool allow_compression,
size_t *start) {
- size_t saved_rindex, after_rindex = 0, jump_barrier;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
+ size_t after_rindex = 0, jump_barrier;
_cleanup_free_ char *ret = NULL;
size_t n = 0, allocated = 0;
bool first = true;
@@ -1320,19 +1332,18 @@ int dns_packet_read_name(
assert(p);
assert(_ret);
+ INIT_REWINDER(rewinder, p);
+ jump_barrier = p->rindex;
if (p->refuse_compression)
allow_compression = false;
- saved_rindex = p->rindex;
- jump_barrier = p->rindex;
-
for (;;) {
uint8_t c, d;
r = dns_packet_read_uint8(p, &c, NULL);
if (r < 0)
- goto fail;
+ return r;
if (c == 0)
/* End of name */
@@ -1343,12 +1354,10 @@ int dns_packet_read_name(
/* Literal label */
r = dns_packet_read(p, c, (const void**) &label, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
+ return -ENOMEM;
if (first)
first = false;
@@ -1357,7 +1366,7 @@ int dns_packet_read_name(
r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX);
if (r < 0)
- goto fail;
+ return r;
n += r;
continue;
@@ -1367,13 +1376,11 @@ int dns_packet_read_name(
/* Pointer */
r = dns_packet_read_uint8(p, &d, NULL);
if (r < 0)
- goto fail;
+ return r;
ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
- if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) {
- r = -EBADMSG;
- goto fail;
- }
+ if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier)
+ return -EBADMSG;
if (after_rindex == 0)
after_rindex = p->rindex;
@@ -1381,16 +1388,12 @@ int dns_packet_read_name(
/* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
jump_barrier = ptr;
p->rindex = ptr;
- } else {
- r = -EBADMSG;
- goto fail;
- }
+ } else
+ return -EBADMSG;
}
- if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!GREEDY_REALLOC(ret, allocated, n + 1))
+ return -ENOMEM;
ret[n] = 0;
@@ -1401,13 +1404,10 @@ int dns_packet_read_name(
ret = NULL;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *start) {
@@ -1417,32 +1417,31 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
uint8_t bit = 0;
unsigned i;
bool found = false;
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
int r;
assert(p);
assert(types);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = bitmap_ensure_allocated(types);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &window, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &length, NULL);
if (r < 0)
- goto fail;
+ return r;
if (length == 0 || length > 32)
return -EBADMSG;
r = dns_packet_read(p, length, (const void **)&bitmap, NULL);
if (r < 0)
- goto fail;
+ return r;
for (i = 0; i < length; i++) {
uint8_t bitmask = 1 << 7;
@@ -1467,10 +1466,10 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
r = bitmap_set(*types, n);
if (r < 0)
- goto fail;
+ return r;
}
- bit ++;
+ bit++;
bitmask >>= 1;
}
}
@@ -1479,70 +1478,61 @@ static int dns_packet_read_type_window(DnsPacket *p, Bitmap **types, size_t *sta
return -EBADMSG;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t size, size_t *start) {
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
int r;
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
- while (p->rindex < saved_rindex + size) {
+ while (p->rindex < rewinder.saved_rindex + size) {
r = dns_packet_read_type_window(p, types, NULL);
if (r < 0)
- goto fail;
+ return r;
/* don't read past end of current RR */
- if (p->rindex > saved_rindex + size) {
- r = -EBADMSG;
- goto fail;
- }
+ if (p->rindex > rewinder.saved_rindex + size)
+ return -EBADMSG;
}
- if (p->rindex != saved_rindex + size) {
- r = -EBADMSG;
- goto fail;
- }
+ if (p->rindex != rewinder.saved_rindex + size)
+ return -EBADMSG;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) {
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
_cleanup_free_ char *name = NULL;
bool cache_flush = false;
uint16_t class, type;
DnsResourceKey *key;
- size_t saved_rindex;
int r;
assert(p);
assert(ret);
-
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_name(p, &name, true, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &type, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &class, NULL);
if (r < 0)
- goto fail;
+ return r;
if (p->protocol == DNS_PROTOCOL_MDNS) {
/* See RFC6762, Section 10.2 */
@@ -1554,10 +1544,8 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus
}
key = dns_resource_key_new_consume(class, type, name);
- if (!key) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!key)
+ return -ENOMEM;
name = NULL;
*ret = key;
@@ -1565,12 +1553,10 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static bool loc_size_ok(uint8_t size) {
@@ -1582,7 +1568,8 @@ static bool loc_size_ok(uint8_t size) {
int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
- size_t saved_rindex, offset;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder;
+ size_t offset;
uint16_t rdlength;
bool cache_flush;
int r;
@@ -1590,27 +1577,22 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
assert(p);
assert(ret);
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!dns_class_is_valid_rr(key->class)||
- !dns_type_is_valid_rr(key->type)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!dns_class_is_valid_rr(key->class) || !dns_type_is_valid_rr(key->type))
+ return -EBADMSG;
rr = dns_resource_record_new(key);
- if (!rr) {
- r = -ENOMEM;
- goto fail;
- }
+ if (!rr)
+ return -ENOMEM;
r = dns_packet_read_uint32(p, &rr->ttl, NULL);
if (r < 0)
- goto fail;
+ return r;
/* RFC 2181, Section 8, suggests to
* treat a TTL with the MSB set as a zero TTL. */
@@ -1619,12 +1601,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_uint16(p, &rdlength, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (p->rindex + rdlength > p->size) {
- r = -EBADMSG;
- goto fail;
- }
+ if (p->rindex + rdlength > p->size)
+ return -EBADMSG;
offset = p->rindex;
@@ -1633,13 +1613,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_SRV:
r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
break;
@@ -1653,7 +1633,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_HINFO:
r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
break;
@@ -1709,27 +1689,27 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_SOA:
r = dns_packet_read_name(p, &rr->soa.mname, true, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->soa.rname, true, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
break;
@@ -1737,7 +1717,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_MX:
r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL);
break;
@@ -1748,49 +1728,43 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_uint8(p, &t, &pos);
if (r < 0)
- goto fail;
+ return r;
if (t == 0) {
rr->loc.version = t;
r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!loc_size_ok(rr->loc.size)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!loc_size_ok(rr->loc.size))
+ return -EBADMSG;
r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!loc_size_ok(rr->loc.horiz_pre)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!loc_size_ok(rr->loc.horiz_pre))
+ return -EBADMSG;
r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (!loc_size_ok(rr->loc.vert_pre)) {
- r = -EBADMSG;
- goto fail;
- }
+ if (!loc_size_ok(rr->loc.vert_pre))
+ return -EBADMSG;
r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
if (r < 0)
- goto fail;
+ return r;
break;
} else {
@@ -1803,122 +1777,114 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_DS:
r = dns_packet_read_uint16(p, &rr->ds.key_tag, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->ds.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->ds.digest_type, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 4,
&rr->ds.digest, &rr->ds.digest_size,
NULL);
if (r < 0)
- goto fail;
+ return r;
- if (rr->ds.digest_size <= 0) {
+ if (rr->ds.digest_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
case DNS_TYPE_SSHFP:
r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 2,
&rr->sshfp.fingerprint, &rr->sshfp.fingerprint_size,
NULL);
- if (rr->sshfp.fingerprint_size <= 0) {
+ if (rr->sshfp.fingerprint_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
case DNS_TYPE_DNSKEY:
r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 4,
&rr->dnskey.key, &rr->dnskey.key_size,
NULL);
- if (rr->dnskey.key_size <= 0) {
+ if (rr->dnskey.key_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
case DNS_TYPE_RRSIG:
r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, offset + rdlength - p->rindex,
&rr->rrsig.signature, &rr->rrsig.signature_size,
NULL);
- if (rr->rrsig.signature_size <= 0) {
+ if (rr->rrsig.signature_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
break;
@@ -1933,11 +1899,9 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_type_windows(p, &rr->nsec.types, offset + rdlength - p->rindex, NULL);
- if (r < 0)
- goto fail;
/* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself
* is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records
@@ -1950,41 +1914,39 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
r = dns_packet_read_uint8(p, &rr->nsec3.algorithm, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->nsec3.flags, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint16(p, &rr->nsec3.iterations, NULL);
if (r < 0)
- goto fail;
+ return r;
/* this may be zero */
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, size, &rr->nsec3.salt, &rr->nsec3.salt_size, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &size, NULL);
if (r < 0)
- goto fail;
+ return r;
- if (size <= 0) {
- r = -EBADMSG;
- goto fail;
- }
+ if (size <= 0)
+ return -EBADMSG;
- r = dns_packet_read_memdup(p, size, &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size, NULL);
+ r = dns_packet_read_memdup(p, size,
+ &rr->nsec3.next_hashed_name, &rr->nsec3.next_hashed_name_size,
+ NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_type_windows(p, &rr->nsec3.types, offset + rdlength - p->rindex, NULL);
- if (r < 0)
- goto fail;
/* empty non-terminals can have NSEC3 records, so empty bitmaps are allowed */
@@ -1994,25 +1956,39 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
case DNS_TYPE_TLSA:
r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL);
if (r < 0)
- goto fail;
+ return r;
r = dns_packet_read_memdup(p, rdlength - 3,
&rr->tlsa.data, &rr->tlsa.data_size,
NULL);
- if (rr->tlsa.data_size <= 0) {
+
+ if (rr->tlsa.data_size <= 0)
/* the accepted size depends on the algorithm, but for now
just ensure that the value is greater than zero */
- r = -EBADMSG;
- goto fail;
- }
+ return -EBADMSG;
+
+ break;
+
+ case DNS_TYPE_CAA:
+ r = dns_packet_read_uint8(p, &rr->caa.flags, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_string(p, &rr->caa.tag, NULL);
+ if (r < 0)
+ return r;
+
+ r = dns_packet_read_memdup(p,
+ rdlength + offset - p->rindex,
+ &rr->caa.value, &rr->caa.value_size, NULL);
break;
@@ -2021,16 +1997,13 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
default:
unparseable:
r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL);
- if (r < 0)
- goto fail;
+
break;
}
if (r < 0)
- goto fail;
- if (p->rindex != offset + rdlength) {
- r = -EBADMSG;
- goto fail;
- }
+ return r;
+ if (p->rindex != offset + rdlength)
+ return -EBADMSG;
*ret = rr;
rr = NULL;
@@ -2038,12 +2011,10 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl
if (ret_cache_flush)
*ret_cache_flush = cache_flush;
if (start)
- *start = saved_rindex;
+ *start = rewinder.saved_rindex;
+ CANCEL_REWINDER(rewinder);
return 0;
-fail:
- dns_packet_rewind(p, saved_rindex);
- return r;
}
static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
@@ -2091,23 +2062,21 @@ static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) {
int dns_packet_extract(DnsPacket *p) {
_cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
_cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- size_t saved_rindex;
+ _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {};
unsigned n, i;
int r;
if (p->extracted)
return 0;
- saved_rindex = p->rindex;
+ INIT_REWINDER(rewinder, p);
dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
n = DNS_PACKET_QDCOUNT(p);
if (n > 0) {
question = dns_question_new(n);
- if (!question) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!question)
+ return -ENOMEM;
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
@@ -2115,21 +2084,17 @@ int dns_packet_extract(DnsPacket *p) {
r = dns_packet_read_key(p, &key, &cache_flush, NULL);
if (r < 0)
- goto finish;
+ return r;
- if (cache_flush) {
- r = -EBADMSG;
- goto finish;
- }
+ if (cache_flush)
+ return -EBADMSG;
- if (!dns_type_is_valid_query(key->type)) {
- r = -EBADMSG;
- goto finish;
- }
+ if (!dns_type_is_valid_query(key->type))
+ return -EBADMSG;
r = dns_question_add(question, key);
if (r < 0)
- goto finish;
+ return r;
}
}
@@ -2139,10 +2104,8 @@ int dns_packet_extract(DnsPacket *p) {
bool bad_opt = false;
answer = dns_answer_new(n);
- if (!answer) {
- r = -ENOMEM;
- goto finish;
- }
+ if (!answer)
+ return -ENOMEM;
for (i = 0; i < n; i++) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
@@ -2150,7 +2113,7 @@ int dns_packet_extract(DnsPacket *p) {
r = dns_packet_read_rr(p, &rr, &cache_flush, NULL);
if (r < 0)
- goto finish;
+ return r;
/* Try to reduce memory usage a bit */
if (previous)
@@ -2167,7 +2130,7 @@ int dns_packet_extract(DnsPacket *p) {
continue;
}
- if (!dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key))) {
+ if (!dns_name_is_root(dns_resource_key_name(rr->key))) {
/* If the OPT RR is not owned by the root domain, then it is bad, let's ignore
* it. */
log_debug("OPT RR is not owned by root domain, ignoring.");
@@ -2213,7 +2176,7 @@ int dns_packet_extract(DnsPacket *p) {
(i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) |
(p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0));
if (r < 0)
- goto finish;
+ return r;
}
/* Remember this RR, so that we potentically can merge it's ->key object with the next RR. Note
@@ -2234,11 +2197,8 @@ int dns_packet_extract(DnsPacket *p) {
p->extracted = true;
- r = 0;
-
-finish:
- p->rindex = saved_rindex;
- return r;
+ /* no CANCEL, always rewind */
+ return 0;
}
int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) {
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-packet.h b/src/grp-resolve/systemd-resolved/resolved-dns-packet.h
index 0bf34d270c..416335d0a2 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-packet.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-packet.h
@@ -262,11 +262,9 @@ static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family,
return f|(family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4);
case DNS_PROTOCOL_MDNS:
- return family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4;
+ return f|(family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4);
default:
- break;
+ return f;
}
-
- return 0;
}
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-query.c b/src/grp-resolve/systemd-resolved/resolved-dns-query.c
index a378b2b7f7..ea04e58d61 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-query.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-query.c
@@ -62,6 +62,7 @@ static void dns_query_candidate_stop(DnsQueryCandidate *c) {
while ((t = set_steal_first(c->transactions))) {
set_remove(t->notify_query_candidates, c);
+ set_remove(t->notify_query_candidates_done, c);
dns_transaction_gc(t);
}
}
@@ -139,6 +140,10 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource
if (r < 0)
goto gc;
+ r = set_ensure_allocated(&t->notify_query_candidates_done, NULL);
+ if (r < 0)
+ goto gc;
+
r = set_put(t->notify_query_candidates, c);
if (r < 0)
goto gc;
@@ -421,6 +426,7 @@ int dns_query_new(
DnsResourceKey *key;
bool good = false;
int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(m);
@@ -471,31 +477,20 @@ int dns_query_new(
q->answer_family = AF_UNSPEC;
/* First dump UTF8 question */
- DNS_QUESTION_FOREACH(key, question_utf8) {
- _cleanup_free_ char *p = NULL;
-
- r = dns_resource_key_to_string(key, &p);
- if (r < 0)
- return r;
-
- log_debug("Looking up RR for %s.", strstrip(p));
- }
+ DNS_QUESTION_FOREACH(key, question_utf8)
+ log_debug("Looking up RR for %s.",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
/* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */
DNS_QUESTION_FOREACH(key, question_idna) {
- _cleanup_free_ char *p = NULL;
-
r = dns_question_contains(question_utf8, key);
if (r < 0)
return r;
if (r > 0)
continue;
- r = dns_resource_key_to_string(key, &p);
- if (r < 0)
- return r;
-
- log_debug("Looking up IDNA RR for %s.", strstrip(p));
+ log_debug("Looking up IDNA RR for %s.",
+ dns_resource_key_to_string(key, key_str, sizeof key_str));
}
LIST_PREPEND(queries, m->dns_queries, q);
@@ -815,7 +810,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {
switch (t->state) {
case DNS_TRANSACTION_SUCCESS: {
- /* We found a successfuly reply, merge it into the answer */
+ /* We found a successfully reply, merge it into the answer */
r = dns_answer_extend(&q->answer, t->answer);
if (r < 0)
goto fail;
@@ -937,7 +932,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
assert(q);
- q->n_cname_redirects ++;
+ q->n_cname_redirects++;
if (q->n_cname_redirects > CNAME_MAX)
return -ELOOP;
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-question.c b/src/grp-resolve/systemd-resolved/resolved-dns-question.c
index 8e452e79a4..c8b502d1cd 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-question.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-question.c
@@ -145,7 +145,7 @@ int dns_question_is_valid_for_query(DnsQuestion *q) {
if (q->n_keys > 65535)
return 0;
- name = DNS_RESOURCE_KEY_NAME(q->keys[0]);
+ name = dns_resource_key_name(q->keys[0]);
if (!name)
return 0;
@@ -154,7 +154,7 @@ int dns_question_is_valid_for_query(DnsQuestion *q) {
assert(q->keys[i]);
if (i > 0) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name);
+ r = dns_name_equal(dns_resource_key_name(q->keys[i]), name);
if (r <= 0)
return r;
}
@@ -235,7 +235,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
if (cname->key->type == DNS_TYPE_CNAME)
d = cname->cname.name;
else {
- r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
+ r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
if (r < 0)
return r;
if (r == 0)
@@ -244,7 +244,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname,
d = destination;
}
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), d);
+ r = dns_name_equal(dns_resource_key_name(key), d);
if (r < 0)
return r;
@@ -291,7 +291,7 @@ const char *dns_question_first_name(DnsQuestion *q) {
if (q->n_keys < 1)
return NULL;
- return DNS_RESOURCE_KEY_NAME(q->keys[0]);
+ return dns_resource_key_name(q->keys[0]);
}
int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bool convert_idna) {
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-rr.c b/src/grp-resolve/systemd-resolved/resolved-dns-rr.c
index 40f8e28dfd..6a29a93a26 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-rr.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-rr.c
@@ -22,6 +22,7 @@
#include "alloc-util.h"
#include "dns-domain.h"
#include "dns-type.h"
+#include "escape.h"
#include "hexdecoct.h"
#include "resolved-dns-dnssec.h"
#include "resolved-dns-packet.h"
@@ -65,7 +66,7 @@ DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const D
DnsResourceKey *k;
char *destination = NULL;
- r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
+ r = dns_name_change_suffix(dns_resource_key_name(key), dns_resource_key_name(cname->key), cname->dname.name, &destination);
if (r < 0)
return NULL;
if (r == 0)
@@ -95,7 +96,7 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key
return 0;
}
- r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), name, &joined);
if (r < 0)
return r;
@@ -157,6 +158,23 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
return NULL;
}
+const char* dns_resource_key_name(const DnsResourceKey *key) {
+ const char *name;
+
+ if (!key)
+ return NULL;
+
+ if (key->_name)
+ name = key->_name;
+ else
+ name = (char*) key + sizeof(DnsResourceKey);
+
+ if (dns_name_is_root(name))
+ return ".";
+ else
+ return name;
+}
+
bool dns_resource_key_is_address(const DnsResourceKey *key) {
assert(key);
@@ -171,7 +189,7 @@ int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
if (a == b)
return 1;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
+ r = dns_name_equal(dns_resource_key_name(a), dns_resource_key_name(b));
if (r <= 0)
return r;
@@ -203,18 +221,18 @@ int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr,
if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
return 0;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
+ r = dns_name_equal(dns_resource_key_name(rr->key), dns_resource_key_name(key));
if (r != 0)
return r;
if (search_domain) {
_cleanup_free_ char *joined = NULL;
- r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
if (r < 0)
return r;
- return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
+ return dns_name_equal(dns_resource_key_name(rr->key), joined);
}
return 0;
@@ -230,9 +248,9 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe
return 0;
if (cname->type == DNS_TYPE_CNAME)
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
+ r = dns_name_equal(dns_resource_key_name(key), dns_resource_key_name(cname));
else if (cname->type == DNS_TYPE_DNAME)
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
+ r = dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(cname));
else
return 0;
@@ -242,14 +260,14 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe
if (search_domain) {
_cleanup_free_ char *joined = NULL;
- r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
+ r = dns_name_concat(dns_resource_key_name(key), search_domain, &joined);
if (r < 0)
return r;
if (cname->type == DNS_TYPE_CNAME)
- return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname));
+ return dns_name_equal(joined, dns_resource_key_name(cname));
else if (cname->type == DNS_TYPE_DNAME)
- return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname));
+ return dns_name_endswith(joined, dns_resource_key_name(cname));
}
return 0;
@@ -267,7 +285,7 @@ int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *
if (soa->type != DNS_TYPE_SOA)
return 0;
- return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa));
+ return dns_name_endswith(dns_resource_key_name(key), dns_resource_key_name(soa));
}
static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
@@ -275,7 +293,7 @@ static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
assert(k);
- dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
+ 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);
}
@@ -284,7 +302,7 @@ static int dns_resource_key_compare_func(const void *a, const void *b) {
const DnsResourceKey *x = a, *y = b;
int ret;
- ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
+ ret = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y));
if (ret != 0)
return ret;
@@ -306,32 +324,22 @@ const struct hash_ops dns_resource_key_hash_ops = {
.compare = dns_resource_key_compare_func
};
-int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
- char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
- const char *c, *t, *n;
- char *s;
+char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size) {
+ const char *c, *t;
+ char *ans = buf;
/* If we cannot convert the CLASS/TYPE into a known string,
use the format recommended by RFC 3597, Section 5. */
c = dns_class_to_string(key->class);
- if (!c) {
- sprintf(cbuf, "CLASS%u", key->class);
- c = cbuf;
- }
-
t = dns_type_to_string(key->type);
- if (!t){
- sprintf(tbuf, "TYPE%u", key->type);
- t = tbuf;
- }
- n = DNS_RESOURCE_KEY_NAME(key);
- if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0)
- return -ENOMEM;
+ snprintf(buf, buf_size, "%s %s%s%.0u %s%s%.0u",
+ dns_resource_key_name(key),
+ c ?: "", c ? "" : "CLASS", c ? 0 : key->class,
+ t ?: "", t ? "" : "TYPE", t ? 0 : key->class);
- *ret = s;
- return 0;
+ return ans;
}
bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) {
@@ -490,6 +498,11 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
free(rr->tlsa.data);
break;
+ case DNS_TYPE_CAA:
+ free(rr->caa.tag);
+ free(rr->caa.value);
+ break;
+
case DNS_TYPE_OPENPGPKEY:
default:
free(rr->generic.data);
@@ -697,6 +710,12 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
a->tlsa.matching_type == b->tlsa.matching_type &&
FIELD_EQUAL(a->tlsa, b->tlsa, data);
+ case DNS_TYPE_CAA:
+ return a->caa.flags == b->caa.flags &&
+ streq(a->caa.tag, b->caa.tag) &&
+ FIELD_EQUAL(a->caa, b->caa, value);
+
+ case DNS_TYPE_OPENPGPKEY:
default:
return FIELD_EQUAL(a->generic, b->generic, data);
}
@@ -818,8 +837,8 @@ static char *format_txt(DnsTxtItem *first) {
}
const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
- _cleanup_free_ char *k = NULL, *t = NULL;
- char *s;
+ _cleanup_free_ char *t = NULL;
+ char *s, k[DNS_RESOURCE_KEY_STRING_MAX];
int r;
assert(rr);
@@ -827,9 +846,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
if (rr->to_string)
return rr->to_string;
- r = dns_resource_key_to_string(rr->key, &k);
- if (r < 0)
- return NULL;
+ dns_resource_key_to_string(rr->key, k, sizeof(k));
switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
@@ -966,7 +983,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
case DNS_TYPE_DNSKEY: {
_cleanup_free_ char *alg = NULL;
char *ss;
- int n, n1;
+ int n;
uint16_t key_tag;
key_tag = dnssec_keytag(rr, true);
@@ -975,9 +992,8 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
if (r < 0)
return NULL;
- r = asprintf(&s, "%s %n%u %u %s %n",
+ r = asprintf(&s, "%s %u %u %s %n",
k,
- &n1,
rr->dnskey.flags,
rr->dnskey.protocol,
alg,
@@ -992,14 +1008,12 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
return NULL;
r = asprintf(&ss, "%s\n"
- "%*s-- Flags:%s%s%s\n"
- "%*s-- Key tag: %u",
+ " -- Flags:%s%s%s\n"
+ " -- Key tag: %u",
s,
- n1, "",
rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "",
rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "",
rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "",
- n1, "",
key_tag);
if (r < 0)
return NULL;
@@ -1102,40 +1116,52 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
case DNS_TYPE_TLSA: {
const char *cert_usage, *selector, *matching_type;
- char *ss;
- int n;
cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage);
selector = tlsa_selector_to_string(rr->tlsa.selector);
matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type);
- r = asprintf(&s, "%s %u %u %u %n",
+ t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
+ if (!t)
+ return NULL;
+
+ r = asprintf(&s,
+ "%s %u %u %u %s\n"
+ " -- Cert. usage: %s\n"
+ " -- Selector: %s\n"
+ " -- Matching type: %s",
k,
rr->tlsa.cert_usage,
rr->tlsa.selector,
rr->tlsa.matching_type,
- &n);
+ t,
+ cert_usage,
+ selector,
+ matching_type);
if (r < 0)
return NULL;
- r = base64_append(&s, n,
- rr->tlsa.data, rr->tlsa.data_size,
- 8, columns());
- if (r < 0)
+ break;
+ }
+
+ case DNS_TYPE_CAA: {
+ _cleanup_free_ char *value;
+
+ value = octescape(rr->caa.value, rr->caa.value_size);
+ if (!value)
return NULL;
- r = asprintf(&ss, "%s\n"
- "%*s-- Cert. usage: %s\n"
- "%*s-- Selector: %s\n"
- "%*s-- Matching type: %s",
- s,
- n - 6, "", cert_usage,
- n - 6, "", selector,
- n - 6, "", matching_type);
+ r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u",
+ k,
+ rr->caa.flags,
+ rr->caa.tag,
+ value,
+ rr->caa.flags ? "\n -- Flags:" : "",
+ rr->caa.flags & CAA_FLAG_CRITICAL ? " critical" : "",
+ rr->caa.flags & ~CAA_FLAG_CRITICAL ? " " : "",
+ rr->caa.flags & ~CAA_FLAG_CRITICAL);
if (r < 0)
return NULL;
- free(s);
- s = ss;
break;
}
@@ -1173,6 +1199,47 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
return s;
}
+ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) {
+ assert(rr);
+ assert(out);
+
+ switch(rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
+ case DNS_TYPE_SRV:
+ case DNS_TYPE_PTR:
+ case DNS_TYPE_NS:
+ case DNS_TYPE_CNAME:
+ case DNS_TYPE_DNAME:
+ case DNS_TYPE_HINFO:
+ case DNS_TYPE_SPF:
+ case DNS_TYPE_TXT:
+ case DNS_TYPE_A:
+ case DNS_TYPE_AAAA:
+ case DNS_TYPE_SOA:
+ case DNS_TYPE_MX:
+ case DNS_TYPE_LOC:
+ case DNS_TYPE_DS:
+ case DNS_TYPE_DNSKEY:
+ case DNS_TYPE_RRSIG:
+ case DNS_TYPE_NSEC:
+ case DNS_TYPE_NSEC3:
+ return -EINVAL;
+
+ case DNS_TYPE_SSHFP:
+ *out = rr->sshfp.fingerprint;
+ return rr->sshfp.fingerprint_size;
+
+ case DNS_TYPE_TLSA:
+ *out = rr->tlsa.data;
+ return rr->tlsa.data_size;
+
+
+ case DNS_TYPE_OPENPGPKEY:
+ default:
+ *out = rr->generic.data;
+ return rr->generic.data_size;
+ }
+}
+
int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
DnsPacket packet = {
@@ -1230,7 +1297,7 @@ int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) {
if (rr->n_skip_labels_signer == (unsigned) -1)
return -ENODATA;
- n = DNS_RESOURCE_KEY_NAME(rr->key);
+ n = dns_resource_key_name(rr->key);
r = dns_name_skip(n, rr->n_skip_labels_signer, &n);
if (r < 0)
return r;
@@ -1253,7 +1320,7 @@ int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) {
if (rr->n_skip_labels_source == (unsigned) -1)
return -ENODATA;
- n = DNS_RESOURCE_KEY_NAME(rr->key);
+ n = dns_resource_key_name(rr->key);
r = dns_name_skip(n, rr->n_skip_labels_source, &n);
if (r < 0)
return r;
@@ -1293,14 +1360,14 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
if (rr->n_skip_labels_source > 1)
return 1;
- r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*");
+ r = dns_name_startswith(dns_resource_key_name(rr->key), "*");
if (r < 0)
return r;
return !r;
}
-static void dns_resource_record_hash_func(const void *i, struct siphash *state) {
+void dns_resource_record_hash_func(const void *i, struct siphash *state) {
const DnsResourceRecord *rr = i;
assert(rr);
@@ -1427,7 +1494,13 @@ static void dns_resource_record_hash_func(const void *i, struct siphash *state)
siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state);
siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state);
siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state);
- siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state);
+ siphash24_compress(rr->tlsa.data, rr->tlsa.data_size, state);
+ break;
+
+ case DNS_TYPE_CAA:
+ siphash24_compress(&rr->caa.flags, sizeof(rr->caa.flags), state);
+ string_hash_func(rr->caa.tag, state);
+ siphash24_compress(rr->caa.value, rr->caa.value_size, state);
break;
case DNS_TYPE_OPENPGPKEY:
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-rr.h b/src/grp-resolve/systemd-resolved/resolved-dns-rr.h
index 2e0dfbaba3..020a2abd77 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-rr.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-rr.h
@@ -26,6 +26,7 @@
#include "hashmap.h"
#include "in-addr-util.h"
#include "list.h"
+#include "string-util.h"
typedef struct DnsResourceKey DnsResourceKey;
typedef struct DnsResourceRecord DnsResourceRecord;
@@ -81,7 +82,7 @@ enum {
struct DnsResourceKey {
unsigned n_ref; /* (unsigned -1) for const keys, see below */
uint16_t class, type;
- char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */
+ char *_name; /* don't access directly, use dns_resource_key_name()! */
};
/* Creates a temporary resource key. This is only useful to quickly
@@ -249,19 +250,17 @@ struct DnsResourceRecord {
void *data;
size_t data_size;
} tlsa;
+
+ /* https://tools.ietf.org/html/rfc6844 */
+ struct {
+ uint8_t flags;
+ char *tag;
+ void *value;
+ size_t value_size;
+ } caa;
};
};
-static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) {
- if (!key)
- return NULL;
-
- if (key->_name)
- return key->_name;
-
- return (char*) key + sizeof(DnsResourceKey);
-}
-
static inline const void* DNS_RESOURCE_RECORD_RDATA(DnsResourceRecord *rr) {
if (!rr)
return NULL;
@@ -289,12 +288,20 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key
DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name);
DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key);
DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key);
+const char* dns_resource_key_name(const DnsResourceKey *key);
bool dns_resource_key_is_address(const DnsResourceKey *key);
int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b);
int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain);
int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain);
int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa);
-int dns_resource_key_to_string(const DnsResourceKey *key, char **ret);
+
+/* _DNS_{CLASS,TYPE}_STRING_MAX include one byte for NUL, which we use for space instead below.
+ * DNS_HOSTNAME_MAX does not include the NUL byte, so we need to add 1. */
+#define DNS_RESOURCE_KEY_STRING_MAX (_DNS_CLASS_STRING_MAX + _DNS_TYPE_STRING_MAX + DNS_HOSTNAME_MAX + 1)
+
+char* dns_resource_key_to_string(const DnsResourceKey *key, char *buf, size_t buf_size);
+ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref);
static inline bool dns_key_is_shared(const DnsResourceKey *key) {
@@ -323,6 +330,8 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr);
DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i);
bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b);
+void dns_resource_record_hash_func(const void *i, struct siphash *state);
+
extern const struct hash_ops dns_resource_key_hash_ops;
extern const struct hash_ops dns_resource_record_hash_ops;
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-scope.c b/src/grp-resolve/systemd-resolved/resolved-dns-scope.c
index a406872a38..66e4585c18 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-scope.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-scope.c
@@ -514,8 +514,8 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) {
* that those should be resolved via LLMNR or search
* path only, and should not be leaked onto the
* internet. */
- return !(dns_name_is_single_label(DNS_RESOURCE_KEY_NAME(key)) ||
- dns_name_is_root(DNS_RESOURCE_KEY_NAME(key)));
+ return !(dns_name_is_single_label(dns_resource_key_name(key)) ||
+ dns_name_is_root(dns_resource_key_name(key)));
}
/* On mDNS and LLMNR, send A and AAAA queries only on the
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-server.c b/src/grp-resolve/systemd-resolved/resolved-dns-server.c
index 27342a0e04..3095c042db 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-server.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-server.c
@@ -120,7 +120,7 @@ DnsServer* dns_server_ref(DnsServer *s) {
return NULL;
assert(s->n_ref > 0);
- s->n_ref ++;
+ s->n_ref++;
return s;
}
@@ -130,7 +130,7 @@ DnsServer* dns_server_unref(DnsServer *s) {
return NULL;
assert(s->n_ref > 0);
- s->n_ref --;
+ s->n_ref--;
if (s->n_ref > 0)
return NULL;
@@ -157,6 +157,7 @@ void dns_server_unlink(DnsServer *s) {
assert(s->link);
assert(s->link->n_dns_servers > 0);
LIST_REMOVE(servers, s->link->dns_servers, s);
+ s->link->n_dns_servers--;
break;
case DNS_SERVER_SYSTEM:
@@ -290,9 +291,9 @@ void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel le
if (s->possible_feature_level == level) {
if (protocol == IPPROTO_UDP)
- s->n_failed_udp ++;
+ s->n_failed_udp++;
else if (protocol == IPPROTO_TCP)
- s->n_failed_tcp ++;
+ s->n_failed_tcp++;
}
if (s->resend_timeout > usec)
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c b/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c
index f4a43dee8c..e3003411f7 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-synthesize.c
@@ -86,7 +86,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
- rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key));
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, dns_resource_key_name(key));
if (!rr)
return -ENOMEM;
@@ -100,7 +100,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if
if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) {
_cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
- rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key));
+ rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key));
if (!rr)
return -ENOMEM;
@@ -140,7 +140,7 @@ static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int i
if (r < 0)
return r;
- r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
+ r = answer_add_ptr(answer, dns_resource_key_name(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED);
if (r < 0)
return r;
}
@@ -254,11 +254,11 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key,
.address.in6 = in6addr_loopback,
};
- return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n);
+ return answer_add_addresses_rr(answer, dns_resource_key_name(key), buffer, n);
}
}
- return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
+ return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
}
static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
@@ -319,7 +319,7 @@ static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifin
return n;
}
- return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n);
+ return answer_add_addresses_rr(answer, dns_resource_key_name(key), addresses, n);
}
static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) {
@@ -360,7 +360,7 @@ int dns_synthesize_answer(
key->class != DNS_CLASS_ANY)
continue;
- name = DNS_RESOURCE_KEY_NAME(key);
+ name = dns_resource_key_name(key);
if (is_localhost(name)) {
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c
index d48fdd1281..a4a67623e7 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.c
@@ -52,6 +52,7 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) {
while ((z = set_steal_first(t->dnssec_transactions))) {
set_remove(z->notify_transactions, t);
+ set_remove(z->notify_transactions_done, t);
dns_transaction_gc(z);
}
}
@@ -100,20 +101,31 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) {
set_remove(c->transactions, t);
set_free(t->notify_query_candidates);
+ while ((c = set_steal_first(t->notify_query_candidates_done)))
+ set_remove(c->transactions, t);
+ set_free(t->notify_query_candidates_done);
+
while ((i = set_steal_first(t->notify_zone_items)))
i->probe_transaction = NULL;
set_free(t->notify_zone_items);
+ while ((i = set_steal_first(t->notify_zone_items_done)))
+ i->probe_transaction = NULL;
+ set_free(t->notify_zone_items_done);
+
while ((z = set_steal_first(t->notify_transactions)))
set_remove(z->dnssec_transactions, t);
set_free(t->notify_transactions);
+ while ((z = set_steal_first(t->notify_transactions_done)))
+ set_remove(z->dnssec_transactions, t);
+ set_free(t->notify_transactions_done);
+
dns_transaction_flush_dnssec_transactions(t);
set_free(t->dnssec_transactions);
dns_answer_unref(t->validated_keys);
dns_resource_key_unref(t->key);
- free(t->key_string);
free(t);
return NULL;
@@ -128,8 +140,11 @@ bool dns_transaction_gc(DnsTransaction *t) {
return true;
if (set_isempty(t->notify_query_candidates) &&
+ set_isempty(t->notify_query_candidates_done) &&
set_isempty(t->notify_zone_items) &&
- set_isempty(t->notify_transactions)) {
+ set_isempty(t->notify_zone_items_done) &&
+ set_isempty(t->notify_transactions) &&
+ set_isempty(t->notify_transactions_done)) {
dns_transaction_free(t);
return false;
}
@@ -210,7 +225,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key)
LIST_PREPEND(transactions_by_scope, s->transactions, t);
t->scope = s;
- s->manager->n_transactions_total ++;
+ s->manager->n_transactions_total++;
if (ret)
*ret = t;
@@ -238,6 +253,7 @@ static void dns_transaction_shuffle_id(DnsTransaction *t) {
static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
_cleanup_free_ char *pretty = NULL;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsZoneItem *z;
assert(t);
@@ -246,15 +262,15 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
if (manager_our_packet(t->scope->manager, p) != 0)
return;
- in_addr_to_string(p->family, &p->sender, &pretty);
+ (void) in_addr_to_string(p->family, &p->sender, &pretty);
log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.",
t->id,
- dns_transaction_key_string(t),
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
- t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
- pretty);
+ af_to_name_short(t->scope->family),
+ strnull(pretty));
/* RFC 4795, Section 4.1 says that the peer with the
* lexicographically smaller IP address loses */
@@ -266,6 +282,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
log_debug("We have the lexicographically larger IP address and thus lost in the conflict.");
t->block_gc++;
+
while ((z = set_first(t->notify_zone_items))) {
/* First, make sure the zone item drops the reference
* to us */
@@ -284,22 +301,25 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
DnsQueryCandidate *c;
DnsZoneItem *z;
DnsTransaction *d;
- Iterator i;
const char *st;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(t);
assert(!DNS_TRANSACTION_IS_LIVE(state));
- if (state == DNS_TRANSACTION_DNSSEC_FAILED)
+ if (state == DNS_TRANSACTION_DNSSEC_FAILED) {
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str);
+
log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_FAILURE),
- LOG_MESSAGE("DNSSEC validation failed for question %s: %s", dns_transaction_key_string(t), dnssec_result_to_string(t->answer_dnssec_result)),
+ LOG_MESSAGE("DNSSEC validation failed for question %s: %s", key_str, dnssec_result_to_string(t->answer_dnssec_result)),
"DNS_TRANSACTION=%" PRIu16, t->id,
- "DNS_QUESTION=%s", dns_transaction_key_string(t),
+ "DNS_QUESTION=%s", key_str,
"DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result),
"DNS_SERVER=%s", dns_server_string(t->server),
"DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level),
NULL);
+ }
/* Note that this call might invalidate the query. Callers
* should hence not attempt to access the query or transaction
@@ -312,10 +332,10 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).",
t->id,
- dns_transaction_key_string(t),
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
- t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family),
+ af_to_name_short(t->scope->family),
st,
t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source),
t->answer_authenticated ? "authenticated" : "unsigned");
@@ -329,39 +349,17 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
* transaction isn't freed while we are still looking at it */
t->block_gc++;
- SET_FOREACH(c, t->notify_query_candidates, i)
+ SET_FOREACH_MOVE(c, t->notify_query_candidates_done, t->notify_query_candidates)
dns_query_candidate_notify(c);
- SET_FOREACH(z, t->notify_zone_items, i)
- dns_zone_item_notify(z);
-
- if (!set_isempty(t->notify_transactions)) {
- DnsTransaction **nt;
- unsigned j, n = 0;
-
- /* We need to be careful when notifying other
- * transactions, as that might destroy other
- * transactions in our list. Hence, in order to be
- * able to safely iterate through the list of
- * transactions, take a GC lock on all of them
- * first. Then, in a second loop, notify them, but
- * first unlock that specific transaction. */
-
- nt = newa(DnsTransaction*, set_size(t->notify_transactions));
- SET_FOREACH(d, t->notify_transactions, i) {
- nt[n++] = d;
- d->block_gc++;
- }
+ SWAP_TWO(t->notify_query_candidates, t->notify_query_candidates_done);
- assert(n == set_size(t->notify_transactions));
-
- for (j = 0; j < n; j++) {
- if (set_contains(t->notify_transactions, nt[j]))
- dns_transaction_notify(nt[j], t);
+ SET_FOREACH_MOVE(z, t->notify_zone_items_done, t->notify_zone_items)
+ dns_zone_item_notify(z);
+ SWAP_TWO(t->notify_zone_items, t->notify_zone_items_done);
- nt[j]->block_gc--;
- dns_transaction_gc(nt[j]);
- }
- }
+ SET_FOREACH_MOVE(d, t->notify_transactions_done, t->notify_transactions)
+ dns_transaction_notify(d, t);
+ SWAP_TWO(t->notify_transactions, t->notify_transactions_done);
t->block_gc--;
dns_transaction_gc(t);
@@ -522,7 +520,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) {
* the IP address, in case this is a reverse
* PTR lookup */
- r = dns_name_address(DNS_RESOURCE_KEY_NAME(t->key), &family, &address);
+ r = dns_name_address(dns_resource_key_name(t->key), &family, &address);
if (r < 0)
return r;
if (r == 0)
@@ -1209,7 +1207,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
return 0;
}
- if (dns_name_is_root(DNS_RESOURCE_KEY_NAME(t->key)) &&
+ if (dns_name_is_root(dns_resource_key_name(t->key)) &&
t->key->type == DNS_TYPE_DS) {
/* Hmm, this is a request for the root DS? A
@@ -1237,8 +1235,7 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) {
* might be DS RRs, but we don't know
* them, and the DNS server won't tell
* them to us (and even if it would,
- * we couldn't validate it and trust
- * it). */
+ * we couldn't validate and trust them. */
dns_transaction_complete(t, DNS_TRANSACTION_NO_TRUST_ANCHOR);
return 0;
@@ -1372,7 +1369,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) {
other->state = DNS_TRANSACTION_PENDING;
other->next_attempt_after = ts;
- qdcount ++;
+ qdcount++;
if (dns_key_is_shared(other->key))
add_known_answers = true;
@@ -1425,6 +1422,7 @@ static int dns_transaction_make_packet(DnsTransaction *t) {
int dns_transaction_go(DnsTransaction *t) {
usec_t ts;
int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
assert(t);
@@ -1434,12 +1432,12 @@ int dns_transaction_go(DnsTransaction *t) {
if (r <= 0)
return r;
- log_debug("Excercising transaction %" PRIu16 " for <%s> on scope %s on %s/%s.",
+ log_debug("Transaction %" PRIu16 " for <%s> scope %s on %s/%s.",
t->id,
- dns_transaction_key_string(t),
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
t->scope->link ? t->scope->link->name : "*",
- t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family));
+ af_to_name_short(t->scope->family));
if (!t->initial_jitter_scheduled &&
(t->scope->protocol == DNS_PROTOCOL_LLMNR ||
@@ -1494,8 +1492,8 @@ int dns_transaction_go(DnsTransaction *t) {
return r;
if (t->scope->protocol == DNS_PROTOCOL_LLMNR &&
- (dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "in-addr.arpa") > 0 ||
- dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), "ip6.arpa") > 0)) {
+ (dns_name_endswith(dns_resource_key_name(t->key), "in-addr.arpa") > 0 ||
+ dns_name_endswith(dns_resource_key_name(t->key), "ip6.arpa") > 0)) {
/* RFC 4795, Section 2.4. says reverse lookups shall
* always be made via TCP on LLMNR */
@@ -1602,11 +1600,14 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource
if (r < 0)
return r;
if (r > 0) {
- log_debug("Detected potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).",
+ char s[DNS_RESOURCE_KEY_STRING_MAX], saux[DNS_RESOURCE_KEY_STRING_MAX];
+
+ log_debug("Potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).",
aux->id,
- strna(dns_transaction_key_string(aux)),
+ dns_resource_key_to_string(t->key, s, sizeof s),
t->id,
- strna(dns_transaction_key_string(t)));
+ dns_resource_key_to_string(aux->key, saux, sizeof saux));
+
return -ELOOP;
}
}
@@ -1619,6 +1620,10 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource
if (r < 0)
goto gc;
+ r = set_ensure_allocated(&aux->notify_transactions_done, NULL);
+ if (r < 0)
+ goto gc;
+
r = set_put(t->dnssec_transactions, aux);
if (r < 0)
goto gc;
@@ -1678,7 +1683,7 @@ static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const
assert(t);
- /* Check whether the specified name is in the the NTA
+ /* Check whether the specified name is in the NTA
* database, either in the global one, or the link-local
* one. */
@@ -1708,7 +1713,7 @@ static int dns_transaction_has_unsigned_negative_answer(DnsTransaction *t) {
/* Is this key explicitly listed as a negative trust anchor?
* If so, it's nothing we need to care about */
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key));
if (r < 0)
return r;
if (r > 0)
@@ -1799,7 +1804,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* - For unsigned SOA/NS we get the matching DS
* - For unsigned CNAME/DNAME/DS we get the parent SOA RR
* - For other unsigned RRs we get the matching SOA RR
- * - For SOA/NS/DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
+ * - For SOA/NS queries with no matching response RR, and no NSEC/NSEC3, the DS RR
+ * - For DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR
* - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR
*/
@@ -1816,7 +1822,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
continue;
/* If this RR is in the negative trust anchor, we don't need to validate it. */
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -1833,7 +1839,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* already have the DNSKEY, and we don't have
* to look for more. */
if (rr->rrsig.type_covered == DNS_TYPE_DNSKEY) {
- r = dns_name_equal(rr->rrsig.signer, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(rr->rrsig.signer, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -1851,7 +1857,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* in another transaction whose additonal RRs
* point back to the original transaction, and
* we deadlock. */
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), rr->rrsig.signer);
+ r = dns_name_endswith(dns_resource_key_name(t->key), rr->rrsig.signer);
if (r < 0)
return r;
if (r == 0)
@@ -1861,7 +1867,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (!dnskey)
return -ENOMEM;
- log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), rr->rrsig.key_tag);
+ log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").",
+ t->id, dns_resource_key_name(rr->key), rr->rrsig.key_tag);
r = dns_transaction_request_dnssec_rr(t, dnskey);
if (r < 0)
return r;
@@ -1879,17 +1886,18 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
* up in request loops, and want to keep
* additional traffic down. */
- r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_endswith(dns_resource_key_name(t->key), dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r == 0)
continue;
- ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key));
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
if (!ds)
return -ENOMEM;
- log_debug("Requesting DS to validate transaction %" PRIu16" (%s, DNSKEY with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dnssec_keytag(rr, false));
+ log_debug("Requesting DS to validate transaction %" PRIu16" (%s, DNSKEY with key tag: %" PRIu16 ").",
+ t->id, dns_resource_key_name(rr->key), dnssec_keytag(rr, false));
r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
@@ -1920,11 +1928,12 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0)
continue;
- ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key));
+ ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, dns_resource_key_name(rr->key));
if (!ds)
return -ENOMEM;
- log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned SOA/NS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key));
+ log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned SOA/NS RRset).",
+ t->id, dns_resource_key_name(rr->key));
r = dns_transaction_request_dnssec_rr(t, ds);
if (r < 0)
return r;
@@ -1966,7 +1975,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0)
continue;
- name = DNS_RESOURCE_KEY_NAME(rr->key);
+ name = dns_resource_key_name(rr->key);
r = dns_name_parent(&name);
if (r < 0)
return r;
@@ -1977,7 +1986,8 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (!soa)
return -ENOMEM;
- log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key));
+ log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).",
+ t->id, dns_resource_key_name(rr->key));
r = dns_transaction_request_dnssec_rr(t, soa);
if (r < 0)
return r;
@@ -2007,11 +2017,12 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0)
continue;
- soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, DNS_RESOURCE_KEY_NAME(rr->key));
+ soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, dns_resource_key_name(rr->key));
if (!soa)
return -ENOMEM;
- log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dns_resource_record_to_string(rr));
+ log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).",
+ t->id, dns_resource_key_name(rr->key), dns_resource_record_to_string(rr));
r = dns_transaction_request_dnssec_rr(t, soa);
if (r < 0)
return r;
@@ -2028,30 +2039,42 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
return r;
if (r > 0) {
const char *name;
+ uint16_t type = 0;
- name = DNS_RESOURCE_KEY_NAME(t->key);
+ name = dns_resource_key_name(t->key);
- /* If this was a SOA or NS request, then this
- * indicates that we are not at a zone apex, hence ask
- * the parent name instead. If this was a DS request,
- * then it's signed when the parent zone is signed,
- * hence ask the parent in that case, too. */
+ /* If this was a SOA or NS request, then check if there's a DS RR for the same domain. Note that this
+ * could also be used as indication that we are not at a zone apex, but in real world setups there are
+ * too many broken DNS servers (Hello, incapdns.net!) where non-terminal zones return NXDOMAIN even
+ * though they have further children. If this was a DS request, then it's signed when the parent zone
+ * is signed, hence ask the parent SOA in that case. If this was any other RR then ask for the SOA RR,
+ * to see if that is signed. */
- if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) {
+ if (t->key->type == DNS_TYPE_DS) {
r = dns_name_parent(&name);
- if (r < 0)
- return r;
- if (r > 0)
- log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key));
- else
+ if (r > 0) {
+ type = DNS_TYPE_SOA;
+ log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty DS response).",
+ t->id, dns_resource_key_name(t->key));
+ } else
name = NULL;
- } else
- log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key));
+
+ } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) {
+
+ type = DNS_TYPE_DS;
+ log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS response).",
+ t->id, dns_resource_key_name(t->key));
+
+ } else {
+ type = DNS_TYPE_SOA;
+ log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).",
+ t->id, dns_resource_key_name(t->key));
+ }
if (name) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL;
- soa = dns_resource_key_new(t->key->class, DNS_TYPE_SOA, name);
+ soa = dns_resource_key_new(t->key->class, type, name);
if (!soa)
return -ENOMEM;
@@ -2118,7 +2141,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (dns_type_is_pseudo(rr->key->type))
return -EINVAL;
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -2144,7 +2167,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (dt->key->type != DNS_TYPE_DS)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r == 0)
@@ -2187,7 +2210,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
continue;
if (!parent) {
- parent = DNS_RESOURCE_KEY_NAME(rr->key);
+ parent = dns_resource_key_name(rr->key);
r = dns_name_parent(&parent);
if (r < 0)
return r;
@@ -2201,7 +2224,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
}
}
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), parent);
+ r = dns_name_equal(dns_resource_key_name(dt->key), parent);
if (r < 0)
return r;
if (r == 0)
@@ -2226,7 +2249,7 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *
if (dt->key->type != DNS_TYPE_SOA)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r == 0)
@@ -2273,7 +2296,7 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe
if (t->scope->dnssec_mode != DNSSEC_ALLOW_DOWNGRADE)
return false; /* In strict DNSSEC mode what doesn't exist, doesn't exist */
- tld = DNS_RESOURCE_KEY_NAME(key);
+ tld = dns_resource_key_name(key);
r = dns_name_parent(&tld);
if (r < 0)
return r;
@@ -2288,7 +2311,7 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe
if (dt->key->class != key->class)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), tld);
+ r = dns_name_equal(dns_resource_key_name(dt->key), tld);
if (r < 0)
return r;
if (r == 0)
@@ -2305,8 +2328,10 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe
}
static int dns_transaction_requires_nsec(DnsTransaction *t) {
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
DnsTransaction *dt;
const char *name;
+ uint16_t type = 0;
Iterator i;
int r;
@@ -2321,7 +2346,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
if (dns_type_is_pseudo(t->key->type))
return -EINVAL;
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key));
if (r < 0)
return r;
if (r > 0)
@@ -2335,28 +2360,32 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
* exist, and we are in downgrade mode, hence ignore
* that fact that we didn't get any NSEC RRs.*/
- log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.", dns_transaction_key_string(t));
+ log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.",
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str));
return false;
}
- name = DNS_RESOURCE_KEY_NAME(t->key);
+ name = dns_resource_key_name(t->key);
- if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) {
+ if (t->key->type == DNS_TYPE_DS) {
- /* We got a negative reply for this SOA/NS lookup? If
- * so, then we are not at a zone apex, and thus should
- * look at the result of the parent SOA lookup.
- *
- * We got a negative reply for this DS lookup? DS RRs
- * are signed when their parent zone is signed, hence
- * also check the parent SOA in this case. */
+ /* We got a negative reply for this DS lookup? DS RRs are signed when their parent zone is signed,
+ * hence check the parent SOA in this case. */
r = dns_name_parent(&name);
if (r < 0)
return r;
if (r == 0)
return true;
- }
+
+ type = DNS_TYPE_SOA;
+
+ } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS))
+ /* We got a negative reply for this SOA/NS lookup? If so, check if there's a DS RR for this */
+ type = DNS_TYPE_DS;
+ else
+ /* For all other negative replies, check for the SOA lookup */
+ type = DNS_TYPE_SOA;
/* For all other RRs we check the SOA on the same level to see
* if it's signed. */
@@ -2365,10 +2394,10 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) {
if (dt->key->class != t->key->class)
continue;
- if (dt->key->type != DNS_TYPE_SOA)
+ if (dt->key->type != type)
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), name);
+ r = dns_name_equal(dns_resource_key_name(dt->key), name);
if (r < 0)
return r;
if (r == 0)
@@ -2390,7 +2419,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe
* the specified RRset is authenticated (i.e. has a matching
* DS RR). */
- r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key));
+ r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(rr->key));
if (r < 0)
return r;
if (r > 0)
@@ -2413,7 +2442,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe
if (dt->key->type == DNS_TYPE_DNSKEY) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer);
+ r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer);
if (r < 0)
return r;
if (r == 0)
@@ -2430,7 +2459,7 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe
} else if (dt->key->type == DNS_TYPE_DS) {
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer);
+ r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer);
if (r < 0)
return r;
if (r == 0)
@@ -2460,7 +2489,7 @@ static int dns_transaction_known_signed(DnsTransaction *t, DnsResourceRecord *rr
* not to be signed, there's a problem with the DNS server */
return rr->key->class == DNS_CLASS_IN &&
- dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key));
+ dns_name_is_root(dns_resource_key_name(rr->key));
}
static int dns_transaction_check_revoked_trust_anchors(DnsTransaction *t) {
@@ -2541,343 +2570,347 @@ static int dns_transaction_copy_validated(DnsTransaction *t) {
return 0;
}
-int dns_transaction_validate_dnssec(DnsTransaction *t) {
- _cleanup_(dns_answer_unrefp) DnsAnswer *validated = NULL;
- enum {
- PHASE_DNSKEY, /* Phase #1, only validate DNSKEYs */
- PHASE_NSEC, /* Phase #2, only validate NSEC+NSEC3 */
- PHASE_ALL, /* Phase #3, validate everything else */
- } phase;
+typedef enum {
+ DNSSEC_PHASE_DNSKEY, /* Phase #1, only validate DNSKEYs */
+ DNSSEC_PHASE_NSEC, /* Phase #2, only validate NSEC+NSEC3 */
+ DNSSEC_PHASE_ALL, /* Phase #3, validate everything else */
+} Phase;
+
+static int dnssec_validate_records(
+ DnsTransaction *t,
+ Phase phase,
+ bool *have_nsec,
+ DnsAnswer **validated) {
+
DnsResourceRecord *rr;
- DnsAnswerFlags flags;
int r;
- assert(t);
+ /* Returns negative on error, 0 if validation failed, 1 to restart validation, 2 when finished. */
- /* We have now collected all DS and DNSKEY RRs in
- * t->validated_keys, let's see which RRs we can now
- * authenticate with that. */
+ DNS_ANSWER_FOREACH(rr, t->answer) {
+ DnsResourceRecord *rrsig = NULL;
+ DnssecResult result;
- if (t->scope->dnssec_mode == DNSSEC_NO)
- return 0;
+ switch (rr->key->type) {
+ case DNS_TYPE_RRSIG:
+ continue;
- /* Already validated */
- if (t->answer_dnssec_result != _DNSSEC_RESULT_INVALID)
- return 0;
+ case DNS_TYPE_DNSKEY:
+ /* We validate DNSKEYs only in the DNSKEY and ALL phases */
+ if (phase == DNSSEC_PHASE_NSEC)
+ continue;
+ break;
- /* Our own stuff needs no validation */
- if (IN_SET(t->answer_source, DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR)) {
- t->answer_dnssec_result = DNSSEC_VALIDATED;
- t->answer_authenticated = true;
- return 0;
- }
+ case DNS_TYPE_NSEC:
+ case DNS_TYPE_NSEC3:
+ *have_nsec = true;
- /* Cached stuff is not affected by validation. */
- if (t->answer_source != DNS_TRANSACTION_NETWORK)
- return 0;
+ /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */
+ if (phase == DNSSEC_PHASE_DNSKEY)
+ continue;
+ break;
- if (!dns_transaction_dnssec_supported_full(t)) {
- /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */
- t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
- log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id);
- return 0;
- }
+ default:
+ /* We validate all other RRs only in the ALL phases */
+ if (phase != DNSSEC_PHASE_ALL)
+ continue;
+ }
- log_debug("Validating response from transaction %" PRIu16 " (%s).", t->id, dns_transaction_key_string(t));
+ r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig);
+ if (r < 0)
+ return r;
- /* First, see if this response contains any revoked trust
- * anchors we care about */
- r = dns_transaction_check_revoked_trust_anchors(t);
- if (r < 0)
- return r;
+ log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
- /* Third, copy all RRs we acquired successfully from auxiliary RRs over. */
- r = dns_transaction_copy_validated(t);
- if (r < 0)
- return r;
+ if (result == DNSSEC_VALIDATED) {
- /* Second, see if there are DNSKEYs we already know a
- * validated DS for. */
- r = dns_transaction_validate_dnskey_by_ds(t);
- if (r < 0)
- return r;
+ if (rr->key->type == DNS_TYPE_DNSKEY) {
+ /* If we just validated a DNSKEY RRset, then let's add these keys to
+ * the set of validated keys for this transaction. */
- /* Fourth, remove all DNSKEY and DS RRs again that our trust
- * anchor says are revoked. After all we might have marked
- * some keys revoked above, but they might still be lingering
- * in our validated_keys list. */
- r = dns_transaction_invalidate_revoked_keys(t);
- if (r < 0)
- return r;
+ r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED);
+ if (r < 0)
+ return r;
- phase = PHASE_DNSKEY;
- for (;;) {
- bool changed = false, have_nsec = false;
+ /* Some of the DNSKEYs we just added might already have been revoked,
+ * remove them again in that case. */
+ r = dns_transaction_invalidate_revoked_keys(t);
+ if (r < 0)
+ return r;
+ }
- DNS_ANSWER_FOREACH(rr, t->answer) {
- DnsResourceRecord *rrsig = NULL;
- DnssecResult result;
+ /* Add the validated RRset to the new list of validated
+ * RRsets, and remove it from the unvalidated RRsets.
+ * We mark the RRset as authenticated and cacheable. */
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE);
+ if (r < 0)
+ return r;
- switch (rr->key->type) {
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key);
- case DNS_TYPE_RRSIG:
- continue;
+ /* Exit the loop, we dropped something from the answer, start from the beginning */
+ return 1;
+ }
- case DNS_TYPE_DNSKEY:
- /* We validate DNSKEYs only in the DNSKEY and ALL phases */
- if (phase == PHASE_NSEC)
- continue;
- break;
+ /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as
+ * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet,
+ * we cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */
+ if (phase != DNSSEC_PHASE_ALL)
+ continue;
- case DNS_TYPE_NSEC:
- case DNS_TYPE_NSEC3:
- have_nsec = true;
+ if (result == DNSSEC_VALIDATED_WILDCARD) {
+ bool authenticated = false;
+ const char *source;
- /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */
- if (phase == PHASE_DNSKEY)
- continue;
+ /* This RRset validated, but as a wildcard. This means we need
+ * to prove via NSEC/NSEC3 that no matching non-wildcard RR exists.*/
- break;
+ /* First step, determine the source of synthesis */
+ r = dns_resource_record_source(rrsig, &source);
+ if (r < 0)
+ return r;
- default:
- /* We validate all other RRs only in the ALL phases */
- if (phase != PHASE_ALL)
- continue;
+ r = dnssec_test_positive_wildcard(*validated,
+ dns_resource_key_name(rr->key),
+ source,
+ rrsig->rrsig.signer,
+ &authenticated);
- break;
+ /* Unless the NSEC proof showed that the key really doesn't exist something is off. */
+ if (r == 0)
+ result = DNSSEC_INVALID;
+ else {
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key,
+ authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0);
+ if (r < 0)
+ return r;
+
+ manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key);
+
+ /* Exit the loop, we dropped something from the answer, start from the beginning */
+ return 1;
}
+ }
- r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig);
+ if (result == DNSSEC_NO_SIGNATURE) {
+ r = dns_transaction_requires_rrsig(t, rr);
if (r < 0)
return r;
+ if (r == 0) {
+ /* Data does not require signing. In that case, just copy it over,
+ * but remember that this is by no means authenticated.*/
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
+ if (r < 0)
+ return r;
+
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
- log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result));
+ r = dns_transaction_known_signed(t, rr);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ /* This is an RR we know has to be signed. If it isn't this means
+ * the server is not attaching RRSIGs, hence complain. */
- if (result == DNSSEC_VALIDATED) {
+ dns_server_packet_rrsig_missing(t->server, t->current_feature_level);
- if (rr->key->type == DNS_TYPE_DNSKEY) {
- /* If we just validated a
- * DNSKEY RRset, then let's
- * add these keys to the set
- * of validated keys for this
- * transaction. */
+ if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) {
- r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED);
- if (r < 0)
- return r;
+ /* Downgrading is OK? If so, just consider the information unsigned */
- /* some of the DNSKEYs we just
- * added might already have
- * been revoked, remove them
- * again in that case. */
- r = dns_transaction_invalidate_revoked_keys(t);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
if (r < 0)
return r;
- }
- /* Add the validated RRset to the new
- * list of validated RRsets, and
- * remove it from the unvalidated
- * RRsets. We mark the RRset as
- * authenticated and cacheable. */
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE);
- if (r < 0)
- return r;
-
- manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key);
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
- /* Exit the loop, we dropped something from the answer, start from the beginning */
- changed = true;
- break;
+ /* Otherwise, fail */
+ t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
+ return 0;
}
- /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as
- * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet, we
- * cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */
- if (phase != PHASE_ALL)
- continue;
+ r = dns_transaction_in_private_tld(t, rr->key);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ char s[DNS_RESOURCE_KEY_STRING_MAX];
- if (result == DNSSEC_VALIDATED_WILDCARD) {
- bool authenticated = false;
- const char *source;
+ /* The data is from a TLD that is proven not to exist, and we are in downgrade
+ * mode, hence ignore the fact that this was not signed. */
- /* This RRset validated, but as a wildcard. This means we need to prove via NSEC/NSEC3
- * that no matching non-wildcard RR exists.*/
+ log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.",
+ dns_resource_key_to_string(rr->key, s, sizeof s));
- /* First step, determine the source of synthesis */
- r = dns_resource_record_source(rrsig, &source);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
if (r < 0)
return r;
- r = dnssec_test_positive_wildcard(
- validated,
- DNS_RESOURCE_KEY_NAME(rr->key),
- source,
- rrsig->rrsig.signer,
- &authenticated);
-
- /* Unless the NSEC proof showed that the key really doesn't exist something is off. */
- if (r == 0)
- result = DNSSEC_INVALID;
- else {
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0);
- if (r < 0)
- return r;
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
+ }
- manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key);
+ if (IN_SET(result,
+ DNSSEC_MISSING_KEY,
+ DNSSEC_SIGNATURE_EXPIRED,
+ DNSSEC_UNSUPPORTED_ALGORITHM)) {
- /* Exit the loop, we dropped something from the answer, start from the beginning */
- changed = true;
- break;
- }
- }
+ r = dns_transaction_dnskey_authenticated(t, rr);
+ if (r < 0 && r != -ENXIO)
+ return r;
+ if (r == 0) {
+ /* The DNSKEY transaction was not authenticated, this means there's
+ * no DS for this, which means it's OK if no keys are found for this signature. */
- if (result == DNSSEC_NO_SIGNATURE) {
- r = dns_transaction_requires_rrsig(t, rr);
+ r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0);
if (r < 0)
return r;
- if (r == 0) {
- /* Data does not require signing. In that case, just copy it over,
- * but remember that this is by no means authenticated.*/
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
+ return 1;
+ }
+ }
- r = dns_transaction_known_signed(t, rr);
+ r = dns_transaction_is_primary_response(t, rr);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ /* Look for a matching DNAME for this CNAME */
+ r = dns_answer_has_dname_for_cname(t->answer, rr);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* Also look among the stuff we already validated */
+ r = dns_answer_has_dname_for_cname(*validated, rr);
if (r < 0)
return r;
- if (r > 0) {
- /* This is an RR we know has to be signed. If it isn't this means
- * the server is not attaching RRSIGs, hence complain. */
-
- dns_server_packet_rrsig_missing(t->server, t->current_feature_level);
+ }
- if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) {
+ if (r == 0) {
+ if (IN_SET(result,
+ DNSSEC_INVALID,
+ DNSSEC_SIGNATURE_EXPIRED,
+ DNSSEC_NO_SIGNATURE))
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
+ else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
+ manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);
+
+ /* This is a primary response to our question, and it failed validation.
+ * That's fatal. */
+ t->answer_dnssec_result = result;
+ return 0;
+ }
- /* Downgrading is OK? If so, just consider the information unsigned */
+ /* This is a primary response, but we do have a DNAME RR
+ * in the RR that can replay this CNAME, hence rely on
+ * that, and we can remove the CNAME in favour of it. */
+ }
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
+ /* This is just some auxiliary data. Just remove the RRset and continue. */
+ r = dns_answer_remove_by_key(&t->answer, rr->key);
+ if (r < 0)
+ return r;
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
+ /* We dropped something from the answer, start from the beginning. */
+ return 1;
+ }
- /* Otherwise, fail */
- t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
- return 0;
- }
+ return 2; /* Finito. */
+}
- r = dns_transaction_in_private_tld(t, rr->key);
- if (r < 0)
- return r;
- if (r > 0) {
- _cleanup_free_ char *s = NULL;
+int dns_transaction_validate_dnssec(DnsTransaction *t) {
+ _cleanup_(dns_answer_unrefp) DnsAnswer *validated = NULL;
+ Phase phase;
+ DnsAnswerFlags flags;
+ int r;
+ char key_str[DNS_RESOURCE_KEY_STRING_MAX];
- /* The data is from a TLD that is proven not to exist, and we are in downgrade
- * mode, hence ignore the fact that this was not signed. */
+ assert(t);
- (void) dns_resource_key_to_string(rr->key, &s);
- log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", strna(s ? strstrip(s) : NULL));
+ /* We have now collected all DS and DNSKEY RRs in
+ * t->validated_keys, let's see which RRs we can now
+ * authenticate with that. */
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
+ if (t->scope->dnssec_mode == DNSSEC_NO)
+ return 0;
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
- }
+ /* Already validated */
+ if (t->answer_dnssec_result != _DNSSEC_RESULT_INVALID)
+ return 0;
- if (IN_SET(result,
- DNSSEC_MISSING_KEY,
- DNSSEC_SIGNATURE_EXPIRED,
- DNSSEC_UNSUPPORTED_ALGORITHM)) {
+ /* Our own stuff needs no validation */
+ if (IN_SET(t->answer_source, DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR)) {
+ t->answer_dnssec_result = DNSSEC_VALIDATED;
+ t->answer_authenticated = true;
+ return 0;
+ }
- r = dns_transaction_dnskey_authenticated(t, rr);
- if (r < 0 && r != -ENXIO)
- return r;
- if (r == 0) {
- /* The DNSKEY transaction was not authenticated, this means there's
- * no DS for this, which means it's OK if no keys are found for this signature. */
+ /* Cached stuff is not affected by validation. */
+ if (t->answer_source != DNS_TRANSACTION_NETWORK)
+ return 0;
- r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0);
- if (r < 0)
- return r;
+ if (!dns_transaction_dnssec_supported_full(t)) {
+ /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */
+ t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER;
+ log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id);
+ return 0;
+ }
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key);
- changed = true;
- break;
- }
- }
+ log_debug("Validating response from transaction %" PRIu16 " (%s).",
+ t->id,
+ dns_resource_key_to_string(t->key, key_str, sizeof key_str));
- r = dns_transaction_is_primary_response(t, rr);
- if (r < 0)
- return r;
- if (r > 0) {
+ /* First, see if this response contains any revoked trust
+ * anchors we care about */
+ r = dns_transaction_check_revoked_trust_anchors(t);
+ if (r < 0)
+ return r;
- /* Look for a matching DNAME for this CNAME */
- r = dns_answer_has_dname_for_cname(t->answer, rr);
- if (r < 0)
- return r;
- if (r == 0) {
- /* Also look among the stuff we already validated */
- r = dns_answer_has_dname_for_cname(validated, rr);
- if (r < 0)
- return r;
- }
+ /* Third, copy all RRs we acquired successfully from auxiliary RRs over. */
+ r = dns_transaction_copy_validated(t);
+ if (r < 0)
+ return r;
- if (r == 0) {
- if (IN_SET(result,
- DNSSEC_INVALID,
- DNSSEC_SIGNATURE_EXPIRED,
- DNSSEC_NO_SIGNATURE))
- manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key);
- else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */
- manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key);
-
- /* This is a primary response to our question, and it failed validation. That's
- * fatal. */
- t->answer_dnssec_result = result;
- return 0;
- }
+ /* Second, see if there are DNSKEYs we already know a
+ * validated DS for. */
+ r = dns_transaction_validate_dnskey_by_ds(t);
+ if (r < 0)
+ return r;
- /* This is a primary response, but we do have a DNAME RR in the RR that can replay this
- * CNAME, hence rely on that, and we can remove the CNAME in favour of it. */
- }
+ /* Fourth, remove all DNSKEY and DS RRs again that our trust
+ * anchor says are revoked. After all we might have marked
+ * some keys revoked above, but they might still be lingering
+ * in our validated_keys list. */
+ r = dns_transaction_invalidate_revoked_keys(t);
+ if (r < 0)
+ return r;
- /* This is just some auxiliary data. Just remove the RRset and continue. */
- r = dns_answer_remove_by_key(&t->answer, rr->key);
- if (r < 0)
- return r;
+ phase = DNSSEC_PHASE_DNSKEY;
+ for (;;) {
+ bool have_nsec = false;
- /* Exit the loop, we dropped something from the answer, start from the beginning */
- changed = true;
- break;
- }
+ r = dnssec_validate_records(t, phase, &have_nsec, &validated);
+ if (r <= 0)
+ return r;
- /* Restart the inner loop as long as we managed to achieve something */
- if (changed)
+ /* Try again as long as we managed to achieve something */
+ if (r == 1)
continue;
- if (phase == PHASE_DNSKEY && have_nsec) {
+ if (phase == DNSSEC_PHASE_DNSKEY && have_nsec) {
/* OK, we processed all DNSKEYs, and there are NSEC/NSEC3 RRs, look at those now. */
- phase = PHASE_NSEC;
+ phase = DNSSEC_PHASE_NSEC;
continue;
}
- if (phase != PHASE_ALL) {
- /* OK, we processed all DNSKEYs and NSEC/NSEC3 RRs, look at all the rest now. Note that in this
- * third phase we start to remove RRs we couldn't validate. */
- phase = PHASE_ALL;
+ if (phase != DNSSEC_PHASE_ALL) {
+ /* OK, we processed all DNSKEYs and NSEC/NSEC3 RRs, look at all the rest now.
+ * Note that in this third phase we start to remove RRs we couldn't validate. */
+ phase = DNSSEC_PHASE_ALL;
continue;
}
@@ -2921,7 +2954,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
case DNSSEC_NSEC_NXDOMAIN:
/* NSEC proves the domain doesn't exist. Very good. */
- log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t));
+ log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str);
t->answer_dnssec_result = DNSSEC_VALIDATED;
t->answer_rcode = DNS_RCODE_NXDOMAIN;
t->answer_authenticated = authenticated;
@@ -2931,7 +2964,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
case DNSSEC_NSEC_NODATA:
/* NSEC proves that there's no data here, very good. */
- log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t));
+ log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str);
t->answer_dnssec_result = DNSSEC_VALIDATED;
t->answer_rcode = DNS_RCODE_SUCCESS;
t->answer_authenticated = authenticated;
@@ -2941,7 +2974,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
case DNSSEC_NSEC_OPTOUT:
/* NSEC3 says the data might not be signed */
- log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t));
+ log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str);
t->answer_dnssec_result = DNSSEC_UNSIGNED;
t->answer_authenticated = false;
@@ -2986,17 +3019,6 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
return 1;
}
-const char *dns_transaction_key_string(DnsTransaction *t) {
- assert(t);
-
- if (!t->key_string) {
- if (dns_resource_key_to_string(t->key, &t->key_string) < 0)
- return "n/a";
- }
-
- return strstrip(t->key_string);
-}
-
static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = {
[DNS_TRANSACTION_NULL] = "null",
[DNS_TRANSACTION_PENDING] = "pending",
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h
index 4617194711..eaece91533 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-transaction.h
@@ -64,7 +64,6 @@ struct DnsTransaction {
DnsScope *scope;
DnsResourceKey *key;
- char *key_string;
DnsTransactionState state;
@@ -119,17 +118,17 @@ struct DnsTransaction {
/* Query candidates this transaction is referenced by and that
* shall be notified about this specific transaction
* completing. */
- Set *notify_query_candidates;
+ Set *notify_query_candidates, *notify_query_candidates_done;
/* Zone items this transaction is referenced by and that shall
* be notified about completion. */
- Set *notify_zone_items;
+ Set *notify_zone_items, *notify_zone_items_done;
/* Other transactions that this transactions is referenced by
* and that shall be notified about completion. This is used
* when transactions want to validate their RRsets, but need
* another DNSKEY or DS RR to do so. */
- Set *notify_transactions;
+ Set *notify_transactions, *notify_transactions_done;
/* The opposite direction: the transactions this transaction
* created in order to request DNSKEY or DS RRs. */
@@ -153,8 +152,6 @@ void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source);
int dns_transaction_validate_dnssec(DnsTransaction *t);
int dns_transaction_request_dnssec_keys(DnsTransaction *t);
-const char *dns_transaction_key_string(DnsTransaction *t);
-
const char* dns_transaction_state_to_string(DnsTransactionState p) _const_;
DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_;
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c b/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c
index a75337eb6a..77370e7dd5 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-trust-anchor.c
@@ -651,7 +651,7 @@ static int dns_trust_anchor_check_revoked_one(DnsTrustAnchor *d, DnsResourceReco
}
}
- a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(revoked_dnskey->key)));
+ a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, dns_resource_key_name(revoked_dnskey->key)));
if (a) {
DnsResourceRecord *anchor;
@@ -698,7 +698,7 @@ int dns_trust_anchor_check_revoked(DnsTrustAnchor *d, DnsResourceRecord *dnskey,
/* Could this be interesting to us at all? If not,
* there's no point in looking for and verifying a
* self-signed RRSIG. */
- if (!dns_trust_anchor_knows_domain_positive(d, DNS_RESOURCE_KEY_NAME(dnskey->key)))
+ if (!dns_trust_anchor_knows_domain_positive(d, dns_resource_key_name(dnskey->key)))
return 0;
/* Look for a self-signed RRSIG in the other rrs belonging to this DNSKEY */
diff --git a/src/grp-resolve/systemd-resolved/resolved-dns-zone.c b/src/grp-resolve/systemd-resolved/resolved-dns-zone.c
index f52383cfd1..850eed8cb8 100644
--- a/src/grp-resolve/systemd-resolved/resolved-dns-zone.c
+++ b/src/grp-resolve/systemd-resolved/resolved-dns-zone.c
@@ -38,6 +38,7 @@ void dns_zone_item_probe_stop(DnsZoneItem *i) {
i->probe_transaction = NULL;
set_remove(t->notify_zone_items, i);
+ set_remove(t->notify_zone_items_done, i);
dns_transaction_gc(t);
}
@@ -68,12 +69,12 @@ static void dns_zone_item_remove_and_free(DnsZone *z, DnsZoneItem *i) {
else
hashmap_remove(z->by_key, i->rr->key);
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
LIST_REMOVE(by_name, first, i);
if (first)
- assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0);
+ assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
else
- hashmap_remove(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ hashmap_remove(z->by_name, dns_resource_key_name(i->rr->key));
dns_zone_item_free(i);
}
@@ -147,12 +148,12 @@ static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) {
return r;
}
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(i->rr->key));
if (first) {
LIST_PREPEND(by_name, first, i);
- assert_se(hashmap_replace(z->by_name, DNS_RESOURCE_KEY_NAME(first->rr->key), first) >= 0);
+ assert_se(hashmap_replace(z->by_name, dns_resource_key_name(first->rr->key), first) >= 0);
} else {
- r = hashmap_put(z->by_name, DNS_RESOURCE_KEY_NAME(i->rr->key), i);
+ r = hashmap_put(z->by_name, dns_resource_key_name(i->rr->key), i);
if (r < 0)
return r;
}
@@ -169,11 +170,11 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
if (i->probe_transaction)
return 0;
- t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)), false);
+ t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), false);
if (!t) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
- key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key));
+ key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key));
if (!key)
return -ENOMEM;
@@ -186,6 +187,10 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) {
if (r < 0)
goto gc;
+ r = set_ensure_allocated(&t->notify_zone_items_done, NULL);
+ if (r < 0)
+ goto gc;
+
r = set_put(t->notify_zone_items, i);
if (r < 0)
goto gc;
@@ -303,7 +308,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
* go through the list by the name and look
* for everything manually */
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -339,7 +344,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
}
if (!found) {
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -370,7 +375,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
bool found = false, added = false;
int k;
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -393,7 +398,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
}
if (found && !added) {
- r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL);
+ r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL);
if (r < 0)
return r;
}
@@ -418,7 +423,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
if (!found) {
bool add_soa = false;
- first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(z->by_name, dns_resource_key_name(key));
LIST_FOREACH(by_name, j, first) {
if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING))
continue;
@@ -430,7 +435,7 @@ int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, Dns
}
if (add_soa) {
- r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL);
+ r = dns_answer_add_soa(soa, dns_resource_key_name(key), LLMNR_DEFAULT_TTL);
if (r < 0)
return r;
}
@@ -482,7 +487,7 @@ void dns_zone_item_conflict(DnsZoneItem *i) {
i->state = DNS_ZONE_ITEM_WITHDRAWN;
/* Maybe change the hostname */
- if (manager_is_own_hostname(i->scope->manager, DNS_RESOURCE_KEY_NAME(i->rr->key)) > 0)
+ if (manager_is_own_hostname(i->scope->manager, dns_resource_key_name(i->rr->key)) > 0)
manager_next_hostname(i->scope->manager);
}
@@ -562,7 +567,7 @@ int dns_zone_check_conflicts(DnsZone *zone, DnsResourceRecord *rr) {
* so, we'll verify our RRs. */
/* No conflict if we don't have the name at all. */
- first = hashmap_get(zone->by_name, DNS_RESOURCE_KEY_NAME(rr->key));
+ first = hashmap_get(zone->by_name, dns_resource_key_name(rr->key));
if (!first)
return 0;
@@ -593,7 +598,7 @@ int dns_zone_verify_conflicts(DnsZone *zone, DnsResourceKey *key) {
/* Somebody else notified us about a possible conflict. Let's
* verify if that's true. */
- first = hashmap_get(zone->by_name, DNS_RESOURCE_KEY_NAME(key));
+ first = hashmap_get(zone->by_name, dns_resource_key_name(key));
if (!first)
return 0;
diff --git a/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c b/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c
index ee82c96822..40d650949d 100644
--- a/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c
+++ b/src/grp-resolve/systemd-resolved/resolved-etc-hosts.c
@@ -301,7 +301,7 @@ int manager_etc_hosts_read(Manager *m) {
FOREACH_LINE(line, f, return log_error_errno(errno, "Failed to read /etc/hosts: %m")) {
char *l;
- nr ++;
+ nr++;
l = strstrip(line);
if (isempty(l))
@@ -363,7 +363,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY))
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name);
+ r = dns_name_equal(dns_resource_key_name(t), name);
if (r < 0)
return r;
if (r > 0) {
@@ -413,7 +413,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) {
if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY))
continue;
- r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name);
+ r = dns_name_equal(dns_resource_key_name(t), name);
if (r < 0)
return r;
if (r == 0)
diff --git a/src/grp-resolve/systemd-resolved/resolved-link-bus.c b/src/grp-resolve/systemd-resolved/resolved-link-bus.c
index df7516f4f4..7f21891819 100644
--- a/src/grp-resolve/systemd-resolved/resolved-link-bus.c
+++ b/src/grp-resolve/systemd-resolved/resolved-link-bus.c
@@ -239,7 +239,7 @@ clear:
return r;
}
-int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Link *l = userdata;
int r;
@@ -457,10 +457,10 @@ const sd_bus_vtable link_vtable[] = {
SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0),
SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0),
SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
- SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0),
+ SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
- SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0),
+ SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0),
SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
diff --git a/src/grp-resolve/systemd-resolved/resolved-link-bus.h b/src/grp-resolve/systemd-resolved/resolved-link-bus.h
index 5a8ee08ec7..b1ac57961d 100644
--- a/src/grp-resolve/systemd-resolved/resolved-link-bus.h
+++ b/src/grp-resolve/systemd-resolved/resolved-link-bus.h
@@ -30,7 +30,7 @@ char *link_bus_path(Link *link);
int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/grp-resolve/systemd-resolved/resolved-link.c b/src/grp-resolve/systemd-resolved/resolved-link.c
index 65df95bb1f..4eef20599a 100644
--- a/src/grp-resolve/systemd-resolved/resolved-link.c
+++ b/src/grp-resolve/systemd-resolved/resolved-link.c
@@ -468,7 +468,7 @@ static void link_read_settings(Link *l) {
}
if (r > 0) {
- /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */
+ /* If this link used to be managed, but is now unmanaged, flush all our settings — but only once. */
if (l->is_managed)
link_flush_settings(l);
diff --git a/src/grp-resolve/systemd-resolved/resolved-llmnr.c b/src/grp-resolve/systemd-resolved/resolved-llmnr.c
index ef12abfbb5..8b1d71a3eb 100644
--- a/src/grp-resolve/systemd-resolved/resolved-llmnr.c
+++ b/src/grp-resolve/systemd-resolved/resolved-llmnr.c
@@ -286,7 +286,7 @@ static int on_llmnr_stream_packet(DnsStream *s) {
scope = manager_find_scope(s->manager, s->read_packet);
if (!scope) {
- log_warning("Got LLMNR TCP packet on unknown scope. Ignroing.");
+ log_warning("Got LLMNR TCP packet on unknown scope. Ignoring.");
return 0;
}
diff --git a/src/grp-resolve/systemd-resolved/resolved-manager.c b/src/grp-resolve/systemd-resolved/resolved-manager.c
index e82c6ec563..7166b94d71 100644
--- a/src/grp-resolve/systemd-resolved/resolved-manager.c
+++ b/src/grp-resolve/systemd-resolved/resolved-manager.c
@@ -485,7 +485,7 @@ int manager_new(Manager **ret) {
m->llmnr_support = RESOLVE_SUPPORT_YES;
m->mdns_support = RESOLVE_SUPPORT_NO;
- m->dnssec_mode = DNSSEC_NO;
+ m->dnssec_mode = DEFAULT_DNSSEC_MODE;
m->read_resolv_conf = true;
m->need_builtin_fallbacks = true;
m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY;
@@ -1213,11 +1213,11 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource
assert(verdict < _DNSSEC_VERDICT_MAX);
if (log_get_max_level() >= LOG_DEBUG) {
- _cleanup_free_ char *s = NULL;
+ char s[DNS_RESOURCE_KEY_STRING_MAX];
- (void) dns_resource_key_to_string(key, &s);
-
- log_debug("Found verdict for lookup %s: %s", s ? strstrip(s) : "n/a", dnssec_verdict_to_string(verdict));
+ log_debug("Found verdict for lookup %s: %s",
+ dns_resource_key_to_string(key, s, sizeof s),
+ dnssec_verdict_to_string(verdict));
}
m->n_dnssec_verdict[verdict]++;
diff --git a/src/grp-resolve/systemd-resolved/resolved-mdns.c b/src/grp-resolve/systemd-resolved/resolved-mdns.c
index bc8b8b809b..b13b1d0144 100644
--- a/src/grp-resolve/systemd-resolved/resolved-mdns.c
+++ b/src/grp-resolve/systemd-resolved/resolved-mdns.c
@@ -106,7 +106,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us
dns_scope_check_conflicts(scope, p);
DNS_ANSWER_FOREACH(rr, p->answer) {
- const char *name = DNS_RESOURCE_KEY_NAME(rr->key);
+ const char *name = dns_resource_key_name(rr->key);
DnsTransaction *t;
/* If the received reply packet contains ANY record that is not .local or .in-addr.arpa,
diff --git a/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c b/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c
index 065427b690..ff03acc772 100644
--- a/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c
+++ b/src/grp-resolve/systemd-resolved/resolved-resolv-conf.c
@@ -158,7 +158,7 @@ static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) {
if (*count == MAXNS)
fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f);
- (*count) ++;
+ (*count)++;
fprintf(f, "nameserver %s\n", s->server_string);
}
@@ -184,7 +184,7 @@ static void write_resolv_conf_search(
}
(*length) += strlen(domain);
- (*count) ++;
+ (*count)++;
fputc(' ', f);
fputs(domain, f);
diff --git a/src/grp-resolve/systemd-resolved/resolved.c b/src/grp-resolve/systemd-resolved/resolved.c
index 07e6bfb54a..086a2fcac7 100644
--- a/src/grp-resolve/systemd-resolved/resolved.c
+++ b/src/grp-resolve/systemd-resolved/resolved.c
@@ -48,7 +48,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- r = mac_selinux_init(NULL);
+ r = mac_selinux_init();
if (r < 0) {
log_error_errno(r, "SELinux setup failed: %m");
goto finish;
diff --git a/src/grp-resolve/systemd-resolved/resolved.conf.in b/src/grp-resolve/systemd-resolved/resolved.conf.in
index efc9c6733a..a288588924 100644
--- a/src/grp-resolve/systemd-resolved/resolved.conf.in
+++ b/src/grp-resolve/systemd-resolved/resolved.conf.in
@@ -16,4 +16,4 @@
#FallbackDNS=@DNS_SERVERS@
#Domains=
#LLMNR=yes
-#DNSSEC=no
+#DNSSEC=@DEFAULT_DNSSEC_MODE@
diff --git a/src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pkts
new file mode 100644
index 0000000000..a383c6286d
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/_443._tcp.fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pkts
new file mode 100644
index 0000000000..15de02e997
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/_openpgpkey.fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/fake-caa.pkts b/src/grp-resolve/systemd-resolved/test-data/fake-caa.pkts
new file mode 100644
index 0000000000..1c3ecc5491
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/fake-caa.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pkts
new file mode 100644
index 0000000000..17874844d9
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/gandi.net.pkts b/src/grp-resolve/systemd-resolved/test-data/gandi.net.pkts
new file mode 100644
index 0000000000..5ef51e0c8e
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/gandi.net.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/google.com.pkts b/src/grp-resolve/systemd-resolved/test-data/google.com.pkts
new file mode 100644
index 0000000000..f98c4cd855
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/google.com.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pkts b/src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pkts
new file mode 100644
index 0000000000..e28a725c9a
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/kyhwana.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/root.pkts b/src/grp-resolve/systemd-resolved/test-data/root.pkts
new file mode 100644
index 0000000000..54ba668c75
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/root.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts b/src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts
new file mode 100644
index 0000000000..a854249532
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/sw1a1aa-sw1a2aa-sw1a2ab-sw1a2ac.find.me.uk.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/teamits.com.pkts b/src/grp-resolve/systemd-resolved/test-data/teamits.com.pkts
new file mode 100644
index 0000000000..11deb39677
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/teamits.com.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pkts b/src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pkts
new file mode 100644
index 0000000000..f0a6f982df
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-data/zbyszek@fedoraproject.org.pkts
Binary files differ
diff --git a/src/grp-resolve/systemd-resolved/test-dns-packet.c b/src/grp-resolve/systemd-resolved/test-dns-packet.c
new file mode 100644
index 0000000000..c232a69ce1
--- /dev/null
+++ b/src/grp-resolve/systemd-resolved/test-dns-packet.c
@@ -0,0 +1,114 @@
+/***
+ This file is part of systemd
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <net/if.h>
+#include <glob.h>
+
+#include "alloc-util.h"
+#include "fileio.h"
+#include "glob-util.h"
+#include "log.h"
+#include "macro.h"
+#include "resolved-dns-packet.h"
+#include "resolved-dns-rr.h"
+#include "string-util.h"
+#include "strv.h"
+
+#define HASH_KEY SD_ID128_MAKE(d3,1e,48,90,4b,fa,4c,fe,af,9d,d5,a1,d7,2e,8a,b1)
+
+static uint64_t hash(DnsResourceRecord *rr) {
+ struct siphash state;
+
+ siphash24_init(&state, HASH_KEY.bytes);
+ dns_resource_record_hash_func(rr, &state);
+ return siphash24_finalize(&state);
+}
+
+static void test_packet_from_file(const char* filename, bool canonical) {
+ _cleanup_free_ char *data = NULL;
+ size_t data_size, packet_size, offset;
+
+ assert_se(read_full_file(filename, &data, &data_size) >= 0);
+ assert_se(data);
+ assert_se(data_size > 8);
+
+ log_info("============== %s %s==============", filename, canonical ? "canonical " : "");
+
+ for (offset = 0; offset < data_size; offset += 8 + packet_size) {
+ _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL, *p2 = NULL;
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL, *rr2 = NULL;
+ const char *s, *s2;
+ uint64_t hash1, hash2;
+
+ packet_size = le64toh( *(uint64_t*)(data + offset) );
+ assert_se(packet_size > 0);
+ assert_se(offset + 8 + packet_size <= data_size);
+
+ assert_se(dns_packet_new(&p, DNS_PROTOCOL_DNS, 0) >= 0);
+
+ assert_se(dns_packet_append_blob(p, data + offset + 8, packet_size, NULL) >= 0);
+ assert_se(dns_packet_read_rr(p, &rr, NULL, NULL) >= 0);
+
+ s = dns_resource_record_to_string(rr);
+ assert_se(s);
+ puts(s);
+
+ hash1 = hash(rr);
+
+ assert_se(dns_resource_record_to_wire_format(rr, canonical) >= 0);
+
+ assert_se(dns_packet_new(&p2, DNS_PROTOCOL_DNS, 0) >= 0);
+ assert_se(dns_packet_append_blob(p2, rr->wire_format, rr->wire_format_size, NULL) >= 0);
+ assert_se(dns_packet_read_rr(p2, &rr2, NULL, NULL) >= 0);
+
+ s2 = dns_resource_record_to_string(rr);
+ assert_se(s2);
+ assert_se(streq(s, s2));
+
+ hash2 = hash(rr);
+ assert_se(hash1 == hash2);
+ }
+}
+
+int main(int argc, char **argv) {
+ int i, N;
+ _cleanup_globfree_ glob_t g = {};
+ char **fnames;
+
+ log_parse_environment();
+
+ if (argc >= 2) {
+ N = argc - 1;
+ fnames = argv + 1;
+ } else {
+ assert_se(glob(RESOLVE_TEST_DIR "/*.pkts", GLOB_NOSORT, NULL, &g) == 0);
+ N = g.gl_pathc;
+ fnames = g.gl_pathv;
+ }
+
+ for (i = 0; i < N; i++) {
+ test_packet_from_file(fnames[i], false);
+ puts("");
+ test_packet_from_file(fnames[i], true);
+ if (i + 1 < N)
+ puts("");
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/grp-resolve/systemd-resolved/test-dnssec.c b/src/grp-resolve/systemd-resolved/test-dnssec.c
index a093d86a91..b3018e8239 100644
--- a/src/grp-resolve/systemd-resolved/test-dnssec.c
+++ b/src/grp-resolve/systemd-resolved/test-dnssec.c
@@ -27,77 +27,89 @@
#include "string-util.h"
#include "hexdecoct.h"
-static void test_dnssec_verify_rrset2(void) {
+static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
+ char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
- static const uint8_t signature_blob[] = {
- 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
- 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
- 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
- 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
- 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
- 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
- 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
- 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
- };
+ assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
+ if (r < 0)
+ return;
+
+ assert_se(streq(canonicalized, canonical));
+}
+static void test_dnssec_canonicalize(void) {
+ test_dnssec_canonicalize_one("", ".", 1);
+ test_dnssec_canonicalize_one(".", ".", 1);
+ test_dnssec_canonicalize_one("foo", "foo.", 4);
+ test_dnssec_canonicalize_one("foo.", "foo.", 4);
+ test_dnssec_canonicalize_one("FOO.", "foo.", 4);
+ test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
+ test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
+}
+
+#ifdef HAVE_GCRYPT
+
+static void test_dnssec_verify_dns_key(void) {
+
+ static const uint8_t ds1_fprint[] = {
+ 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
+ 0x80, 0x67, 0x14, 0x01,
+ };
+ static const uint8_t ds2_fprint[] = {
+ 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
+ 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
+ };
static const uint8_t dnskey_blob[] = {
- 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
- 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
- 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
- 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
- 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
- 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
- 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
- 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
- 0x74, 0x62, 0xfe, 0xd7,
+ 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
+ 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
+ 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
+ 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
+ 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
+ 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
+ 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
+ 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
+ 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
+ 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
+ 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
+ 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
+ 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
+ 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
+ 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
+ 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
+ 0xe7, 0xea, 0x77, 0x03,
};
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
- _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
- DnssecResult result;
-
- nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
- assert_se(nsec);
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
- nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
- assert_se(nsec->nsec.next_domain_name);
+ /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
+ ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
+ assert_se(ds1);
- nsec->nsec.types = bitmap_new();
- assert_se(nsec->nsec.types);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
- assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
+ ds1->ds.key_tag = 47857;
+ ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
+ ds1->ds.digest_size = sizeof(ds1_fprint);
+ ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
+ assert_se(ds1->ds.digest);
- log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
+ log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
- rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
- assert_se(rrsig);
+ ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
+ assert_se(ds2);
- rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
- rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- rrsig->rrsig.labels = 2;
- rrsig->rrsig.original_ttl = 300;
- rrsig->rrsig.expiration = 0x5689002f;
- rrsig->rrsig.inception = 0x56617230;
- rrsig->rrsig.key_tag = 30390;
- rrsig->rrsig.signer = strdup("Nasa.Gov.");
- assert_se(rrsig->rrsig.signer);
- rrsig->rrsig.signature_size = sizeof(signature_blob);
- rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
- assert_se(rrsig->rrsig.signature);
+ ds2->ds.key_tag = 47857;
+ ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
+ ds2->ds.digest_size = sizeof(ds2_fprint);
+ ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
+ assert_se(ds2->ds.digest);
- log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
+ log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
- dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
+ dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
assert_se(dnskey);
- dnskey->dnskey.flags = 256;
+ dnskey->dnskey.flags = 257;
dnskey->dnskey.protocol = 3;
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
dnskey->dnskey.key_size = sizeof(dnskey_blob);
@@ -107,16 +119,8 @@ static void test_dnssec_verify_rrset2(void) {
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
- assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
- assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
-
- answer = dns_answer_new(1);
- assert_se(answer);
- assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
-
- /* Validate the RR as it if was 2015-12-11 today */
- assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
- assert_se(result == DNSSEC_VALIDATED);
+ assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
+ assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
}
static void test_dnssec_verify_rrset(void) {
@@ -198,67 +202,77 @@ static void test_dnssec_verify_rrset(void) {
assert_se(result == DNSSEC_VALIDATED);
}
-static void test_dnssec_verify_dns_key(void) {
+static void test_dnssec_verify_rrset2(void) {
- static const uint8_t ds1_fprint[] = {
- 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D,
- 0x80, 0x67, 0x14, 0x01,
- };
- static const uint8_t ds2_fprint[] = {
- 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE,
- 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98,
+ static const uint8_t signature_blob[] = {
+ 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11,
+ 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b,
+ 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca,
+ 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2,
+ 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda,
+ 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27,
+ 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50,
+ 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22,
};
+
static const uint8_t dnskey_blob[] = {
- 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e,
- 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc,
- 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48,
- 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49,
- 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde,
- 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe,
- 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf,
- 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45,
- 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77,
- 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39,
- 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d,
- 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68,
- 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39,
- 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4,
- 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba,
- 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73,
- 0xe7, 0xea, 0x77, 0x03,
+ 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea,
+ 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3,
+ 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07,
+ 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5,
+ 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7,
+ 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56,
+ 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e,
+ 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49,
+ 0x74, 0x62, 0xfe, 0xd7,
};
- _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL;
+ _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL;
+ _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
+ DnssecResult result;
- /* The two DS RRs in effect for nasa.gov on 2015-12-01. */
- ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov");
- assert_se(ds1);
+ nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov");
+ assert_se(nsec);
- ds1->ds.key_tag = 47857;
- ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- ds1->ds.digest_type = DNSSEC_DIGEST_SHA1;
- ds1->ds.digest_size = sizeof(ds1_fprint);
- ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size);
- assert_se(ds1->ds.digest);
+ nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov");
+ assert_se(nsec->nsec.next_domain_name);
- log_info("DS1: %s", strna(dns_resource_record_to_string(ds1)));
+ nsec->nsec.types = bitmap_new();
+ assert_se(nsec->nsec.types);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0);
+ assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0);
- ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV");
- assert_se(ds2);
+ log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec)));
- ds2->ds.key_tag = 47857;
- ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256;
- ds2->ds.digest_type = DNSSEC_DIGEST_SHA256;
- ds2->ds.digest_size = sizeof(ds2_fprint);
- ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size);
- assert_se(ds2->ds.digest);
+ rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV.");
+ assert_se(rrsig);
- log_info("DS2: %s", strna(dns_resource_record_to_string(ds2)));
+ rrsig->rrsig.type_covered = DNS_TYPE_NSEC;
+ rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256;
+ rrsig->rrsig.labels = 2;
+ rrsig->rrsig.original_ttl = 300;
+ rrsig->rrsig.expiration = 0x5689002f;
+ rrsig->rrsig.inception = 0x56617230;
+ rrsig->rrsig.key_tag = 30390;
+ rrsig->rrsig.signer = strdup("Nasa.Gov.");
+ assert_se(rrsig->rrsig.signer);
+ rrsig->rrsig.signature_size = sizeof(signature_blob);
+ rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size);
+ assert_se(rrsig->rrsig.signature);
- dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV");
+ log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig)));
+
+ dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV");
assert_se(dnskey);
- dnskey->dnskey.flags = 257;
+ dnskey->dnskey.flags = 256;
dnskey->dnskey.protocol = 3;
dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256;
dnskey->dnskey.key_size = sizeof(dnskey_blob);
@@ -268,28 +282,16 @@ static void test_dnssec_verify_dns_key(void) {
log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey)));
log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false));
- assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0);
- assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0);
-}
-
-static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) {
- char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX];
-
- assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r);
- if (r < 0)
- return;
+ assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0);
+ assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0);
- assert_se(streq(canonicalized, canonical));
-}
+ answer = dns_answer_new(1);
+ assert_se(answer);
+ assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0);
-static void test_dnssec_canonicalize(void) {
- test_dnssec_canonicalize_one("", ".", 1);
- test_dnssec_canonicalize_one(".", ".", 1);
- test_dnssec_canonicalize_one("foo", "foo.", 4);
- test_dnssec_canonicalize_one("foo.", "foo.", 4);
- test_dnssec_canonicalize_one("FOO.", "foo.", 4);
- test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8);
- test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL);
+ /* Validate the RR as it if was 2015-12-11 today */
+ assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0);
+ assert_se(result == DNSSEC_VALIDATED);
}
static void test_dnssec_nsec3_hash(void) {
@@ -324,13 +326,18 @@ static void test_dnssec_nsec3_hash(void) {
assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0);
}
+#endif
+
int main(int argc, char*argv[]) {
test_dnssec_canonicalize();
+
+#ifdef HAVE_GCRYPT
test_dnssec_verify_dns_key();
test_dnssec_verify_rrset();
test_dnssec_verify_rrset2();
test_dnssec_nsec3_hash();
+#endif
return 0;
}
diff --git a/src/grp-resolve/systemd-resolved/test-resolve-tables.c b/src/grp-resolve/systemd-resolved/test-resolve-tables.c
index 63660afc87..2d615130e1 100644
--- a/src/grp-resolve/systemd-resolved/test-resolve-tables.c
+++ b/src/grp-resolve/systemd-resolved/test-resolve-tables.c
@@ -21,7 +21,44 @@
#include "test-tables.h"
int main(int argc, char **argv) {
+ uint16_t i;
+
test_table_sparse(dns_type, DNS_TYPE);
+ log_info("/* DNS_TYPE */");
+ for (i = 0; i < _DNS_TYPE_MAX; i++) {
+ const char *s;
+
+ s = dns_type_to_string(i);
+ assert_se(s == NULL || strlen(s) < _DNS_TYPE_STRING_MAX);
+
+ if (s)
+ log_info("%-*s %s%s%s%s%s%s%s%s%s",
+ (int) _DNS_TYPE_STRING_MAX - 1, s,
+ dns_type_is_pseudo(i) ? "pseudo " : "",
+ dns_type_is_valid_query(i) ? "valid_query " : "",
+ dns_type_is_valid_rr(i) ? "is_valid_rr " : "",
+ dns_type_may_redirect(i) ? "may_redirect " : "",
+ dns_type_is_dnssec(i) ? "dnssec " : "",
+ dns_type_is_obsolete(i) ? "obsolete " : "",
+ dns_type_may_wildcard(i) ? "wildcard " : "",
+ dns_type_apex_only(i) ? "apex_only " : "",
+ dns_type_needs_authentication(i) ? "needs_authentication" : "");
+ }
+
+ log_info("/* DNS_CLASS */");
+ for (i = 0; i < _DNS_CLASS_MAX; i++) {
+ const char *s;
+
+ s = dns_class_to_string(i);
+ assert_se(s == NULL || strlen(s) < _DNS_CLASS_STRING_MAX);
+
+ if (s)
+ log_info("%-*s %s%s",
+ (int) _DNS_CLASS_STRING_MAX - 1, s,
+ dns_class_is_pseudo(i) ? "is_pseudo " : "",
+ dns_class_is_valid_rr(i) ? "is_valid_rr " : "");
+ }
+
return EXIT_SUCCESS;
}
diff --git a/src/grp-system/systemctl/systemctl.c b/src/grp-system/systemctl/systemctl.c
index c03fca06c8..c7c00bbbc3 100644
--- a/src/grp-system/systemctl/systemctl.c
+++ b/src/grp-system/systemctl/systemctl.c
@@ -39,6 +39,7 @@
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-message.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
@@ -101,8 +102,10 @@ static bool arg_no_block = false;
static bool arg_no_legend = false;
static bool arg_no_pager = false;
static bool arg_no_wtmp = false;
+static bool arg_no_sync = false;
static bool arg_no_wall = false;
static bool arg_no_reload = false;
+static bool arg_value = false;
static bool arg_show_types = false;
static bool arg_ignore_inhibitors = false;
static bool arg_dry = false;
@@ -152,7 +155,7 @@ static bool arg_now = false;
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 int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state);
static bool original_stdout_is_tty;
@@ -200,14 +203,6 @@ static void release_busses(void) {
busses[w] = sd_bus_flush_close_unref(busses[w]);
}
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
static void ask_password_agent_open_if_enabled(void) {
/* Open the password agent as a child process if necessary */
@@ -331,6 +326,8 @@ static int compare_unit_info(const void *a, const void *b) {
}
static bool output_show_unit(const UnitInfo *u, char **patterns) {
+ assert(u);
+
if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
return false;
@@ -348,10 +345,21 @@ static bool output_show_unit(const UnitInfo *u, char **patterns) {
if (arg_all)
return true;
+ /* Note that '--all' is not purely a state filter, but also a
+ * filter that hides units that "follow" other units (which is
+ * used for device units that appear under different names). */
+ if (!isempty(u->following))
+ return false;
+
+ if (!strv_isempty(arg_states))
+ return true;
+
+ /* By default show all units except the ones in inactive
+ * state and with no pending job */
if (u->job_id > 0)
return true;
- if (streq(u->active_state, "inactive") || u->following[0])
+ if (streq(u->active_state, "inactive"))
return false;
return true;
@@ -476,7 +484,7 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) {
}
if (circle_len > 0)
- printf("%s%s%s ", on_circle, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_circle);
+ printf("%s%s%s ", on_circle, circle ? special_glyph(BLACK_CIRCLE) : " ", off_circle);
printf("%s%-*s%s %s%-*s%s %s%-*s %-*s%s %-*s",
on_active, id_len, id, off_active,
@@ -534,6 +542,7 @@ static int get_unit_list(
size_t size = c;
int r;
UnitInfo u;
+ bool fallback = false;
assert(bus);
assert(unit_infos);
@@ -545,8 +554,7 @@ static int get_unit_list(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "ListUnitsFiltered");
-
+ "ListUnitsByPatterns");
if (r < 0)
return bus_log_create_error(r);
@@ -554,7 +562,34 @@ static int get_unit_list(
if (r < 0)
return bus_log_create_error(r);
+ r = sd_bus_message_append_strv(m, patterns);
+ if (r < 0)
+ return bus_log_create_error(r);
+
r = sd_bus_call(bus, m, 0, &error, &reply);
+ if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+ /* Fallback to legacy ListUnitsFiltered method */
+ fallback = true;
+ log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
+ m = sd_bus_message_unref(m);
+ sd_bus_error_free(&error);
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListUnitsFiltered");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_strv(m, arg_states);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, 0, &error, &reply);
+ }
if (r < 0)
return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
@@ -565,7 +600,7 @@ static int get_unit_list(
while ((r = bus_parse_unit_info(reply, &u)) > 0) {
u.machine = machine;
- if (!output_show_unit(&u, patterns))
+ if (!output_show_unit(&u, fallback ? patterns : NULL))
continue;
if (!GREEDY_REALLOC(*unit_infos, size, c+1))
@@ -678,7 +713,7 @@ static int list_units(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -890,7 +925,7 @@ static int list_sockets(int argc, char *argv[], void *userdata) {
int r = 0, n;
sd_bus *bus;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -1197,7 +1232,7 @@ static int list_timers(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r = 0;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -1275,7 +1310,9 @@ static int compare_unit_file_list(const void *a, const void *b) {
return strcasecmp(basename(u->path), basename(v->path));
}
-static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
+static bool output_show_unit_file(const UnitFileList *u, char **states, char **patterns) {
+ assert(u);
+
if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
return false;
@@ -1290,8 +1327,8 @@ static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
return false;
}
- if (!strv_isempty(arg_states) &&
- !strv_find(arg_states, unit_file_state_to_string(u->state)))
+ if (!strv_isempty(states) &&
+ !strv_find(states, unit_file_state_to_string(u->state)))
return false;
return true;
@@ -1319,7 +1356,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
} else
id_cols = max_id_len;
- if (!arg_no_legend)
+ if (!arg_no_legend && c > 0)
printf("%-*s %-*s\n",
id_cols, "UNIT FILE",
state_cols, "STATE");
@@ -1364,8 +1401,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
const char *state;
char *path;
int r;
+ bool fallback = false;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (install_client_side()) {
Hashmap *h;
@@ -1377,7 +1415,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
if (!h)
return log_oom();
- r = unit_file_get_list(arg_scope, arg_root, h);
+ r = unit_file_get_list(arg_scope, arg_root, h, arg_states, strv_skip(argv, 1));
if (r < 0) {
unit_file_list_free(h);
return log_error_errno(r, "Failed to get unit file list: %m");
@@ -1385,14 +1423,14 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
n_units = hashmap_size(h);
- units = new(UnitFileList, n_units);
- if (!units && n_units > 0) {
+ units = new(UnitFileList, n_units ?: 1); /* avoid malloc(0) */
+ if (!units) {
unit_file_list_free(h);
return log_oom();
}
HASHMAP_FOREACH(u, h, i) {
- if (!output_show_unit_file(u, strv_skip(argv, 1)))
+ if (!output_show_unit_file(u, NULL, NULL))
continue;
units[c++] = *u;
@@ -1401,7 +1439,10 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
assert(c <= n_units);
hashmap_free(h);
+
+ r = 0;
} else {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
@@ -1409,15 +1450,44 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- r = sd_bus_call_method(
+ r = sd_bus_message_new_method_call(
bus,
+ &m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
- "ListUnitFiles",
- &error,
- &reply,
- NULL);
+ "ListUnitFilesByPatterns");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_strv(m, arg_states);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_strv(m, strv_skip(argv, 1));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, 0, &error, &reply);
+ if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+ /* Fallback to legacy ListUnitFiles method */
+ fallback = true;
+ log_debug_errno(r, "Failed to list unit files: %s Falling back to ListUnitsFiles method.", bus_error_message(&error, r));
+ m = sd_bus_message_unref(m);
+ sd_bus_error_free(&error);
+
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "ListUnitFiles");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_call(bus, m, 0, &error, &reply);
+ }
if (r < 0)
return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r));
@@ -1435,8 +1505,10 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
unit_file_state_from_string(state)
};
- if (output_show_unit_file(&units[c], strv_skip(argv, 1)))
- c ++;
+ if (output_show_unit_file(&units[c],
+ fallback ? arg_states : NULL,
+ fallback ? strv_skip(argv, 1) : NULL))
+ c++;
}
if (r < 0)
@@ -1450,10 +1522,9 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
output_unit_file_list(units, c);
- if (install_client_side()) {
+ if (install_client_side())
for (unit = units; unit < units + c; unit++)
free(unit->path);
- }
return 0;
}
@@ -1472,7 +1543,7 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
printf("%s...\n",max_len % 2 ? "" : " ");
return 0;
}
- printf("%s", draw_special_char(branches & (1 << i) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE));
+ printf("%s", special_glyph(branches & (1 << i) ? TREE_VERTICAL : TREE_SPACE));
}
len += 2;
@@ -1481,10 +1552,10 @@ static int list_dependencies_print(const char *name, int level, unsigned int bra
return 0;
}
- printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
+ printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH));
}
- if (arg_full){
+ if (arg_full) {
printf("%s\n", name);
return 0;
}
@@ -1638,12 +1709,29 @@ static int list_dependencies_one(
if (arg_plain)
printf(" ");
else {
- int state;
+ UnitActiveState active_state = _UNIT_ACTIVE_STATE_INVALID;
const char *on;
- state = check_one_unit(bus, *c, "activating\0active\0reloading\0", true);
- on = state > 0 ? ansi_highlight_green() : ansi_highlight_red();
- printf("%s%s%s ", on, draw_special_char(DRAW_BLACK_CIRCLE), ansi_normal());
+ (void) get_state_one_unit(bus, *c, &active_state);
+
+ switch (active_state) {
+ case UNIT_ACTIVE:
+ case UNIT_RELOADING:
+ case UNIT_ACTIVATING:
+ on = ansi_highlight_green();
+ break;
+
+ case UNIT_INACTIVE:
+ case UNIT_DEACTIVATING:
+ on = ansi_normal();
+ break;
+
+ default:
+ on = ansi_highlight_red();
+ break;
+ }
+
+ printf("%s%s%s ", on, special_glyph(BLACK_CIRCLE), ansi_normal());
}
r = list_dependencies_print(*c, level, branches, c[1] == NULL);
@@ -1679,7 +1767,7 @@ static int list_dependencies(int argc, char *argv[], void *userdata) {
} else
u = SPECIAL_DEFAULT_TARGET;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -1880,16 +1968,16 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n)
on_failed = off_failed = "";
if (circle_len > 0)
- printf("%s%s%s ", on_state, circle ? draw_special_char(DRAW_BLACK_CIRCLE) : " ", off_state);
+ printf("%s%s%s ", on_state, circle ? special_glyph(BLACK_CIRCLE) : " ", off_state);
if (m->is_host)
- printf("%-*s (host) %s%-*s%s %s%*u%s %*u\n",
+ printf("%-*s (host) %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
(int) (namelen - (sizeof(" (host)")-1)), strna(m->name),
on_state, statelen, strna(m->state), off_state,
on_failed, failedlen, m->n_failed_units, off_failed,
jobslen, m->n_jobs);
else
- printf("%-*s %s%-*s%s %s%*u%s %*u\n",
+ printf("%-*s %s%-*s%s %s%*" PRIu32 "%s %*" PRIu32 "\n",
namelen, strna(m->name),
on_state, statelen, strna(m->state), off_state,
on_failed, failedlen, m->n_failed_units, off_failed,
@@ -1910,7 +1998,7 @@ static int list_machines(int argc, char *argv[], void *userdata) {
return -EPERM;
}
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -1939,6 +2027,7 @@ static int get_default(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to get default target: %m");
path = _path;
+ r = 0;
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
@@ -1970,21 +2059,10 @@ static int get_default(int argc, char *argv[], void *userdata) {
return 0;
}
-static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_changes) {
- unsigned i;
-
- assert(changes || n_changes == 0);
-
- for (i = 0; i < n_changes; i++) {
- if (changes[i].type == UNIT_FILE_SYMLINK)
- log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source);
- else
- log_info("Removed symlink %s.", changes[i].path);
- }
-}
-
static int set_default(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *unit = NULL;
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
int r;
assert(argc >= 2);
@@ -1995,18 +2073,11 @@ static int set_default(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to mangle unit name: %m");
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");
+ unit_file_dump_changes(r, "set default", changes, n_changes, arg_quiet);
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
- unit_file_changes_free(changes, n_changes);
- r = 0;
+ if (r > 0)
+ r = 0;
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -2030,9 +2101,9 @@ static int set_default(int argc, char *argv[], void *userdata) {
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);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
if (r < 0)
- return r;
+ goto finish;
/* Try to reload if enabled */
if (!arg_no_reload)
@@ -2041,6 +2112,9 @@ static int set_default(int argc, char *argv[], void *userdata) {
r = 0;
}
+finish:
+ unit_file_changes_free(changes, n_changes);
+
return r;
}
@@ -2067,7 +2141,7 @@ static void output_jobs_list(const struct job_info* jobs, unsigned n, bool skipp
return;
}
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
id_len = strlen("JOB");
unit_len = strlen("UNIT");
@@ -2137,7 +2211,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
int r;
bool skipped = false;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -2267,6 +2341,8 @@ static int need_daemon_reload(sd_bus *bus, const char *unit) {
}
static void warn_unit_file_changed(const char *name) {
+ assert(name);
+
log_warning("%sWarning:%s %s changed on disk. Run 'systemctl%s daemon-reload' to reload units.",
ansi_highlight_red(),
ansi_normal(),
@@ -2281,7 +2357,7 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un
assert(unit_name);
assert(unit_path);
- STRV_FOREACH(p, lp->unit_path) {
+ STRV_FOREACH(p, lp->search_path) {
_cleanup_free_ char *path;
path = path_join(arg_root, *p, unit_name);
@@ -2381,7 +2457,7 @@ static int unit_find_paths(
}
if (dropin_paths) {
- r = unit_file_find_dropin_paths(lp->unit_path, NULL, names, &dropins);
+ r = unit_file_find_dropin_paths(lp->search_path, NULL, names, &dropins);
if (r < 0)
return r;
}
@@ -2407,18 +2483,19 @@ static int unit_find_paths(
return r;
}
-static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) {
+static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *buf = NULL;
- const char *path, *state;
+ UnitActiveState state;
+ const char *path;
int r;
assert(name);
+ assert(active_state);
/* We don't use unit_dbus_path_from_name() directly since we don't want to load the unit unnecessarily, if it
* isn't loaded. */
-
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -2434,7 +2511,7 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states
/* The unit is currently not loaded, hence say it's "inactive", since all units that aren't loaded are
* considered inactive. */
- state = "inactive";
+ state = UNIT_INACTIVE;
} else {
r = sd_bus_message_read(reply, "o", &path);
@@ -2452,13 +2529,15 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states
if (r < 0)
return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
- state = buf;
+ state = unit_active_state_from_string(buf);
+ if (state == _UNIT_ACTIVE_STATE_INVALID) {
+ log_error("Invalid unit state '%s' for: %s", buf, name);
+ return -EINVAL;
+ }
}
- if (!quiet)
- puts(state);
-
- return nulstr_contains(good_states, state);
+ *active_state = state;
+ return 0;
}
static int check_triggering_units(
@@ -2466,9 +2545,10 @@ static int check_triggering_units(
const char *name) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL;
+ _cleanup_free_ char *path = NULL, *n = NULL, *load_state = NULL;
_cleanup_strv_free_ char **triggered_by = NULL;
bool print_warning_label = true;
+ UnitActiveState active_state;
char **i;
int r;
@@ -2487,11 +2567,11 @@ static int check_triggering_units(
"org.freedesktop.systemd1.Unit",
"LoadState",
&error,
- &state);
+ &load_state);
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"))
+ if (streq(load_state, "masked"))
return 0;
r = sd_bus_get_property_strv(
@@ -2506,11 +2586,11 @@ static int check_triggering_units(
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);
+ r = get_state_one_unit(bus, *i, &active_state);
if (r < 0)
- return log_error_errno(r, "Failed to check unit: %m");
+ return r;
- if (r == 0)
+ if (!IN_SET(active_state, UNIT_ACTIVE, UNIT_RELOADING))
continue;
if (print_warning_label) {
@@ -2604,7 +2684,10 @@ static int start_unit_one(
if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
!sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED))
- log_error("See system logs and 'systemctl status %s' for details.", name);
+ log_error("See %s logs and 'systemctl%s status %s' for details.",
+ arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
+ arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
+ name);
return r;
}
@@ -2778,9 +2861,22 @@ static int start_unit(int argc, char *argv[], void *userdata) {
}
if (!arg_no_block) {
- int q;
+ int q, arg_count = 0;
+ const char* extra_args[4] = {};
+
+ if (arg_scope != UNIT_FILE_SYSTEM)
+ extra_args[arg_count++] = "--user";
+
+ assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
+ if (arg_transport == BUS_TRANSPORT_REMOTE) {
+ extra_args[arg_count++] = "-H";
+ extra_args[arg_count++] = arg_host;
+ } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
+ extra_args[arg_count++] = "-M";
+ extra_args[arg_count++] = arg_host;
+ }
- q = bus_wait_for_jobs(w, arg_quiet, arg_scope != UNIT_FILE_SYSTEM ? "--user" : NULL);
+ q = bus_wait_for_jobs(w, arg_quiet, extra_args);
if (q < 0)
return q;
@@ -3075,7 +3171,7 @@ static int set_exit_code(uint8_t code) {
NULL,
"y", code);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to set exit code: %s", bus_error_message(&error, r));
return 0;
}
@@ -3102,7 +3198,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
return r;
if (a == ACTION_REBOOT && argc > 1) {
- r = update_reboot_param_file(argv[1]);
+ r = update_reboot_parameter_and_warn(argv[1]);
if (r < 0)
return r;
@@ -3158,11 +3254,12 @@ static int start_special(int argc, char *argv[], void *userdata) {
return start_unit(argc, argv, userdata);
}
-static int check_unit_generic(int code, const char *good_states, char **args) {
+static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
_cleanup_strv_free_ char **names = NULL;
+ UnitActiveState active_state;
sd_bus *bus;
char **name;
- int r;
+ int r, i;
bool found = false;
r = acquire_bus(BUS_MANAGER, &bus);
@@ -3174,13 +3271,16 @@ static int check_unit_generic(int code, const char *good_states, char **args) {
return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
- int state;
+ r = get_state_one_unit(bus, *name, &active_state);
+ if (r < 0)
+ return r;
+
+ if (!arg_quiet)
+ puts(unit_active_state_to_string(active_state));
- state = check_one_unit(bus, *name, good_states, arg_quiet);
- if (state < 0)
- return state;
- if (state > 0)
- found = true;
+ for (i = 0; i < nb_states; ++i)
+ if (good_states[i] == active_state)
+ found = true;
}
/* use the given return code for the case that we won't find
@@ -3189,12 +3289,14 @@ static int check_unit_generic(int code, const char *good_states, char **args) {
}
static int check_unit_active(int argc, char *argv[], void *userdata) {
+ const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING };
/* According to LSB: 3, "program is not running" */
- return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1));
+ return check_unit_generic(3, states, ELEMENTSOF(states), strv_skip(argv, 1));
}
static int check_unit_failed(int argc, char *argv[], void *userdata) {
- return check_unit_generic(1, "failed\0", strv_skip(argv, 1));
+ const UnitActiveState states[] = { UNIT_FAILED };
+ return check_unit_generic(1, states, ELEMENTSOF(states), strv_skip(argv, 1));
}
static int kill_unit(int argc, char *argv[], void *userdata) {
@@ -3214,7 +3316,7 @@ static int kill_unit(int argc, char *argv[], void *userdata) {
/* --fail was specified */
if (streq(arg_job_mode, "fail"))
- kill_who = strjoina(arg_kill_who, "-fail", NULL);
+ kill_who = strjoina(arg_kill_who, "-fail");
r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
@@ -3406,6 +3508,7 @@ typedef struct UnitStatusInfo {
} UnitStatusInfo;
static void print_status_info(
+ sd_bus *bus,
UnitStatusInfo *i,
bool *ellipsized) {
@@ -3416,6 +3519,7 @@ static void print_status_info(
char since2[FORMAT_TIMESTAMP_MAX], *s2;
const char *path;
char **t, **t2;
+ int r;
assert(i);
@@ -3431,7 +3535,7 @@ static void print_status_info(
} else
active_on = active_off = "";
- printf("%s%s%s %s", active_on, draw_special_char(DRAW_BLACK_CIRCLE), active_off, strna(i->id));
+ printf("%s%s%s %s", active_on, special_glyph(BLACK_CIRCLE), active_off, strna(i->id));
if (i->description && !streq_ptr(i->id, i->description))
printf(" - %s", i->description);
@@ -3486,7 +3590,7 @@ static void print_status_info(
}
printf("%s\n %s", dir,
- draw_special_char(DRAW_TREE_RIGHT));
+ special_glyph(TREE_RIGHT));
}
last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
@@ -3688,25 +3792,26 @@ static void print_status_info(
printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
}
- if (i->control_group &&
- (i->main_pid > 0 || i->control_pid > 0 ||
- (!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
+ if (i->control_group)
+ printf(" CGroup: %s\n", i->control_group);
+
+ {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ static const char prefix[] = " ";
unsigned c;
- printf(" CGroup: %s\n", i->control_group);
+ c = columns();
+ if (c > sizeof(prefix) - 1)
+ c -= sizeof(prefix) - 1;
+ else
+ c = 0;
- if (IN_SET(arg_transport,
- BUS_TRANSPORT_LOCAL,
- BUS_TRANSPORT_MACHINE)) {
+ r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
+ if (r == -EBADR) {
unsigned k = 0;
pid_t extra[2];
- static const char prefix[] = " ";
- c = columns();
- if (c > sizeof(prefix) - 1)
- c -= sizeof(prefix) - 1;
- else
- c = 0;
+ /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
if (i->main_pid > 0)
extra[k++] = i->main_pid;
@@ -3714,8 +3819,9 @@ static void print_status_info(
if (i->control_pid > 0)
extra[k++] = i->control_pid;
- show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags());
- }
+ show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
+ } else if (r < 0)
+ log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r));
}
if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
@@ -4077,6 +4183,14 @@ skip:
return 0;
}
+#define print_prop(name, fmt, ...) \
+ do { \
+ if (arg_value) \
+ printf(fmt "\n", __VA_ARGS__); \
+ else \
+ printf("%s=" fmt "\n", name, __VA_ARGS__); \
+ } while(0)
+
static int print_property(const char *name, sd_bus_message *m, const char *contents) {
int r;
@@ -4104,9 +4218,9 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
if (u > 0)
- printf("%s=%"PRIu32"\n", name, u);
+ print_prop(name, "%"PRIu32, u);
else if (arg_all)
- printf("%s=\n", name);
+ print_prop(name, "%s", "");
return 0;
@@ -4118,7 +4232,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
if (arg_all || !isempty(s))
- printf("%s=%s\n", name, s);
+ print_prop(name, "%s", s);
return 0;
@@ -4130,7 +4244,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
if (arg_all || !isempty(a) || !isempty(b))
- printf("%s=%s \"%s\"\n", name, strempty(a), strempty(b));
+ print_prop(name, "%s \"%s\"", strempty(a), strempty(b));
return 0;
} else if (streq_ptr(name, "SystemCallFilter")) {
@@ -4157,8 +4271,10 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
bool first = true;
char **i;
- fputs(name, stdout);
- fputc('=', stdout);
+ if (!arg_value) {
+ fputs(name, stdout);
+ fputc('=', stdout);
+ }
if (!whitelist)
fputc('~', stdout);
@@ -4190,7 +4306,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
- printf("EnvironmentFile=%s (ignore_errors=%s)\n", path, yes_no(ignore));
+ print_prop("EnvironmentFile", "%s (ignore_errors=%s)\n", path, yes_no(ignore));
if (r < 0)
return bus_log_parse_error(r);
@@ -4209,7 +4325,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
- printf("%s=%s\n", type, path);
+ print_prop(type, "%s", path);
if (r < 0)
return bus_log_parse_error(r);
@@ -4227,7 +4343,10 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
- printf("Listen%s=%s\n", type, path);
+ if (arg_value)
+ puts(path);
+ else
+ printf("Listen%s=%s\n", type, path);
if (r < 0)
return bus_log_parse_error(r);
@@ -4248,10 +4367,9 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
while ((r = sd_bus_message_read(m, "(stt)", &base, &value, &next_elapse)) > 0) {
char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
- printf("%s={ value=%s ; next_elapse=%s }\n",
- base,
- format_timespan(timespan1, sizeof(timespan1), value, 0),
- format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
+ print_prop(base, "{ value=%s ; next_elapse=%s }",
+ format_timespan(timespan1, sizeof(timespan1), value, 0),
+ format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
}
if (r < 0)
return bus_log_parse_error(r);
@@ -4275,18 +4393,18 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
tt = strv_join(info.argv, " ");
- printf("%s={ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }\n",
- name,
- strna(info.path),
- strna(tt),
- yes_no(info.ignore),
- strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
- strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
- info.pid,
- sigchld_code_to_string(info.code),
- info.status,
- info.code == CLD_EXITED ? "" : "/",
- strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+ print_prop(name,
+ "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+ strna(info.path),
+ strna(tt),
+ yes_no(info.ignore),
+ strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
+ strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
+ info.pid,
+ sigchld_code_to_string(info.code),
+ info.status,
+ info.code == CLD_EXITED ? "" : "/",
+ strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
free(info.path);
strv_free(info.argv);
@@ -4307,7 +4425,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
- printf("%s=%s %s\n", name, strna(path), strna(rwm));
+ print_prop(name, "%s %s", strna(path), strna(rwm));
if (r < 0)
return bus_log_parse_error(r);
@@ -4317,7 +4435,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return 0;
- } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "BlockIODeviceWeight")) {
+ } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "IODeviceWeight") || streq(name, "BlockIODeviceWeight"))) {
const char *path;
uint64_t weight;
@@ -4326,7 +4444,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
- printf("%s=%s %" PRIu64 "\n", name, strna(path), weight);
+ print_prop(name, "%s %"PRIu64, strna(path), weight);
if (r < 0)
return bus_log_parse_error(r);
@@ -4336,7 +4454,8 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return 0;
- } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
+ } else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (cgroup_io_limit_type_from_string(name) >= 0 ||
+ streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
const char *path;
uint64_t bandwidth;
@@ -4345,7 +4464,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
- printf("%s=%s %" PRIu64 "\n", name, strna(path), bandwidth);
+ print_prop(name, "%s %"PRIu64, strna(path), bandwidth);
if (r < 0)
return bus_log_parse_error(r);
@@ -4359,7 +4478,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
break;
}
- r = bus_print_property(name, m, arg_all);
+ r = bus_print_property(name, m, arg_value, arg_all);
if (r < 0)
return bus_log_parse_error(r);
@@ -4464,7 +4583,7 @@ static int show_one(
if (streq(verb, "help"))
show_unit_help(&info);
else
- print_status_info(&info, ellipsized);
+ print_status_info(bus, &info, ellipsized);
}
strv_free(info.documentation);
@@ -4546,7 +4665,7 @@ static int show_all(
if (r < 0)
return r;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
c = (unsigned) r;
@@ -4593,13 +4712,13 @@ static int show_system_status(sd_bus *bus) {
} else
on = off = "";
- printf("%s%s%s %s\n", on, draw_special_char(DRAW_BLACK_CIRCLE), off, arg_host ? arg_host : hn);
+ printf("%s%s%s %s\n", on, special_glyph(BLACK_CIRCLE), off, arg_host ? arg_host : hn);
printf(" State: %s%s%s\n",
on, strna(mi.state), off);
- printf(" Jobs: %u queued\n", mi.n_jobs);
- printf(" Failed: %u units\n", mi.n_failed_units);
+ printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs);
+ printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
printf(" Since: %s; %s\n",
format_timestamp(since2, sizeof(since2), mi.timestamp),
@@ -4618,7 +4737,7 @@ static int show_system_status(sd_bus *bus) {
else
c = 0;
- show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
+ show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
}
return 0;
@@ -4641,7 +4760,7 @@ static int show(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (show_status)
/* Increase max number of open files to 16K if we can, we
@@ -4659,7 +4778,7 @@ static int show(int argc, char *argv[], void *userdata) {
if (show_status && argc <= 1) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
show_system_status(bus);
new_line = true;
@@ -4728,34 +4847,6 @@ static int show(int argc, char *argv[], void *userdata) {
return ret;
}
-static int init_home_and_lookup_paths(char **user_home, char **user_runtime, LookupPaths *lp) {
- int r;
-
- assert(user_home);
- assert(user_runtime);
- assert(lp);
-
- if (arg_scope == UNIT_FILE_USER) {
- r = user_config_home(user_home);
- if (r < 0)
- return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
- else if (r == 0)
- return log_error_errno(ENOTDIR, "Cannot find units: $XDG_CONFIG_HOME and $HOME are not set.");
-
- r = user_runtime_dir(user_runtime);
- if (r < 0)
- return log_error_errno(r, "Failed to query XDG_CONFIG_HOME: %m");
- else if (r == 0)
- return log_error_errno(ENOTDIR, "Cannot find units: $XDG_RUNTIME_DIR is not set.");
- }
-
- r = lookup_paths_init_from_scope(lp, arg_scope, arg_root);
- if (r < 0)
- return log_error_errno(r, "Failed to query unit lookup paths: %m");
-
- return 0;
-}
-
static int cat_file(const char *filename, bool newline) {
_cleanup_close_ int fd;
@@ -4774,8 +4865,6 @@ static int cat_file(const char *filename, bool newline) {
}
static int cat(int argc, char *argv[], void *userdata) {
- _cleanup_free_ char *user_home = NULL;
- _cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
_cleanup_strv_free_ char **names = NULL;
char **name;
@@ -4788,9 +4877,9 @@ static int cat(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
- r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
+ r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to determine unit paths: %m");
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -4800,7 +4889,7 @@ static int cat(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
STRV_FOREACH(name, names) {
_cleanup_free_ char *fragment_path = NULL;
@@ -4937,7 +5026,7 @@ static int daemon_reload(int argc, char *argv[], void *userdata) {
* reply */
r = 0;
else if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
return r < 0 ? r : 0;
}
@@ -4990,7 +5079,7 @@ static int show_environment(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
@@ -5201,8 +5290,10 @@ static int enable_sysv_units(const char *verb, char **args) {
int r = 0;
#if defined(HAVE_SYSV_COMPAT)
- unsigned f = 0;
_cleanup_lookup_paths_free_ LookupPaths paths = {};
+ unsigned f = 0;
+
+ /* Processes all SysV units, and reshuffles the array so that afterwards only the native units remain */
if (arg_scope != UNIT_FILE_SYSTEM)
return 0;
@@ -5216,24 +5307,28 @@ static int enable_sysv_units(const char *verb, char **args) {
"is-enabled"))
return 0;
- /* Processes all SysV units, and reshuffles the array so that
- * afterwards only the native units remain */
-
- r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, arg_root, NULL, NULL, NULL);
+ r = lookup_paths_init(&paths, arg_scope, LOOKUP_PATHS_EXCLUDE_GENERATED, arg_root);
if (r < 0)
return r;
r = 0;
while (args[f]) {
- const char *name;
+
+ const char *argv[] = {
+ ROOTLIBEXECDIR "/systemd-sysv-install",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ };
+
_cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
bool found_native = false, found_sysv;
+ siginfo_t status;
+ const char *name;
unsigned c = 1;
- const char *argv[6] = { ROOTLIBEXECDIR "/systemd-sysv-install", NULL, NULL, NULL, NULL };
- char **k;
- int j;
pid_t pid;
- siginfo_t status;
+ int j;
name = args[f++];
@@ -5243,21 +5338,13 @@ static int enable_sysv_units(const char *verb, char **args) {
if (path_is_absolute(name))
continue;
- STRV_FOREACH(k, paths.unit_path) {
- _cleanup_free_ char *path = NULL;
-
- path = path_join(arg_root, *k, name);
- if (!path)
- return log_oom();
-
- found_native = access(path, F_OK) >= 0;
- if (found_native)
- break;
- }
+ j = unit_file_exists(arg_scope, &paths, name);
+ if (j < 0 && !IN_SET(j, -ELOOP, -ERFKILL, -EADDRNOTAVAIL))
+ return log_error_errno(j, "Failed to lookup unit file state: %m");
+ found_native = j != 0;
- /* If we have both a native unit and a SysV script,
- * enable/disable them both (below); for is-enabled, prefer the
- * native unit */
+ /* If we have both a native unit and a SysV script, enable/disable them both (below); for is-enabled,
+ * prefer the native unit */
if (found_native && streq(verb, "is-enabled"))
continue;
@@ -5271,9 +5358,9 @@ static int enable_sysv_units(const char *verb, char **args) {
continue;
if (found_native)
- log_info("Synchronizing state of %s with SysV init with %s...", name, argv[0]);
+ log_info("Synchronizing state of %s with SysV service script with %s.", name, argv[0]);
else
- log_info("%s is not a native service, redirecting to systemd-sysv-install", name);
+ log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
if (!isempty(arg_root))
argv[c++] = q = strappend("--root=", arg_root);
@@ -5286,7 +5373,7 @@ static int enable_sysv_units(const char *verb, char **args) {
if (!l)
return log_oom();
- log_info("Executing %s", l);
+ log_info("Executing: %s", l);
pid = fork();
if (pid < 0)
@@ -5298,7 +5385,7 @@ static int enable_sysv_units(const char *verb, char **args) {
(void) reset_signal_mask();
execv(argv[0], (char**) argv);
- log_error_errno(r, "Failed to execute %s: %m", argv[0]);
+ log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
_exit(EXIT_FAILURE);
}
@@ -5320,9 +5407,11 @@ static int enable_sysv_units(const char *verb, char **args) {
}
} else if (status.si_status != 0)
- return -EINVAL;
- } else
+ return -EBADE; /* We don't warn here, under the assumption the script already showed an explanation */
+ } else {
+ log_error("Unexpected waitid() result.");
return -EPROTO;
+ }
if (found_native)
continue;
@@ -5380,6 +5469,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
int carries_install_info = -1;
+ bool ignore_carries_install_info = arg_quiet;
int r;
if (!argv[1])
@@ -5393,10 +5483,12 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
- /* If the operation was fully executed by the SysV compat,
- * let's finish early */
- if (strv_isempty(names))
- return 0;
+ /* If the operation was fully executed by the SysV compat, let's finish early */
+ if (strv_isempty(names)) {
+ if (arg_no_reload || install_client_side())
+ return 0;
+ return daemon_reload(argc, argv, userdata);
+ }
if (install_client_side()) {
if (streq(verb, "enable")) {
@@ -5411,28 +5503,24 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
r = unit_file_link(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
else if (streq(verb, "preset")) {
r = unit_file_preset(arg_scope, arg_runtime, arg_root, names, arg_preset_mode, arg_force, &changes, &n_changes);
- carries_install_info = r;
} else if (streq(verb, "mask"))
r = unit_file_mask(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes);
else if (streq(verb, "unmask"))
r = unit_file_unmask(arg_scope, arg_runtime, arg_root, names, &changes, &n_changes);
+ else if (streq(verb, "revert"))
+ r = unit_file_revert(arg_scope, arg_root, names, &changes, &n_changes);
else
assert_not_reached("Unknown verb");
- if (r == -ESHUTDOWN)
- return log_error_errno(r, "Unit file is masked.");
+ unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
if (r < 0)
- return log_error_errno(r, "Operation failed: %m");
-
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
+ return r;
r = 0;
} else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- int expect_carries_install_info = false;
- bool send_force = true, send_preset_mode = false;
+ bool expect_carries_install_info = false;
+ bool send_runtime = true, send_force = true, send_preset_mode = false;
const char *method;
sd_bus *bus;
@@ -5462,11 +5550,15 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
method = "PresetUnitFiles";
expect_carries_install_info = true;
+ ignore_carries_install_info = true;
} else if (streq(verb, "mask"))
method = "MaskUnitFiles";
else if (streq(verb, "unmask")) {
method = "UnmaskUnitFiles";
send_force = false;
+ } else if (streq(verb, "revert")) {
+ method = "RevertUnitFiles";
+ send_runtime = send_force = false;
} else
assert_not_reached("Unknown verb");
@@ -5490,9 +5582,11 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
return bus_log_create_error(r);
}
- r = sd_bus_message_append(m, "b", arg_runtime);
- if (r < 0)
- return bus_log_create_error(r);
+ if (send_runtime) {
+ r = sd_bus_message_append(m, "b", arg_runtime);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
if (send_force) {
r = sd_bus_message_append(m, "b", arg_force);
@@ -5502,7 +5596,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to %s unit: %s", verb, bus_error_message(&error, r));
if (expect_carries_install_info) {
r = sd_bus_message_read(reply, "b", &carries_install_info);
@@ -5521,16 +5615,19 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
r = 0;
}
- if (carries_install_info == 0)
- log_warning("The unit files have no [Install] section. They are not meant to be enabled\n"
- "using systemctl.\n"
+ if (carries_install_info == 0 && !ignore_carries_install_info)
+ log_warning("The unit files have no installation config (WantedBy, RequiredBy, Also, Alias\n"
+ "settings in the [Install] section, and DefaultInstance for template units).\n"
+ "This means they are not meant to be enabled using systemctl.\n"
"Possible reasons for having this kind of units are:\n"
"1) A unit may be statically enabled by being symlinked from another unit's\n"
" .wants/ or .requires/ directory.\n"
"2) A unit's purpose may be to act as a helper for some other unit which has\n"
" a requirement dependency on it.\n"
"3) A unit may be started when needed via activation (socket, path, timer,\n"
- " D-Bus, udev, scripted systemctl call, ...).\n");
+ " D-Bus, udev, scripted systemctl call, ...).\n"
+ "4) In case of template units, the unit is meant to be enabled with some\n"
+ " instance name specified.");
if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) {
char *new_args[n_changes + 2];
@@ -5559,6 +5656,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
_cleanup_free_ char *target = NULL;
const char *verb = argv[0];
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
UnitDependency dep;
int r = 0;
@@ -5581,20 +5680,11 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
assert_not_reached("Unknown verb");
if (install_client_side()) {
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
-
r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes);
- if (r == -ESHUTDOWN)
- return log_error_errno(r, "Unit file is masked.");
- if (r < 0)
- return log_error_errno(r, "Can't add dependency: %m");
-
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
- unit_file_changes_free(changes, n_changes);
+ unit_file_dump_changes(r, "add dependency on", changes, n_changes, arg_quiet);
+ if (r > 0)
+ r = 0;
} else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -5626,18 +5716,23 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to add dependency: %s", bus_error_message(&error, r));
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
if (r < 0)
- return r;
+ goto finish;
- if (!arg_no_reload)
- r = daemon_reload(argc, argv, userdata);
- else
+ if (arg_no_reload) {
r = 0;
+ goto finish;
+ }
+
+ r = daemon_reload(argc, argv, userdata);
}
+finish:
+ unit_file_changes_free(changes, n_changes);
+
return r;
}
@@ -5647,18 +5742,11 @@ static int preset_all(int argc, char *argv[], void *userdata) {
int r;
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) {
- log_error_errno(r, "Operation failed: %m");
- goto finish;
- }
-
- if (!arg_quiet)
- dump_unit_file_changes(changes, n_changes);
-
- r = 0;
+ unit_file_dump_changes(r, "preset", changes, n_changes, arg_quiet);
+ if (r > 0)
+ r = 0;
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
@@ -5683,16 +5771,18 @@ static int preset_all(int argc, char *argv[], void *userdata) {
arg_runtime,
arg_force);
if (r < 0)
- return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+ return log_error_errno(r, "Failed to preset all units: %s", bus_error_message(&error, r));
- r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
+ r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
if (r < 0)
- return r;
+ goto finish;
- if (!arg_no_reload)
- r = daemon_reload(argc, argv, userdata);
- else
+ if (arg_no_reload) {
r = 0;
+ goto finish;
+ }
+
+ r = daemon_reload(argc, argv, userdata);
}
finish:
@@ -5731,13 +5821,15 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
UNIT_FILE_ENABLED,
UNIT_FILE_ENABLED_RUNTIME,
UNIT_FILE_STATIC,
- UNIT_FILE_INDIRECT))
+ UNIT_FILE_INDIRECT,
+ UNIT_FILE_GENERATED))
enabled = true;
if (!arg_quiet)
puts(unit_file_state_to_string(state));
}
+ r = 0;
} else {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
@@ -5766,7 +5858,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
- if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect"))
+ if (STR_IN_SET(s, "enabled", "enabled-runtime", "static", "indirect", "generated"))
enabled = true;
if (!arg_quiet)
@@ -5774,7 +5866,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) {
}
}
- return !enabled;
+ return enabled ? EXIT_SUCCESS : EXIT_FAILURE;
}
static int is_system_running(int argc, char *argv[], void *userdata) {
@@ -5844,52 +5936,32 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
return 0;
}
-static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) {
- _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL;
+static int get_file_to_edit(
+ const LookupPaths *paths,
+ const char *name,
+ char **ret_path) {
+
+ _cleanup_free_ char *path = NULL, *run = NULL;
assert(name);
assert(ret_path);
- switch (arg_scope) {
- case UNIT_FILE_SYSTEM:
- path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name);
- if (arg_runtime)
- run = path_join(arg_root, "/run/systemd/system/", name);
- break;
- case UNIT_FILE_GLOBAL:
- path = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
- if (arg_runtime)
- run = path_join(arg_root, "/run/systemd/user/", name);
- break;
- case UNIT_FILE_USER:
- assert(user_home);
- assert(user_runtime);
-
- path = path_join(arg_root, user_home, name);
- if (arg_runtime) {
- path2 = path_join(arg_root, USER_CONFIG_UNIT_PATH, name);
- if (!path2)
- return log_oom();
- run = path_join(arg_root, user_runtime, name);
- }
- break;
- default:
- assert_not_reached("Invalid scope");
- }
- if (!path || (arg_runtime && !run))
+ path = strjoin(paths->persistent_config, "/", name, NULL);
+ if (!path)
return log_oom();
if (arg_runtime) {
+ run = strjoin(paths->runtime_config, name, NULL);
+ if (!run)
+ return log_oom();
+ }
+
+ if (arg_runtime) {
if (access(path, F_OK) >= 0) {
log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path);
return -EEXIST;
}
- if (path2 && access(path2, F_OK) >= 0) {
- log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2);
- return -EEXIST;
- }
-
*ret_path = run;
run = NULL;
} else {
@@ -5900,7 +5972,12 @@ static int get_file_to_edit(const char *name, const char *user_home, const char
return 0;
}
-static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) {
+static int unit_file_create_dropin(
+ const LookupPaths *paths,
+ const char *unit_name,
+ char **ret_new_path,
+ char **ret_tmp_path) {
+
char *tmp_new_path, *tmp_tmp_path, *ending;
int r;
@@ -5909,7 +5986,7 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home,
assert(ret_tmp_path);
ending = strjoina(unit_name, ".d/override.conf");
- r = get_file_to_edit(ending, user_home, user_runtime, &tmp_new_path);
+ r = get_file_to_edit(paths, ending, &tmp_new_path);
if (r < 0)
return r;
@@ -5926,10 +6003,9 @@ static int unit_file_create_dropin(const char *unit_name, const char *user_home,
}
static int unit_file_create_copy(
+ const LookupPaths *paths,
const char *unit_name,
const char *fragment_path,
- const char *user_home,
- const char *user_runtime,
char **ret_new_path,
char **ret_tmp_path) {
@@ -5941,7 +6017,7 @@ static int unit_file_create_copy(
assert(ret_new_path);
assert(ret_tmp_path);
- r = get_file_to_edit(unit_name, user_home, user_runtime, &tmp_new_path);
+ r = get_file_to_edit(paths, unit_name, &tmp_new_path);
if (r < 0)
return r;
@@ -6056,8 +6132,6 @@ static int run_editor(char **paths) {
}
static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
- _cleanup_free_ char *user_home = NULL;
- _cleanup_free_ char *user_runtime = NULL;
_cleanup_lookup_paths_free_ LookupPaths lp = {};
char **name;
int r;
@@ -6065,13 +6139,12 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
assert(names);
assert(paths);
- r = init_home_and_lookup_paths(&user_home, &user_runtime, &lp);
+ r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
if (r < 0)
return r;
STRV_FOREACH(name, names) {
- _cleanup_free_ char *path = NULL;
- char *new_path, *tmp_path;
+ _cleanup_free_ char *path = NULL, *new_path = NULL, *tmp_path = NULL;
r = unit_find_paths(bus, *name, &lp, &path, NULL);
if (r < 0)
@@ -6085,15 +6158,16 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
}
if (arg_full)
- r = unit_file_create_copy(*name, path, user_home, user_runtime, &new_path, &tmp_path);
+ r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path);
else
- r = unit_file_create_dropin(*name, user_home, user_runtime, &new_path, &tmp_path);
+ r = unit_file_create_dropin(&lp, *name, &new_path, &tmp_path);
if (r < 0)
return r;
r = strv_push_pair(paths, new_path, tmp_path);
if (r < 0)
return log_oom();
+ new_path = tmp_path = NULL;
}
return 0;
@@ -6157,15 +6231,30 @@ static int edit(int argc, char *argv[], void *userdata) {
r = daemon_reload(argc, argv, userdata);
end:
- STRV_FOREACH_PAIR(original, tmp, paths)
+ STRV_FOREACH_PAIR(original, tmp, paths) {
(void) unlink(*tmp);
+ /* Removing empty dropin dirs */
+ if (!arg_full) {
+ _cleanup_free_ char *dir;
+
+ dir = dirname_malloc(*original);
+ if (!dir)
+ return log_oom();
+
+ /* no need to check if the dir is empty, rmdir
+ * does nothing if it is not the case.
+ */
+ (void) rmdir(dir);
+ }
+ }
+
return r;
}
static void systemctl_help(void) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Query or send control commands to the systemd manager.\n\n"
@@ -6189,6 +6278,7 @@ static void systemctl_help(void) {
" --job-mode=MODE Specify how to deal with already queued jobs, when\n"
" queueing a new job\n"
" --show-types When showing sockets, explicitly show their type\n"
+ " --value When showing properties, only print the value\n"
" -i --ignore-inhibitors\n"
" When shutting down or sleeping, ignore inhibitors\n"
" --kill-who=WHO Who to send signal to\n"
@@ -6256,6 +6346,8 @@ static void systemctl_help(void) {
" unmask NAME... Unmask one or more units\n"
" link PATH... Link one or more units files into\n"
" the search path\n"
+ " revert NAME... Revert one or more unit files to vendor\n"
+ " version\n"
" add-wants TARGET NAME... Add 'Wants' dependency for the target\n"
" on specified one or more units\n"
" add-requires TARGET NAME... Add 'Requires' dependency for the target\n"
@@ -6440,6 +6532,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_SHOW_TYPES,
ARG_IRREVERSIBLE,
ARG_IGNORE_DEPENDENCIES,
+ ARG_VALUE,
ARG_VERSION,
ARG_USER,
ARG_SYSTEM,
@@ -6481,6 +6574,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */
{ "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */
{ "ignore-inhibitors", no_argument, NULL, 'i' },
+ { "value", no_argument, NULL, ARG_VALUE },
{ "user", no_argument, NULL, ARG_USER },
{ "system", no_argument, NULL, ARG_SYSTEM },
{ "global", no_argument, NULL, ARG_GLOBAL },
@@ -6537,7 +6631,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
}
p = optarg;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *type = NULL;
r = extract_first_word(&p, &type, ",", 0);
@@ -6587,7 +6681,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
return log_oom();
} else {
p = optarg;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *prop = NULL;
r = extract_first_word(&p, &prop, ",", 0);
@@ -6632,6 +6726,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_show_types = true;
break;
+ case ARG_VALUE:
+ arg_value = true;
+ break;
+
case ARG_JOB_MODE:
arg_job_mode = optarg;
break;
@@ -6677,7 +6775,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_ROOT:
- r = parse_path_argument_and_warn(optarg, true, &arg_root);
+ r = parse_path_argument_and_warn(optarg, false, &arg_root);
if (r < 0)
return r;
break;
@@ -6697,11 +6795,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
break;
case ARG_FORCE:
- arg_force ++;
+ arg_force++;
break;
case 'f':
- arg_force ++;
+ arg_force++;
break;
case ARG_NO_RELOAD:
@@ -6772,7 +6870,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
}
p = optarg;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *s = NULL;
r = extract_first_word(&p, &s, ",", 0);
@@ -6855,6 +6953,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
{ "force", no_argument, NULL, 'f' },
{ "wtmp-only", no_argument, NULL, 'w' },
{ "no-wtmp", no_argument, NULL, 'd' },
+ { "no-sync", no_argument, NULL, 'n' },
{ "no-wall", no_argument, NULL, ARG_NO_WALL },
{}
};
@@ -6900,13 +6999,16 @@ static int halt_parse_argv(int argc, char *argv[]) {
arg_no_wtmp = true;
break;
+ case 'n':
+ arg_no_sync = true;
+ break;
+
case ARG_NO_WALL:
arg_no_wall = true;
break;
case 'i':
case 'h':
- case 'n':
/* Compatibility nops */
break;
@@ -6918,7 +7020,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
}
if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
- r = update_reboot_param_file(argc == optind + 1 ? argv[optind] : NULL);
+ r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
if (r < 0)
return r;
} else if (optind < argc) {
@@ -7167,7 +7269,7 @@ static int telinit_parse_argv(int argc, char *argv[]) {
arg_action = table[i].to;
- optind ++;
+ optind++;
return 1;
}
@@ -7258,6 +7360,7 @@ static int parse_argv(int argc, char *argv[]) {
return systemctl_parse_argv(argc, argv);
}
+#ifdef HAVE_SYSV_COMPAT
_pure_ static int action_to_runlevel(void) {
static const char table[_ACTION_MAX] = {
@@ -7275,6 +7378,7 @@ _pure_ static int action_to_runlevel(void) {
return table[arg_action];
}
+#endif
static int talk_initctl(void) {
#ifdef HAVE_SYSV_COMPAT
@@ -7371,6 +7475,7 @@ static int systemctl_main(int argc, char *argv[]) {
{ "mask", 2, VERB_ANY, 0, enable_unit },
{ "unmask", 2, VERB_ANY, 0, enable_unit },
{ "link", 2, VERB_ANY, 0, enable_unit },
+ { "revert", 2, VERB_ANY, 0, enable_unit },
{ "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
{ "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
{ "set-default", 2, 2, 0, set_default },
@@ -7417,11 +7522,13 @@ static int start_with_fallback(void) {
}
static int halt_now(enum action a) {
+ int r;
/* The kernel will automaticall flush ATA disks and suchlike
* on reboot(), but the file systems need to be synce'd
* explicitly in advance. */
- (void) sync();
+ if (!arg_no_sync)
+ (void) sync();
/* Make sure C-A-D is handled by the kernel from this point
* on... */
@@ -7443,9 +7550,14 @@ static int halt_now(enum action a) {
case ACTION_REBOOT: {
_cleanup_free_ char *param = NULL;
- if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
+ r = read_one_line_file("/run/systemd/reboot-param", &param);
+ if (r < 0)
+ log_warning_errno(r, "Failed to read reboot parameter file: %m");
+
+ if (!isempty(param)) {
log_info("Rebooting with argument '%s'.", param);
(void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
+ log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
}
log_info("Rebooting.");
diff --git a/src/grp-system/systemd/Makefile b/src/grp-system/systemd/Makefile
index 0e34d8d829..2e6d9bbf7f 100644
--- a/src/grp-system/systemd/Makefile
+++ b/src/grp-system/systemd/Makefile
@@ -53,6 +53,9 @@ pkgconfigdata_DATA += \
nodist_rpmmacros_DATA = \
src/core/macros.systemd
+BUILT_SOURCES += \
+ src/core/triggers.systemd
+
EXTRA_DIST += \
src/core/systemd.pc.in \
src/core/macros.systemd.in \
diff --git a/src/grp-system/systemd/main.c b/src/grp-system/systemd/main.c
index bc151cde85..042cce49dd 100644
--- a/src/grp-system/systemd/main.c
+++ b/src/grp-system/systemd/main.c
@@ -81,6 +81,7 @@
#include "strv.h"
#include "switch-root.h"
#include "terminal-util.h"
+#include "umask-util.h"
#include "user-util.h"
#include "virt.h"
#include "watchdog.h"
@@ -94,7 +95,7 @@ static enum {
ACTION_DONE
} arg_action = ACTION_RUN;
static char *arg_default_unit = NULL;
-static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
+static bool arg_system = false;
static bool arg_dump_core = true;
static int arg_crash_chvt = -1;
static bool arg_crash_shell = false;
@@ -102,7 +103,7 @@ 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;
-static int arg_no_pager = -1;
+static bool arg_no_pager = false;
static char ***arg_join_controllers = NULL;
static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
@@ -121,20 +122,13 @@ static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE;
static Set* arg_syscall_archs = NULL;
static FILE* arg_serialization = NULL;
static bool arg_default_cpu_accounting = false;
+static bool arg_default_io_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static bool arg_default_tasks_accounting = true;
static uint64_t arg_default_tasks_max = UINT64_C(512);
static sd_id128_t arg_machine_id = {};
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager <= 0)
- return;
-
- pager_open(false);
-}
-
noreturn static void freeze_or_reboot(void) {
if (arg_crash_reboot) {
@@ -296,6 +290,7 @@ static int parse_crash_chvt(const char *value) {
}
static int set_machine_id(const char *m) {
+ assert(m);
if (sd_id128_from_string(m, &arg_machine_id) < 0)
return -EINVAL;
@@ -420,6 +415,15 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
target = runlevel_to_target(key);
if (target)
return free_and_strdup(&arg_default_unit, target);
+
+ } else if (streq(key, "systemd.default_timeout_start_sec") && value) {
+
+ r = parse_sec(value, &arg_default_timeout_start_usec);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse default start timeout: %s, ignoring.", value);
+
+ if (arg_default_timeout_start_usec <= 0)
+ arg_default_timeout_start_usec = USEC_INFINITY;
}
return 0;
@@ -667,7 +671,8 @@ static int parse_config_file(void) {
{ "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec },
{ "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec },
{ "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec },
- { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
+ { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, /* obsolete alias */
+ { "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
{ "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit },
@@ -687,6 +692,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
{ "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
+ { "Manager", "DefaultIOAccounting", config_parse_bool, 0, &arg_default_io_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
@@ -696,11 +702,11 @@ static int parse_config_file(void) {
const char *fn, *conf_dirs_nulstr;
- fn = arg_running_as == MANAGER_SYSTEM ?
+ fn = arg_system ?
PKGSYSCONFDIR "/system.conf" :
PKGSYSCONFDIR "/user.conf";
- conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ?
+ conf_dirs_nulstr = arg_system ?
CONF_PATHS_NULSTR("systemd/system.conf.d") :
CONF_PATHS_NULSTR("systemd/user.conf.d");
@@ -729,6 +735,7 @@ static void manager_set_defaults(Manager *m) {
m->default_start_limit_interval = arg_default_start_limit_interval;
m->default_start_limit_burst = arg_default_start_limit_burst;
m->default_cpu_accounting = arg_default_cpu_accounting;
+ m->default_io_accounting = arg_default_io_accounting;
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
m->default_tasks_accounting = arg_default_tasks_accounting;
@@ -874,17 +881,15 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_SYSTEM:
- arg_running_as = MANAGER_SYSTEM;
+ arg_system = true;
break;
case ARG_USER:
- arg_running_as = MANAGER_USER;
+ arg_system = false;
break;
case ARG_TEST:
arg_action = ACTION_TEST;
- if (arg_no_pager < 0)
- arg_no_pager = true;
break;
case ARG_NO_PAGER:
@@ -994,8 +999,6 @@ static int parse_argv(int argc, char *argv[]) {
case 'h':
arg_action = ACTION_HELP;
- if (arg_no_pager < 0)
- arg_no_pager = true;
break;
case 'D':
@@ -1073,7 +1076,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching
return log_error_errno(r, "Failed to create serialization file: %m");
/* Make sure nothing is really destructed when we shut down */
- m->n_reloading ++;
+ m->n_reloading++;
bus_manager_send_reloading(m, true);
fds = fdset_new();
@@ -1230,10 +1233,15 @@ static int status_welcome(void) {
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read os-release file: %m");
- return status_printf(NULL, false, false,
- "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
- isempty(ansi_color) ? "1" : ansi_color,
- isempty(pretty_name) ? "GNU/Linux" : pretty_name);
+ if (log_get_show_color())
+ return status_printf(NULL, false, false,
+ "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
+ isempty(ansi_color) ? "1" : ansi_color,
+ isempty(pretty_name) ? "GNU/Linux" : pretty_name);
+ else
+ return status_printf(NULL, false, false,
+ "\nWelcome to %s!\n",
+ isempty(pretty_name) ? "GNU/Linux" : pretty_name);
}
static int write_container_id(void) {
@@ -1244,7 +1252,8 @@ static int write_container_id(void) {
if (isempty(c))
return 0;
- r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+ RUN_WITH_UMASK(0022)
+ r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
if (r < 0)
return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m");
@@ -1313,7 +1322,6 @@ int main(int argc, char *argv[]) {
/* This is compatibility support for SysV, where
* calling init as a user is identical to telinit. */
- errno = -ENOENT;
execv(SYSTEMCTL_BINARY_PATH, argv);
log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
return 1;
@@ -1344,7 +1352,7 @@ int main(int argc, char *argv[]) {
saved_argv = argv;
saved_argc = argc;
- log_show_color(isatty(STDERR_FILENO) > 0);
+ log_show_color(colors_enabled());
log_set_upgrade_syslog_to_journal(true);
/* Disable the umask logic */
@@ -1354,7 +1362,7 @@ int main(int argc, char *argv[]) {
if (getpid() == 1 && detect_container() <= 0) {
/* Running outside of a container as PID 1 */
- arg_running_as = MANAGER_SYSTEM;
+ arg_system = true;
make_null_stdio();
log_set_target(LOG_TARGET_KMSG);
log_open();
@@ -1382,13 +1390,13 @@ int main(int argc, char *argv[]) {
dual_timestamp_get(&security_finish_timestamp);
}
- if (mac_selinux_init(NULL) < 0) {
+ if (mac_selinux_init() < 0) {
error_message = "Failed to initialize SELinux policy";
goto finish;
}
if (!skip_setup) {
- if (clock_is_localtime() > 0) {
+ if (clock_is_localtime(NULL) > 0) {
int min;
/*
@@ -1438,7 +1446,7 @@ int main(int argc, char *argv[]) {
} else if (getpid() == 1) {
/* Running inside a container, as PID 1 */
- arg_running_as = MANAGER_SYSTEM;
+ arg_system = true;
log_set_target(LOG_TARGET_CONSOLE);
log_close_console(); /* force reopen of /dev/console */
log_open();
@@ -1448,12 +1456,10 @@ int main(int argc, char *argv[]) {
/* clear the kernel timestamp,
* because we are in a container */
- kernel_timestamp.monotonic = 0ULL;
- kernel_timestamp.realtime = 0ULL;
-
+ kernel_timestamp = DUAL_TIMESTAMP_NULL;
} else {
/* Running as user instance */
- arg_running_as = MANAGER_USER;
+ arg_system = false;
log_set_target(LOG_TARGET_AUTO);
log_open();
@@ -1511,7 +1517,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == MANAGER_SYSTEM) {
+ if (arg_system) {
r = parse_proc_cmdline(parse_proc_cmdline_item);
if (r < 0)
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
@@ -1532,14 +1538,14 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == MANAGER_USER &&
+ if (!arg_system &&
arg_action == ACTION_RUN &&
sd_booted() <= 0) {
log_error("Trying to run as user instance, but the system has not been booted with systemd.");
goto finish;
}
- if (arg_running_as == MANAGER_SYSTEM &&
+ if (arg_system &&
arg_action == ACTION_RUN &&
running_in_chroot() > 0) {
log_error("Cannot be run in a chroot() environment.");
@@ -1549,7 +1555,8 @@ int main(int argc, char *argv[]) {
if (arg_action == ACTION_TEST)
skip_setup = true;
- pager_open_if_enabled();
+ if (arg_action == ACTION_TEST || arg_action == ACTION_HELP)
+ pager_open(arg_no_pager, false);
if (arg_action == ACTION_HELP) {
retval = help();
@@ -1566,7 +1573,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == MANAGER_USER &&
+ if (!arg_system &&
!getenv("XDG_RUNTIME_DIR")) {
log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
goto finish;
@@ -1589,7 +1596,7 @@ int main(int argc, char *argv[]) {
if (arg_serialization)
assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0);
- if (arg_running_as == MANAGER_SYSTEM)
+ if (arg_system)
/* Become a session leader if we aren't one yet. */
setsid();
@@ -1598,7 +1605,7 @@ int main(int argc, char *argv[]) {
/* Reset the console, but only if this is really init and we
* are freshly booted */
- if (arg_running_as == MANAGER_SYSTEM && arg_action == ACTION_RUN) {
+ if (arg_system && arg_action == ACTION_RUN) {
/* If we are init, we connect stdin/stdout/stderr to
* /dev/null and make sure we don't have a controlling
@@ -1625,7 +1632,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_running_as == MANAGER_SYSTEM) {
+ if (arg_system) {
int v;
log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")",
@@ -1661,7 +1668,7 @@ int main(int argc, char *argv[]) {
arg_action == ACTION_TEST ? " test" : "", getuid(), t);
}
- if (arg_running_as == MANAGER_SYSTEM && !skip_setup) {
+ if (arg_system && !skip_setup) {
if (arg_show_status > 0)
status_welcome();
@@ -1673,7 +1680,7 @@ int main(int argc, char *argv[]) {
test_usr();
}
- if (arg_running_as == MANAGER_SYSTEM && arg_runtime_watchdog > 0)
+ if (arg_system && arg_runtime_watchdog > 0 && arg_runtime_watchdog != USEC_INFINITY)
watchdog_set_timeout(&arg_runtime_watchdog);
if (arg_timer_slack_nsec != NSEC_INFINITY)
@@ -1703,12 +1710,12 @@ int main(int argc, char *argv[]) {
}
}
- if (arg_running_as == MANAGER_USER)
+ if (!arg_system)
/* Become reaper of our children */
if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
log_warning_errno(errno, "Failed to make us a subreaper: %m");
- if (arg_running_as == MANAGER_SYSTEM) {
+ if (arg_system) {
bump_rlimit_nofile(&saved_rlimit_nofile);
if (empty_etc) {
@@ -1720,7 +1727,7 @@ int main(int argc, char *argv[]) {
}
}
- r = manager_new(arg_running_as, arg_action == ACTION_TEST, &m);
+ r = manager_new(arg_system ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, arg_action == ACTION_TEST, &m);
if (r < 0) {
log_emergency_errno(r, "Failed to allocate manager object: %m");
error_message = "Failed to allocate manager object";
@@ -1883,7 +1890,7 @@ int main(int argc, char *argv[]) {
case MANAGER_EXIT:
retval = m->return_value;
- if (m->running_as == MANAGER_USER) {
+ if (MANAGER_IS_USER(m)) {
log_debug("Exit.");
goto finish;
}
@@ -1979,7 +1986,7 @@ finish:
args[i++] = SYSTEMD_BINARY_PATH;
if (switch_root_dir)
args[i++] = "--switched-root";
- args[i++] = arg_running_as == MANAGER_SYSTEM ? "--system" : "--user";
+ args[i++] = arg_system ? "--system" : "--user";
args[i++] = "--deserialize";
args[i++] = sfd;
args[i++] = NULL;
@@ -2104,7 +2111,7 @@ finish:
assert(pos < ELEMENTSOF(command_line));
- if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) {
+ if (arm_reboot_watchdog && arg_shutdown_watchdog > 0 && arg_shutdown_watchdog != USEC_INFINITY) {
char *e;
/* If we reboot let's set the shutdown
diff --git a/src/grp-system/systemd/org.freedesktop.systemd1.conf b/src/grp-system/systemd/org.freedesktop.systemd1.conf
index 6a7a37ee92..3c64f20872 100644
--- a/src/grp-system/systemd/org.freedesktop.systemd1.conf
+++ b/src/grp-system/systemd/org.freedesktop.systemd1.conf
@@ -70,14 +70,26 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="ListUnitsByPatterns"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="ListUnitFiles"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="ListUnitFilesByPatterns"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="GetUnitFileState"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="GetUnitProcesses"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="ListJobs"/>
<allow send_destination="org.freedesktop.systemd1"
@@ -144,6 +156,10 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="ListUnitsByNames"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="StartTransientUnit"/>
<allow send_destination="org.freedesktop.systemd1"
@@ -176,6 +192,10 @@
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
+ send_member="RevertUnitFiles"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
send_member="PresetUnitFiles"/>
<allow send_destination="org.freedesktop.systemd1"
diff --git a/src/grp-system/systemd/system.conf b/src/grp-system/systemd/system.conf
index e2ded27333..db8b7acd78 100644
--- a/src/grp-system/systemd/system.conf
+++ b/src/grp-system/systemd/system.conf
@@ -34,10 +34,11 @@
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
#DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
+#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5
#DefaultEnvironment=
#DefaultCPUAccounting=no
+#DefaultIOAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
#DefaultTasksAccounting=yes
diff --git a/src/grp-system/systemd/triggers.systemd.in b/src/grp-system/systemd/triggers.systemd.in
index 9e18a39a67..0d8c303136 100644
--- a/src/grp-system/systemd/triggers.systemd.in
+++ b/src/grp-system/systemd/triggers.systemd.in
@@ -18,6 +18,8 @@
# along with systemd; If not, see <http://www.gnu.org/licenses/>.
# The contents of this are an example to be copied into systemd.spec.
+#
+# Minimum rpm version supported: 4.13.0
%transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system
-- This script will run after any package is initially installed or
diff --git a/src/grp-system/systemd/user.conf b/src/grp-system/systemd/user.conf
index 87c8164378..b427f1ef6d 100644
--- a/src/grp-system/systemd/user.conf
+++ b/src/grp-system/systemd/user.conf
@@ -23,7 +23,7 @@
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
#DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
+#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5
#DefaultEnvironment=
#DefaultLimitCPU=
diff --git a/src/grp-timedate/systemd-timedated/timedated.c b/src/grp-timedate/systemd-timedated/timedated.c
index f5ca319640..51a13fcf49 100644
--- a/src/grp-timedate/systemd-timedated/timedated.c
+++ b/src/grp-timedate/systemd-timedated/timedated.c
@@ -78,7 +78,7 @@ static int context_read_data(Context *c) {
c->zone = t;
t = NULL;
- c->local_rtc = clock_is_localtime() > 0;
+ c->local_rtc = clock_is_localtime(NULL) > 0;
return 0;
}
@@ -125,30 +125,44 @@ static int context_write_data_local_rtc(Context *c) {
if (!w)
return -ENOMEM;
} else {
- char *p, *e;
+ char *p;
+ const char *e = "\n"; /* default if there is less than 3 lines */
+ const char *prepend = "";
size_t a, b;
- p = strchr(s, '\n');
- if (!p)
- return -EIO;
-
- p = strchr(p+1, '\n');
- if (!p)
- return -EIO;
-
- p++;
- e = strchr(p, '\n');
- if (!e)
- return -EIO;
+ p = strchrnul(s, '\n');
+ if (*p == '\0')
+ /* only one line, no \n terminator */
+ prepend = "\n0\n";
+ else if (p[1] == '\0') {
+ /* only one line, with \n terminator */
+ ++p;
+ prepend = "0\n";
+ } else {
+ p = strchr(p+1, '\n');
+ if (!p) {
+ /* only two lines, no \n terminator */
+ prepend = "\n";
+ p = s + strlen(s);
+ } else {
+ char *end;
+ /* third line might have a \n terminator or not */
+ p++;
+ end = strchr(p, '\n');
+ /* if we actually have a fourth line, use that as suffix "e", otherwise the default \n */
+ if (end)
+ e = end;
+ }
+ }
a = p - s;
b = strlen(e);
- w = new(char, a + (c->local_rtc ? 5 : 3) + b + 1);
+ w = new(char, a + (c->local_rtc ? 5 : 3) + strlen(prepend) + b + 1);
if (!w)
return -ENOMEM;
- *(char*) mempcpy(stpcpy(mempcpy(w, s, a), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
+ *(char*) mempcpy(stpcpy(stpcpy(mempcpy(w, s, a), prepend), c->local_rtc ? "LOCAL" : "UTC"), e, b) = 0;
if (streq(w, NULL_ADJTIME_UTC)) {
if (unlink("/etc/adjtime") < 0)
@@ -159,7 +173,7 @@ static int context_write_data_local_rtc(Context *c) {
}
}
- mac_selinux_init("/etc");
+ mac_selinux_init();
return write_string_file_atomic_label("/etc/adjtime", w);
}
diff --git a/src/grp-timedate/timedatectl/timedatectl.c b/src/grp-timedate/timedatectl/timedatectl.c
index 28546a0ad1..1fd542fb49 100644
--- a/src/grp-timedate/timedatectl/timedatectl.c
+++ b/src/grp-timedate/timedatectl/timedatectl.c
@@ -40,14 +40,6 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static char *arg_host = NULL;
static bool arg_adjust_system_clock = false;
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
static void polkit_agent_open_if_enabled(void) {
/* Open the polkit agent as a child process if necessary */
@@ -313,7 +305,7 @@ static int list_timezones(sd_bus *bus, char **args, unsigned n) {
if (r < 0)
return log_error_errno(r, "Failed to read list of time zones: %m");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
strv_print(zones);
return 0;
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index c37e32e96b..d11756e615 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -706,7 +706,7 @@ int main(int argc, char *argv[]) {
log_open();
umask(0022);
- mac_selinux_init("/etc");
+ mac_selinux_init();
if (argc != 1) {
log_error("This program takes no arguments.");
diff --git a/src/import/Makefile b/src/import/Makefile
index 909662b1b4..a918dd5344 100644
--- a/src/import/Makefile
+++ b/src/import/Makefile
@@ -65,8 +65,6 @@ systemd_pull_SOURCES = \
src/import/import-compress.h \
src/import/curl-util.c \
src/import/curl-util.h \
- src/import/aufs-util.c \
- src/import/aufs-util.h \
src/import/qcow2-util.c \
src/import/qcow2-util.h
diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c
deleted file mode 100644
index 44aa6e2170..0000000000
--- a/src/import/aufs-util.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <ftw.h>
-
-#include "aufs-util.h"
-#include "rm-rf.h"
-#include "string-util.h"
-#include "util.h"
-
-static int nftw_cb(
- const char *fpath,
- const struct stat *sb,
- int flag,
- struct FTW *ftwbuf) {
-
- const char *fn, *original;
- char *p;
- int r;
-
- fn = fpath + ftwbuf->base;
-
- /* We remove all whiteout files, and all whiteouts */
-
- original = startswith(fn, ".wh.");
- if (!original)
- return FTW_CONTINUE;
-
- log_debug("Removing whiteout indicator %s.", fpath);
- r = rm_rf(fpath, REMOVE_ROOT|REMOVE_PHYSICAL);
- if (r < 0)
- return FTW_STOP;
-
- if (!startswith(fn, ".wh..wh.")) {
-
- p = alloca(ftwbuf->base + strlen(original));
- strcpy(mempcpy(p, fpath, ftwbuf->base), original);
-
- log_debug("Removing deleted file %s.", p);
- r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
- if (r < 0)
- return FTW_STOP;
- }
-
- return FTW_CONTINUE;
-}
-
-int aufs_resolve(const char *path) {
- int r;
-
- errno = 0;
- r = nftw(path, nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- if (r == FTW_STOP)
- return errno > 0 ? -errno : -EIO;
-
- return 0;
-}
diff --git a/src/import/curl-util.c b/src/import/curl-util.c
index a04c8c49ff..6990c47f48 100644
--- a/src/import/curl-util.c
+++ b/src/import/curl-util.c
@@ -137,7 +137,7 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v
if (sd_event_add_io(g->event, &io, fd, events, curl_glue_on_io, g) < 0)
return -1;
- sd_event_source_set_description(io, "curl-io");
+ (void) sd_event_source_set_description(io, "curl-io");
r = hashmap_put(g->ios, FD_TO_PTR(s), io);
if (r < 0) {
@@ -204,7 +204,7 @@ static int curl_glue_timer_callback(CURLM *curl, long timeout_ms, void *userdata
if (sd_event_add_time(g->event, &g->timer, clock_boottime_or_monotonic(), usec, 0, curl_glue_on_timer, g) < 0)
return -1;
- sd_event_source_set_description(g->timer, "curl-timer");
+ (void) sd_event_source_set_description(g->timer, "curl-timer");
}
return 0;
diff --git a/src/import/import-common.c b/src/import/import-common.c
index 18a30be36d..287a3382a1 100644
--- a/src/import/import-common.c
+++ b/src/import/import-common.c
@@ -136,7 +136,7 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
if (r < 0)
log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
- execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", NULL);
+ execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL);
log_error_errno(errno, "Failed to execute tar: %m");
_exit(EXIT_FAILURE);
}
@@ -210,7 +210,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
if (r < 0)
log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
- execlp("tar", "tar", "-C", path, "-c", ".", NULL);
+ execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL);
log_error_errno(errno, "Failed to execute tar: %m");
_exit(EXIT_FAILURE);
}
diff --git a/src/import/importd.c b/src/import/importd.c
index b44d0525ae..e30dfdf805 100644
--- a/src/import/importd.c
+++ b/src/import/importd.c
@@ -677,7 +677,7 @@ static int manager_new(Manager **ret) {
(void) mkdir_parents_label(sa.un.sun_path, 0755);
(void) unlink(sa.un.sun_path);
- if (bind(m->notify_fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (bind(m->notify_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
if (setsockopt(m->notify_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
diff --git a/src/import/pull-common.c b/src/import/pull-common.c
index d301d4d79e..dc4e4667a9 100644
--- a/src/import/pull-common.c
+++ b/src/import/pull-common.c
@@ -330,7 +330,7 @@ int pull_verify(PullJob *main_job,
_cleanup_close_ int sig_file = -1;
const char *p, *line;
char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX";
- _cleanup_sigkill_wait_ pid_t pid = 0;
+ _cleanup_(sigkill_waitp) pid_t pid = 0;
bool gpg_home_created = false;
int r;
diff --git a/src/import/pull-job.h b/src/import/pull-job.h
index 998857035a..3a152a50e3 100644
--- a/src/import/pull-job.h
+++ b/src/import/pull-job.h
@@ -44,15 +44,6 @@ typedef enum PullJobState {
#define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED))
-typedef enum PullJobCompression {
- PULL_JOB_UNCOMPRESSED,
- PULL_JOB_XZ,
- PULL_JOB_GZIP,
- PULL_JOB_BZIP2,
- _PULL_JOB_COMPRESSION_MAX,
- _PULL_JOB_COMPRESSION_INVALID = -1,
-} PullJobCompression;
-
struct PullJob {
PullJobState state;
int error;
diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c
index ca49f0c7d7..19155cc53a 100644
--- a/src/import/pull-raw.c
+++ b/src/import/pull-raw.c
@@ -355,10 +355,12 @@ static int raw_pull_make_local_copy(RawPull *i) {
r = copy_file_atomic(i->settings_path, local_settings, 0644, i->force_local, 0);
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
- else if (r < 0 && r != -ENOENT)
+ else if (r == -ENOENT)
+ log_debug_errno(r, "Skipping creation of settings file, since none was found.");
+ else if (r < 0)
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);
+ log_info("Created new settings file %s.", local_settings);
}
return 0;
diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c
index 1fed468b7e..e0205c3841 100644
--- a/src/import/pull-tar.c
+++ b/src/import/pull-tar.c
@@ -251,10 +251,12 @@ static int tar_pull_make_local_copy(TarPull *i) {
r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0);
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
- else if (r < 0 && r != -ENOENT)
+ else if (r == -ENOENT)
+ log_debug_errno(r, "Skipping creation of settings file, since none was found.");
+ else if (r < 0)
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);
+ log_info("Created new settings file %s.", local_settings);
}
return 0;
diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c
index 27f1fd04a1..05285e3846 100644
--- a/src/initctl/initctl.c
+++ b/src/initctl/initctl.c
@@ -314,7 +314,7 @@ static int server_init(Server *s, unsigned n_sockets) {
f->fd = fd;
LIST_PREPEND(fifo, s->fifos, f);
f->server = s;
- s->n_fifos ++;
+ s->n_fifos++;
}
r = bus_connect_system_systemd(&s->bus);
diff --git a/src/journal/Makefile b/src/journal/Makefile
deleted file mode 100644
index 4a7d6122c1..0000000000
--- a/src/journal/Makefile
+++ /dev/null
@@ -1,348 +0,0 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*-
-#
-# This file is part of systemd.
-#
-# Copyright 2010-2012 Lennart Poettering
-# Copyright 2010-2012 Kay Sievers
-# Copyright 2013 Zbigniew Jędrzejewski-Szmek
-# Copyright 2013 David Strauss
-# Copyright 2016 Luke Shumaker
-#
-# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
-include $(topsrcdir)/build-aux/Makefile.head.mk
-
-
-$(outdir)/dns_type-list.txt: src/resolve/dns-type.h
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)$(SED) -n -r 's/.* DNS_TYPE_(\w+).*/\1/p' <$< >$@
-
-$(outdir)/dns_type-to-name.h: src/resolve/dns_type-list.txt
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" } {printf " case DNS_TYPE_%s: return ", $$1; sub(/_/, "-"); printf "\"%s\";\n", $$1 } END{ print " default: return NULL;\n\t}\n}\n" }' <$< >$@
-
-$(outdir)/dns_type-from-name.gperf: src/resolve/dns_type-list.txt
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct dns_type_name { const char* name; int id; };"; print "%null-strings"; print "%%";} { s=$$1; sub(/_/, "-", s); printf "%s, ", $$s; printf "DNS_TYPE_%s\n", $$1 }' <$< >$@
-
-systemd_journald_SOURCES = \
- src/journal/journald.c \
- src/journal/journald-server.h
-
-systemd_journald_LDADD = \
- libjournal-core.la \
- libshared.la
-
-systemd_cat_SOURCES = \
- src/journal/cat.c
-
-systemd_cat_LDADD = \
- libjournal-core.la
-
-# using _CFLAGS = in the conditional below would suppress AM_CFLAGS
-journalctl_CFLAGS = \
- $(AM_CFLAGS)
-
-journalctl_SOURCES = \
- src/journal/journalctl.c
-
-journalctl_LDADD = \
- libshared.la \
- libudev-core.la
-
-ifneq ($(HAVE_QRENCODE),)
-journalctl_SOURCES += \
- src/journal/journal-qrcode.c \
- src/journal/journal-qrcode.h
-
-journalctl_CFLAGS += \
- $(QRENCODE_CFLAGS)
-
-journalctl_LDADD += \
- $(QRENCODE_LIBS)
-endif # HAVE_QRENCODE
-
-test_journal_SOURCES = \
- src/journal/test-journal.c
-
-test_journal_LDADD = \
- libjournal-core.la
-
-test_journal_send_SOURCES = \
- src/journal/test-journal-send.c
-
-test_journal_send_LDADD = \
- libjournal-core.la
-
-test_journal_syslog_SOURCES = \
- src/journal/test-journal-syslog.c
-
-test_journal_syslog_LDADD = \
- libjournal-core.la
-
-test_journal_match_SOURCES = \
- src/journal/test-journal-match.c
-
-test_journal_match_LDADD = \
- libjournal-core.la
-
-test_journal_enum_SOURCES = \
- src/journal/test-journal-enum.c
-
-test_journal_enum_LDADD = \
- libjournal-core.la
-
-test_journal_stream_SOURCES = \
- src/journal/test-journal-stream.c
-
-test_journal_stream_LDADD = \
- libjournal-core.la
-
-test_journal_flush_SOURCES = \
- src/journal/test-journal-flush.c
-
-test_journal_flush_LDADD = \
- libjournal-core.la
-
-test_journal_init_SOURCES = \
- src/journal/test-journal-init.c
-
-test_journal_init_LDADD = \
- libjournal-core.la
-
-test_journal_verify_SOURCES = \
- src/journal/test-journal-verify.c
-
-test_journal_verify_LDADD = \
- libjournal-core.la
-
-test_journal_interleaving_SOURCES = \
- src/journal/test-journal-interleaving.c
-
-test_journal_interleaving_LDADD = \
- libjournal-core.la
-
-test_mmap_cache_SOURCES = \
- src/journal/test-mmap-cache.c
-
-test_mmap_cache_LDADD = \
- libjournal-core.la
-
-test_catalog_SOURCES = \
- src/journal/test-catalog.c
-
-test_catalog_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -DCATALOG_DIR=\"$(abs_top_srcdir)/catalog\"
-
-test_catalog_LDADD = \
- libjournal-core.la
-
-test_compress_SOURCES = \
- src/journal/test-compress.c
-
-test_compress_LDADD = \
- libshared.la
-
-test_compress_benchmark_SOURCES = \
- src/journal/test-compress-benchmark.c
-
-test_compress_benchmark_LDADD = \
- libshared.la
-
-test_audit_type_SOURCES = \
- src/journal/test-audit-type.c
-
-test_audit_type_LDADD = \
- libjournal-core.la
-
-libjournal_core_la_SOURCES = \
- src/journal/journald-kmsg.c \
- src/journal/journald-kmsg.h \
- src/journal/journald-syslog.c \
- src/journal/journald-syslog.h \
- src/journal/journald-stream.c \
- src/journal/journald-stream.h \
- src/journal/journald-server.c \
- src/journal/journald-server.h \
- src/journal/journald-console.c \
- src/journal/journald-console.h \
- src/journal/journald-wall.c \
- src/journal/journald-wall.h \
- src/journal/journald-native.c \
- src/journal/journald-native.h \
- src/journal/journald-audit.c \
- src/journal/journald-audit.h \
- src/journal/journald-rate-limit.c \
- src/journal/journald-rate-limit.h \
- src/journal/journal-internal.h
-
-nodist_libjournal_core_la_SOURCES = \
- src/journal/journald-gperf.c
-
-libjournal_core_la_LIBADD = \
- libshared.la
-
-noinst_LTLIBRARIES += \
- libjournal-core.la
-
-journal-install-hook:
- -$(MKDIR_P) $(DESTDIR)/var/log/journal
- -chown 0:0 $(DESTDIR)/var/log/journal
- -chmod 755 $(DESTDIR)/var/log/journal
- -setfacl -nm g:adm:rx,d:g:adm:rx $(DESTDIR)/var/log/journal/
- -setfacl -nm g:wheel:rx,d:g:wheel:rx $(DESTDIR)/var/log/journal/
-
-journal-uninstall-hook:
- -rmdir $(DESTDIR)/var/log/journal/remote
- -rmdir $(DESTDIR)/var/log/journal/
-
-INSTALL_EXEC_HOOKS += journal-install-hook
-UNINSTALL_EXEC_HOOKS += journal-uninstall-hook
-
-# ------------------------------------------------------------------------------
-# Update catalog on installation. Do not bother if installing
-# in DESTDIR, since this is likely for packaging purposes.
-catalog-update-hook:
- -test -n "$(DESTDIR)" || $(bindir)/journalctl --update-catalog
-
-INSTALL_DATA_HOOKS += \
- catalog-update-hook
-
-catalog-remove-hook:
- -test -n "$(DESTDIR)" || rm -f $(catalogstatedir)/database
-
-UNINSTALL_DATA_HOOKS += \
- catalog-remove-hook
-
-manual_tests += \
- test-journal-enum
-
-tests += \
- test-journal \
- test-journal-send \
- test-journal-syslog \
- test-journal-match \
- test-journal-stream \
- test-journal-init \
- test-journal-verify \
- test-journal-interleaving \
- test-journal-flush \
- test-mmap-cache \
- test-catalog \
- test-audit-type
-
-ifneq ($(HAVE_COMPRESSION),)
-tests += \
- test-compress \
- test-compress-benchmark
-endif # HAVE_COMPRESSION
-
-
-libexec_PROGRAMS += \
- systemd-journald
-
-bin_PROGRAMS += \
- journalctl
-
-bin_PROGRAMS += \
- systemd-cat
-
-dist_systemunit_DATA += \
- units/systemd-journald.socket \
- units/systemd-journald-dev-log.socket \
- units/systemd-journald-audit.socket
-
-nodist_systemunit_DATA += \
- units/systemd-journald.service \
- units/systemd-journal-flush.service \
- units/systemd-journal-catalog-update.service
-
-dist_pkgsysconf_DATA += \
- src/journal/journald.conf
-
-dist_catalog_DATA = \
- catalog/systemd.be.catalog \
- catalog/systemd.be@latin.catalog \
- catalog/systemd.fr.catalog \
- catalog/systemd.it.catalog \
- catalog/systemd.pl.catalog \
- catalog/systemd.pt_BR.catalog \
- catalog/systemd.ru.catalog \
- catalog/systemd.zh_CN.catalog \
- catalog/systemd.zh_TW.catalog \
- catalog/systemd.catalog
-
-SOCKETS_TARGET_WANTS += \
- systemd-journald.socket \
- systemd-journald-dev-log.socket \
- systemd-journald-audit.socket
-
-SYSINIT_TARGET_WANTS += \
- systemd-journald.service \
- systemd-journal-flush.service \
- systemd-journal-catalog-update.service
-
-EXTRA_DIST += \
- units/systemd-journald.service.in \
- units/systemd-journal-flush.service.in \
- units/systemd-journal-catalog-update.service.in
-
-gperf_gperf_sources += \
- src/journal/journald-gperf.gperf
-
-# ------------------------------------------------------------------------------
-ifneq ($(HAVE_MICROHTTPD),)
-gatewayddocumentrootdir=$(pkgdatadir)/gatewayd
-
-libexec_PROGRAMS += \
- systemd-journal-gatewayd
-
-systemd_journal_gatewayd_SOURCES = \
- src/journal-remote/journal-gatewayd.c \
- src/journal-remote/microhttpd-util.h \
- src/journal-remote/microhttpd-util.c
-
-systemd_journal_gatewayd_LDADD = \
- libshared.la \
- $(MICROHTTPD_LIBS)
-
-ifneq ($(HAVE_GNUTLS),)
-systemd_journal_gatewayd_LDADD += \
- $(GNUTLS_LIBS)
-endif # HAVE_GNUTLS
-
-systemd_journal_gatewayd_CFLAGS = \
- $(AM_CFLAGS) \
- $(MICROHTTPD_CFLAGS)
-
-systemd_journal_gatewayd_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -DDOCUMENT_ROOT=\"$(gatewayddocumentrootdir)\"
-
-dist_systemunit_DATA += \
- units/systemd-journal-gatewayd.socket
-
-nodist_systemunit_DATA += \
- units/systemd-journal-gatewayd.service
-
-dist_gatewayddocumentroot_DATA = \
- src/journal-remote/browse.html
-
-endif # HAVE_MICROHTTPD
-
-EXTRA_DIST += \
- units/systemd-journal-gatewayd.service.in
-
-include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/libbasic/Makefile b/src/libbasic/Makefile
index 10f79ec40a..9f8d4ec995 100644
--- a/src/libbasic/Makefile
+++ b/src/libbasic/Makefile
@@ -28,10 +28,9 @@ noinst_LTLIBRARIES += \
libbasic_la_SOURCES = \
src/basic/missing.h \
+ src/basic/missing_syscall.h \
src/basic/capability-util.c \
src/basic/capability-util.h \
- src/basic/c-rbtree.c \
- src/basic/c-rbtree.h \
src/basic/conf-files.c \
src/basic/conf-files.h \
src/basic/stdio-util.h \
@@ -138,6 +137,8 @@ libbasic_la_SOURCES = \
src/basic/exit-status.h \
src/basic/virt.c \
src/basic/virt.h \
+ src/basic/architecture.c \
+ src/basic/architecture.h \
src/basic/smack-util.c \
src/basic/smack-util.h \
src/basic/device-nodes.c \
@@ -182,8 +183,6 @@ libbasic_la_SOURCES = \
src/basic/audit-util.h \
src/basic/xml.c \
src/basic/xml.h \
- src/basic/json.c \
- src/basic/json.h \
src/basic/barrier.c \
src/basic/barrier.h \
src/basic/async.c \
diff --git a/src/libbasic/MurmurHash2.c b/src/libbasic/MurmurHash2.c
index 2f4149dbe9..9020793930 100644
--- a/src/libbasic/MurmurHash2.c
+++ b/src/libbasic/MurmurHash2.c
@@ -50,7 +50,7 @@ uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed )
const unsigned char * data = (const unsigned char *)key;
- while(len >= 4)
+ while (len >= 4)
{
uint32_t k = *(uint32_t*)data;
diff --git a/src/libbasic/af-list.h b/src/libbasic/af-list.h
index 135248dc64..6a4cc03839 100644
--- a/src/libbasic/af-list.h
+++ b/src/libbasic/af-list.h
@@ -19,7 +19,23 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "string-util.h"
+
const char *af_to_name(int id);
int af_from_name(const char *name);
+static inline const char* af_to_name_short(int id) {
+ const char *f;
+
+ if (id == AF_UNSPEC)
+ return "*";
+
+ f = af_to_name(id);
+ if (!f)
+ return "unknown";
+
+ assert(startswith(f, "AF_"));
+ return f + 3;
+}
+
int af_max(void);
diff --git a/src/libbasic/alloc-util.h b/src/libbasic/alloc-util.h
index 679ba7f398..ceeee519b7 100644
--- a/src/libbasic/alloc-util.h
+++ b/src/libbasic/alloc-util.h
@@ -51,25 +51,29 @@ static inline void freep(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))
+static inline bool size_multiply_overflow(size_t size, size_t need) {
+ return _unlikely_(need != 0 && size > (SIZE_MAX / need));
+}
+
+_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
+ if (size_multiply_overflow(size, need))
return NULL;
- return malloc(a * b);
+ return malloc(size * need);
}
-_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))
+_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t size, size_t need) {
+ if (size_multiply_overflow(size, need))
return NULL;
- return realloc(p, a * b);
+ return realloc(p, size * need);
}
-_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))
+_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
+ if (size_multiply_overflow(size, need))
return NULL;
- return memdup(p, a * b);
+ return memdup(p, size * need);
}
void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size);
diff --git a/src/libshared/architecture.c b/src/libbasic/architecture.c
index a9ecfc1cd6..b1c8e91f50 100644
--- a/src/libshared/architecture.c
+++ b/src/libbasic/architecture.c
@@ -63,7 +63,7 @@ int uname_architecture(void) {
#elif defined(__s390__) || defined(__s390x__)
{ "s390x", ARCHITECTURE_S390X },
{ "s390", ARCHITECTURE_S390 },
-#elif defined(__sparc__) || defined(__sparc64__)
+#elif defined(__sparc__)
{ "sparc64", ARCHITECTURE_SPARC64 },
{ "sparc", ARCHITECTURE_SPARC },
#elif defined(__mips__) || defined(__mips64__)
@@ -121,6 +121,8 @@ int uname_architecture(void) {
{ "tilegx", ARCHITECTURE_TILEGX },
#elif defined(__cris__)
{ "crisv32", ARCHITECTURE_CRIS },
+#elif defined(__nios2__)
+ { "nios2", ARCHITECTURE_NIOS2 },
#else
#error "Please register your architecture here!"
#endif
@@ -171,6 +173,7 @@ static const char *const architecture_table[_ARCHITECTURE_MAX] = {
[ARCHITECTURE_M68K] = "m68k",
[ARCHITECTURE_TILEGX] = "tilegx",
[ARCHITECTURE_CRIS] = "cris",
+ [ARCHITECTURE_NIOS2] = "nios2",
};
DEFINE_STRING_TABLE_LOOKUP(architecture, int);
diff --git a/src/libshared/architecture.h b/src/libbasic/architecture.h
index 26679e28c6..b3e4d85906 100644
--- a/src/libshared/architecture.h
+++ b/src/libbasic/architecture.h
@@ -57,6 +57,7 @@ enum {
ARCHITECTURE_M68K,
ARCHITECTURE_TILEGX,
ARCHITECTURE_CRIS,
+ ARCHITECTURE_NIOS2,
_ARCHITECTURE_MAX,
_ARCHITECTURE_INVALID = -1
};
@@ -77,20 +78,20 @@ 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"
+# define SECONDARY_ARCHITECTURE ARCHITECTURE_X86
#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
# define LIB_ARCH_TUPLE "ppc64-linux-gnu"
+# define SECONDARY_ARCHITECTURE ARCHITECTURE_PPC
# else
# define native_architecture() ARCHITECTURE_PPC64_LE
# define LIB_ARCH_TUPLE "powerpc64le-linux-gnu"
+# define SECONDARY_ARCHITECTURE ARCHITECTURE_PPC_LE
# endif
-# define PROC_CPUINFO_MODEL "cpu"
#elif defined(__powerpc__)
# if __BYTE_ORDER == __BIG_ENDIAN
# define native_architecture() ARCHITECTURE_PPC
@@ -99,32 +100,28 @@ 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"
+# define SECONDARY_ARCHITECTURE ARCHITECTURE_S390
#elif defined(__s390__)
# define native_architecture() ARCHITECTURE_S390
# define LIB_ARCH_TUPLE "s390-linux-gnu"
-#elif defined(__sparc64__)
+#elif defined(__sparc__) && defined (__arch64__)
# 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
@@ -133,7 +130,6 @@ 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
@@ -142,7 +138,6 @@ 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"
@@ -178,7 +173,6 @@ 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"
@@ -194,14 +188,12 @@ int uname_architecture(void);
#elif defined(__cris__)
# define native_architecture() ARCHITECTURE_CRIS
# error "Missing LIB_ARCH_TUPLE for CRIS"
+#elif defined(__nios2__)
+# define native_architecture() ARCHITECTURE_NIOS2
+# define LIB_ARCH_TUPLE "nios2-linux-gnu"
#else
# error "Please register your architecture here!"
#endif
-#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/libbasic/btrfs-util.h b/src/libbasic/btrfs-util.h
index 29f8ba63d3..db431f5b74 100644
--- a/src/libbasic/btrfs-util.h
+++ b/src/libbasic/btrfs-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
diff --git a/src/libbasic/c-rbtree.c b/src/libbasic/c-rbtree.c
deleted file mode 100644
index 914d7e5229..0000000000
--- a/src/libbasic/c-rbtree.c
+++ /dev/null
@@ -1,679 +0,0 @@
-/***
- This file is part of systemd. See COPYING for details.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * RB-Tree Implementation
- * This implements the insertion/removal of elements in RB-Trees. You're highly
- * recommended to have an RB-Tree documentation at hand when reading this. Both
- * insertion and removal can be split into a handful of situations that can
- * occur. Those situations are enumerated as "Case 1" to "Case n" here, and
- * follow closely the cases described in most RB-Tree documentations. This file
- * does not explain why it is enough to handle just those cases, nor does it
- * provide a proof of correctness. Dig out your algorithm 101 handbook if
- * you're interested.
- *
- * This implementation is *not* straightforward. Usually, a handful of
- * rotation, reparent, swap and link helpers can be used to implement the
- * rebalance operations. However, those often perform unnecessary writes.
- * Therefore, this implementation hard-codes all the operations. You're highly
- * recommended to look at the two basic helpers before reading the code:
- * c_rbtree_swap_child()
- * c_rbtree_set_parent_and_color()
- * Those are the only helpers used, hence, you should really know what they do
- * before digging into the code.
- *
- * For a highlevel documentation of the API, see the header file and docbook
- * comments.
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include "c-rbtree.h"
-
-enum {
- C_RBNODE_RED = 0,
- C_RBNODE_BLACK = 1,
-};
-
-static inline unsigned long c_rbnode_color(CRBNode *n) {
- return (unsigned long)n->__parent_and_color & 1UL;
-}
-
-static inline _Bool c_rbnode_is_red(CRBNode *n) {
- return c_rbnode_color(n) == C_RBNODE_RED;
-}
-
-static inline _Bool c_rbnode_is_black(CRBNode *n) {
- return c_rbnode_color(n) == C_RBNODE_BLACK;
-}
-
-/**
- * c_rbnode_leftmost() - return leftmost child
- * @n: current node, or NULL
- *
- * This returns the leftmost child of @n. If @n is NULL, this will return NULL.
- * In all other cases, this function returns a valid pointer. That is, if @n
- * does not have any left children, this returns @n.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to leftmost child, or NULL.
- */
-CRBNode *c_rbnode_leftmost(CRBNode *n) {
- if (n)
- while (n->left)
- n = n->left;
- return n;
-}
-
-/**
- * c_rbnode_rightmost() - return rightmost child
- * @n: current node, or NULL
- *
- * This returns the rightmost child of @n. If @n is NULL, this will return
- * NULL. In all other cases, this function returns a valid pointer. That is, if
- * @n does not have any right children, this returns @n.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to rightmost child, or NULL.
- */
-CRBNode *c_rbnode_rightmost(CRBNode *n) {
- if (n)
- while (n->right)
- n = n->right;
- return n;
-}
-
-/**
- * c_rbnode_next() - return next node
- * @n: current node, or NULL
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically next node to @n. If @n is NULL, the last node or
- * unlinked, this returns NULL.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to next node, or NULL.
- */
-CRBNode *c_rbnode_next(CRBNode *n) {
- CRBNode *p;
-
- if (!c_rbnode_is_linked(n))
- return NULL;
- if (n->right)
- return c_rbnode_leftmost(n->right);
-
- while ((p = c_rbnode_parent(n)) && n == p->right)
- n = p;
-
- return p;
-}
-
-/**
- * c_rbnode_prev() - return previous node
- * @n: current node, or NULL
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically previous node to @n. If @n is NULL, the first node or
- * unlinked, this returns NULL.
- *
- * Worst case runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to previous node, or NULL.
- */
-CRBNode *c_rbnode_prev(CRBNode *n) {
- CRBNode *p;
-
- if (!c_rbnode_is_linked(n))
- return NULL;
- if (n->left)
- return c_rbnode_rightmost(n->left);
-
- while ((p = c_rbnode_parent(n)) && n == p->left)
- n = p;
-
- return p;
-}
-
-/**
- * c_rbtree_first() - return first node
- * @t: tree to operate on
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically first node in @t. If @t is empty, NULL is returned.
- *
- * Fixed runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to first node, or NULL.
- */
-CRBNode *c_rbtree_first(CRBTree *t) {
- assert(t);
- return c_rbnode_leftmost(t->root);
-}
-
-/**
- * c_rbtree_last() - return last node
- * @t: tree to operate on
- *
- * An RB-Tree always defines a linear order of its elements. This function
- * returns the logically last node in @t. If @t is empty, NULL is returned.
- *
- * Fixed runtime (n: number of elements in tree): O(log(n))
- *
- * Return: Pointer to last node, or NULL.
- */
-CRBNode *c_rbtree_last(CRBTree *t) {
- assert(t);
- return c_rbnode_rightmost(t->root);
-}
-
-/*
- * Set the color and parent of a node. This should be treated as a simple
- * assignment of the 'color' and 'parent' fields of the node. No other magic is
- * applied. But since both fields share its backing memory, this helper
- * function is provided.
- */
-static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigned long c) {
- assert(!((unsigned long)p & 1));
- assert(c < 2);
- n->__parent_and_color = (CRBNode*)((unsigned long)p | c);
-}
-
-/* same as c_rbnode_set_parent_and_color(), but keeps the current parent */
-static inline void c_rbnode_set_color(CRBNode *n, unsigned long c) {
- c_rbnode_set_parent_and_color(n, c_rbnode_parent(n), c);
-}
-
-/* same as c_rbnode_set_parent_and_color(), but keeps the current color */
-static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) {
- c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n));
-}
-
-/*
- * This function partially replaces an existing child pointer to a new one. The
- * existing child must be given as @old, the new child as @new. @p must be the
- * parent of @old (or NULL if it has no parent).
- * This function ensures that the parent of @old now points to @new. However,
- * it does *NOT* change the parent pointer of @new. The caller must ensure
- * this.
- * If @p is NULL, this function ensures that the root-pointer is adjusted
- * instead (given as @t).
- */
-static inline void c_rbtree_swap_child(CRBTree *t, CRBNode *p, CRBNode *old, CRBNode *new) {
- if (p) {
- if (p->left == old)
- p->left = new;
- else
- p->right = new;
- } else {
- t->root = new;
- }
-}
-
-static inline CRBNode *c_rbtree_paint_one(CRBTree *t, CRBNode *n) {
- CRBNode *p, *g, *gg, *u, *x;
-
- /*
- * Paint a single node according to RB-Tree rules. The node must
- * already be linked into the tree and painted red.
- * We repaint the node or rotate the tree, if required. In case a
- * recursive repaint is required, the next node to be re-painted
- * is returned.
- * p: parent
- * g: grandparent
- * gg: grandgrandparent
- * u: uncle
- * x: temporary
- */
-
- /* node is red, so we can access the parent directly */
- p = n->__parent_and_color;
-
- if (!p) {
- /* Case 1:
- * We reached the root. Mark it black and be done. As all
- * leaf-paths share the root, the ratio of black nodes on each
- * path stays the same. */
- c_rbnode_set_parent_and_color(n, p, C_RBNODE_BLACK);
- n = NULL;
- } else if (c_rbnode_is_black(p)) {
- /* Case 2:
- * The parent is already black. As our node is red, we did not
- * change the number of black nodes on any path, nor do we have
- * multiple consecutive red nodes. */
- n = NULL;
- } else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */
- g = p->__parent_and_color;
- gg = c_rbnode_parent(g);
- u = g->right;
-
- if (u && c_rbnode_is_red(u)) {
- /* Case 3:
- * Parent and uncle are both red. We know the
- * grandparent must be black then. Repaint parent and
- * uncle black, the grandparent red and recurse into
- * the grandparent. */
- c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED);
- n = g;
- } else {
- /* parent is red, uncle is black */
-
- if (n == p->right) {
- /* Case 4:
- * We're the right child. Rotate on parent to
- * become left child, so we can handle it the
- * same as case 5. */
- x = n->left;
- p->right = n->left;
- n->left = p;
- if (x)
- c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED);
- p = n;
- }
-
- /* 'n' is invalid from here on! */
- n = NULL;
-
- /* Case 5:
- * We're the red left child or a red parent, black
- * grandparent and uncle. Rotate on grandparent and
- * switch color with parent. Number of black nodes on
- * each path stays the same, but we got rid of the
- * double red path. As the grandparent is still black,
- * we're done. */
- x = p->right;
- g->left = x;
- p->right = g;
- if (x)
- c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED);
- c_rbtree_swap_child(t, gg, g, p);
- }
- } else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */
- g = p->__parent_and_color;
- gg = c_rbnode_parent(g);
- u = g->left;
-
- if (u && c_rbnode_is_red(u)) {
- c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED);
- n = g;
- } else {
- if (n == p->left) {
- x = n->right;
- p->left = n->right;
- n->right = p;
- if (x)
- c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED);
- p = n;
- }
-
- n = NULL;
-
- x = p->left;
- g->right = x;
- p->left = g;
- if (x)
- c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED);
- c_rbtree_swap_child(t, gg, g, p);
- }
- }
-
- return n;
-}
-
-static inline void c_rbtree_paint(CRBTree *t, CRBNode *n) {
- assert(t);
- assert(n);
-
- while (n)
- n = c_rbtree_paint_one(t, n);
-}
-
-/**
- * c_rbtree_add() - add node to tree
- * @t: tree to operate one
- * @p: parent node to link under, or NULL
- * @l: left/right slot of @p (or root) to link at
- * @n: node to add
- *
- * This links @n into the tree given as @t. The caller must provide the exact
- * spot where to link the node. That is, the caller must traverse the tree
- * based on their search order. Once they hit a leaf where to insert the node,
- * call this function to link it and rebalance the tree.
- *
- * A typical insertion would look like this (@t is your tree, @n is your node):
- *
- * CRBNode **i, *p;
- *
- * i = &t->root;
- * p = NULL;
- * while (*i) {
- * p = *i;
- * if (compare(n, *i) < 0)
- * i = &(*i)->left;
- * else
- * i = &(*i)->right;
- * }
- *
- * c_rbtree_add(t, p, i, n);
- *
- * Once the node is linked into the tree, a simple lookup on the same tree can
- * be coded like this:
- *
- * CRBNode *i;
- *
- * i = t->root;
- * while (i) {
- * int v = compare(n, i);
- * if (v < 0)
- * i = (*i)->left;
- * else if (v > 0)
- * i = (*i)->right;
- * else
- * break;
- * }
- *
- * When you add nodes to a tree, the memory contents of the node do not matter.
- * That is, there is no need to initialize the node via c_rbnode_init().
- * However, if you relink nodes multiple times during their lifetime, it is
- * usually very convenient to use c_rbnode_init() and c_rbtree_remove_init().
- * In those cases, you should validate that a node is unlinked before you call
- * c_rbtree_add().
- */
-void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) {
- assert(t);
- assert(l);
- assert(n);
- assert(!p || l == &p->left || l == &p->right);
- assert(p || l == &t->root);
-
- c_rbnode_set_parent_and_color(n, p, C_RBNODE_RED);
- n->left = n->right = NULL;
- *l = n;
-
- c_rbtree_paint(t, n);
-}
-
-static inline CRBNode *c_rbtree_rebalance_one(CRBTree *t, CRBNode *p, CRBNode *n) {
- CRBNode *s, *x, *y, *g;
-
- /*
- * Rebalance tree after a node was removed. This happens only if you
- * remove a black node and one path is now left with an unbalanced
- * number or black nodes.
- * This function assumes all paths through p and n have one black node
- * less than all other paths. If recursive fixup is required, the
- * current node is returned.
- */
-
- if (n == p->left) {
- s = p->right;
- if (c_rbnode_is_red(s)) {
- /* Case 3:
- * We have a red node as sibling. Rotate it onto our
- * side so we can later on turn it black. This way, we
- * gain the additional black node in our path. */
- g = c_rbnode_parent(p);
- x = s->left;
- p->right = x;
- s->left = p;
- c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
- c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED);
- c_rbtree_swap_child(t, g, p, s);
- s = x;
- }
-
- x = s->right;
- if (!x || c_rbnode_is_black(x)) {
- y = s->left;
- if (!y || c_rbnode_is_black(y)) {
- /* Case 4:
- * Our sibling is black and has only black
- * children. Flip it red and turn parent black.
- * This way we gained a black node in our path,
- * or we fix it recursively one layer up, which
- * will rotate the red sibling as parent. */
- c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED);
- if (c_rbnode_is_black(p))
- return p;
-
- c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK);
- return NULL;
- }
-
- /* Case 5:
- * Left child of our sibling is red, right one is black.
- * Rotate on parent so the right child of our sibling is
- * now red, and we can fall through to case 6. */
- x = y->right;
- s->left = y->right;
- y->right = s;
- p->right = y;
- if (x)
- c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
- x = s;
- s = y;
- }
-
- /* Case 6:
- * The right child of our sibling is red. Rotate left and flip
- * colors, which gains us an additional black node in our path,
- * that was previously on our sibling. */
- g = c_rbnode_parent(p);
- y = s->left;
- p->right = y;
- s->left = p;
- c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
- if (y)
- c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y));
- c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
- c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK);
- c_rbtree_swap_child(t, g, p, s);
- } else /* if (!n || n == p->right) */ { /* same as above, but mirrored */
- s = p->left;
- if (c_rbnode_is_red(s)) {
- g = c_rbnode_parent(p);
- x = s->right;
- p->left = x;
- s->right = p;
- c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(s, g, C_RBNODE_BLACK);
- c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED);
- c_rbtree_swap_child(t, g, p, s);
- s = x;
- }
-
- x = s->left;
- if (!x || c_rbnode_is_black(x)) {
- y = s->right;
- if (!y || c_rbnode_is_black(y)) {
- c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED);
- if (c_rbnode_is_black(p))
- return p;
-
- c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK);
- return NULL;
- }
-
- x = y->left;
- s->right = y->left;
- y->left = s;
- p->left = y;
- if (x)
- c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
- x = s;
- s = y;
- }
-
- g = c_rbnode_parent(p);
- y = s->right;
- p->left = y;
- s->right = p;
- c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK);
- if (y)
- c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y));
- c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p));
- c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK);
- c_rbtree_swap_child(t, g, p, s);
- }
-
- return NULL;
-}
-
-static inline void c_rbtree_rebalance(CRBTree *t, CRBNode *p) {
- CRBNode *n = NULL;
-
- assert(t);
- assert(p);
-
- do {
- n = c_rbtree_rebalance_one(t, p, n);
- p = n ? c_rbnode_parent(n) : NULL;
- } while (p);
-}
-
-/**
- * c_rbtree_remove() - remove node from tree
- * @t: tree to operate one
- * @n: node to remove
- *
- * This removes the given node from its tree. Once unlinked, the tree is
- * rebalanced.
- * The caller *must* ensure that the given tree is actually the tree it is
- * linked on. Otherwise, behavior is undefined.
- *
- * This does *NOT* reset @n to being unlinked (for performance reason, this
- * function *never* modifies @n at all). If you need this, use
- * c_rbtree_remove_init().
- */
-void c_rbtree_remove(CRBTree *t, CRBNode *n) {
- CRBNode *p, *s, *gc, *x, *next = NULL;
- unsigned long c;
-
- assert(t);
- assert(n);
- assert(c_rbnode_is_linked(n));
-
- /*
- * There are three distinct cases during node removal of a tree:
- * * The node has no children, in which case it can simply be removed.
- * * The node has exactly one child, in which case the child displaces
- * its parent.
- * * The node has two children, in which case there is guaranteed to
- * be a successor to the node (successor being the node ordered
- * directly after it). This successor cannot have two children by
- * itself (two interior nodes can never be successive). Therefore,
- * we can simply swap the node with its successor (including color)
- * and have reduced this case to either of the first two.
- *
- * Whenever the node we removed was black, we have to rebalance the
- * tree. Note that this affects the actual node we _remove_, not @n (in
- * case we swap it).
- *
- * p: parent
- * s: successor
- * gc: grand-...-child
- * x: temporary
- * next: next node to rebalance on
- */
-
- if (!n->left) {
- /*
- * Case 1:
- * The node has no left child. If it neither has a right child,
- * it is a leaf-node and we can simply unlink it. If it also
- * was black, we have to rebalance, as always if we remove a
- * black node.
- * But if the node has a right child, the child *must* be red
- * (otherwise, the right path has more black nodes as the
- * non-existing left path), and the node to be removed must
- * hence be black. We simply replace the node with its child,
- * turning the red child black, and thus no rebalancing is
- * required.
- */
- p = c_rbnode_parent(n);
- c = c_rbnode_color(n);
- c_rbtree_swap_child(t, p, n, n->right);
- if (n->right)
- c_rbnode_set_parent_and_color(n->right, p, c);
- else
- next = (c == C_RBNODE_BLACK) ? p : NULL;
- } else if (!n->right) {
- /*
- * Case 1.1:
- * The node has exactly one child, and it is on the left. Treat
- * it as mirrored case of Case 1 (i.e., replace the node by its
- * child).
- */
- p = c_rbnode_parent(n);
- c = c_rbnode_color(n);
- c_rbtree_swap_child(t, p, n, n->left);
- c_rbnode_set_parent_and_color(n->left, p, c);
- } else {
- /*
- * Case 2:
- * We are dealing with a full interior node with a child not on
- * both sides. Find its successor and swap it. Then remove the
- * node similar to Case 1. For performance reasons we don't
- * perform the full swap, but skip links that are about to be
- * removed, anyway.
- */
- s = n->right;
- if (!s->left) {
- /* right child is next, no need to touch grandchild */
- p = s;
- gc = s->right;
- } else {
- /* find successor and swap partially */
- s = c_rbnode_leftmost(s);
- p = c_rbnode_parent(s);
-
- gc = s->right;
- p->left = s->right;
- s->right = n->right;
- c_rbnode_set_parent(n->right, s);
- }
-
- /* node is partially swapped, now remove as in Case 1 */
- s->left = n->left;
- c_rbnode_set_parent(n->left, s);
-
- x = c_rbnode_parent(n);
- c = c_rbnode_color(n);
- c_rbtree_swap_child(t, x, n, s);
- if (gc)
- c_rbnode_set_parent_and_color(gc, p, C_RBNODE_BLACK);
- else
- next = c_rbnode_is_black(s) ? p : NULL;
- c_rbnode_set_parent_and_color(s, x, c);
- }
-
- if (next)
- c_rbtree_rebalance(t, next);
-}
diff --git a/src/libbasic/c-rbtree.h b/src/libbasic/c-rbtree.h
deleted file mode 100644
index 20c5515ca1..0000000000
--- a/src/libbasic/c-rbtree.h
+++ /dev/null
@@ -1,297 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd. See COPYING for details.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * Standalone Red-Black-Tree Implementation in Standard ISO-C11
- *
- * This header provides an RB-Tree API, that is fully implemented in ISO-C11
- * and has no external dependencies. Furthermore, tree traversal, memory
- * allocations, and key comparisons a fully in control of the API user. The
- * implementation only provides the RB-Tree specific rebalancing and coloring.
- *
- * A tree is represented by the "CRBTree" structure. It contains a *singly*
- * field, which is a pointer to the root node. If NULL, the tree is empty. If
- * non-NULL, there is at least a single element in the tree.
- *
- * Each node of the tree is represented by the "CRBNode" structure. It has
- * three fields. The @left and @right members can be accessed by the API user
- * directly to traverse the tree. The third member is an implementation detail
- * and encodes the parent pointer and color of the node.
- * API users are required to embed the CRBNode object into their own objects
- * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode
- * pointers into pointers to their own structure.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct CRBNode CRBNode;
-typedef struct CRBTree CRBTree;
-
-/**
- * struct CRBNode - Node of a Red-Black Tree
- * @__parent_and_color: internal state
- * @left: left child, or NULL
- * @right: right child, or NULL
- *
- * Each node in an RB-Tree must embed an CRBNode object. This object contains
- * pointers to its left and right child, which can be freely accessed by the
- * API user at any time. They are NULL, if the node does not have a left/right
- * child.
- *
- * The @__parent_and_color field must never be accessed directly. It encodes
- * the pointer to the parent node, and the color of the node. Use the accessor
- * functions instead.
- *
- * There is no reason to initialize a CRBNode object before linking it.
- * However, if you need a boolean state that tells you whether the node is
- * linked or not, you should initialize the node via c_rbnode_init() or
- * C_RBNODE_INIT.
- */
-struct CRBNode {
- CRBNode *__parent_and_color;
- CRBNode *left;
- CRBNode *right;
-};
-
-#define C_RBNODE_INIT(_var) { .__parent_and_color = &(_var) }
-
-CRBNode *c_rbnode_leftmost(CRBNode *n);
-CRBNode *c_rbnode_rightmost(CRBNode *n);
-CRBNode *c_rbnode_next(CRBNode *n);
-CRBNode *c_rbnode_prev(CRBNode *n);
-
-/**
- * struct CRBTree - Red-Black Tree
- * @root: pointer to the root node, or NULL
- *
- * Each Red-Black Tree is rooted in an CRBTree object. This object contains a
- * pointer to the root node of the tree. The API user is free to access the
- * @root member at any time, and use it to traverse the tree.
- *
- * To initialize an RB-Tree, set it to NULL / all zero.
- */
-struct CRBTree {
- CRBNode *root;
-};
-
-CRBNode *c_rbtree_first(CRBTree *t);
-CRBNode *c_rbtree_last(CRBTree *t);
-
-void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n);
-void c_rbtree_remove(CRBTree *t, CRBNode *n);
-
-/**
- * c_rbnode_init() - mark a node as unlinked
- * @n: node to operate on
- *
- * This marks the node @n as unlinked. The node will be set to a valid state
- * that can never happen if the node is linked in a tree. Furthermore, this
- * state is fully known to the implementation, and as such handled gracefully
- * in all cases.
- *
- * You are *NOT* required to call this on your node. c_rbtree_add() can handle
- * uninitialized nodes just fine. However, calling this allows to use
- * c_rbnode_is_linked() to check for the state of a node. Furthermore,
- * iterators and accessors can be called on initialized (yet unlinked) nodes.
- *
- * Use the C_RBNODE_INIT macro if you want to initialize static variables.
- */
-static inline void c_rbnode_init(CRBNode *n) {
- *n = (CRBNode)C_RBNODE_INIT(*n);
-}
-
-/**
- * c_rbnode_is_linked() - check whether a node is linked
- * @n: node to check, or NULL
- *
- * This checks whether the passed node is linked. If you pass NULL, or if the
- * node is not linked into a tree, this will return false. Otherwise, this
- * returns true.
- *
- * Note that you must have either linked the node or initialized it, before
- * calling this function. Never call this function on uninitialized nodes.
- * Furthermore, removing a node via c_rbtree_remove() does *NOT* mark the node
- * as unlinked. You have to call c_rbnode_init() yourself after removal, or use
- * the c_rbtree_remove_init() helper.
- *
- * Return: true if the node is linked, false if not.
- */
-static inline _Bool c_rbnode_is_linked(CRBNode *n) {
- return n && n->__parent_and_color != n;
-}
-
-/**
- * c_rbnode_parent() - return parent pointer
- * @n node to access
- *
- * This returns a pointer to the parent of the given node @n. If @n does not
- * have a parent, NULL is returned. If @n is not linked, @n itself is returned.
- *
- * You should not call this on unlinked or uninitialized nodes! If you do, you
- * better know how its semantics.
- *
- * Return: Pointer to parent.
- */
-static inline CRBNode *c_rbnode_parent(CRBNode *n) {
- return (CRBNode*)((unsigned long)n->__parent_and_color & ~1UL);
-}
-
-/**
- * c_rbtree_remove_init() - safely remove node from tree and reinitialize it
- * @t: tree to operate on
- * @n: node to remove, or NULL
- *
- * This is almost the same as c_rbtree_remove(), but extends it slightly, to be
- * more convenient to use in many cases:
- * - if @n is unlinked or NULL, this is a no-op
- * - @n is reinitialized after being removed
- */
-static inline void c_rbtree_remove_init(CRBTree *t, CRBNode *n) {
- if (c_rbnode_is_linked(n)) {
- c_rbtree_remove(t, n);
- c_rbnode_init(n);
- }
-}
-
-/**
- * CRBCompareFunc - compare a node to a key
- * @t: tree where the node is linked to
- * @k: key to compare
- * @n: node to compare
- *
- * If you use the tree-traversal helpers (which are optional), you need to
- * provide this callback so they can compare nodes in a tree to the key you
- * look for.
- *
- * The tree @t is provided as optional context to this callback. The key you
- * look for is provided as @k, the current node that should be compared to is
- * provided as @n. This function should work like strcmp(), that is, return -1
- * if @key orders before @n, 0 if both compare equal, and 1 if it orders after
- * @n.
- */
-typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n);
-
-/**
- * c_rbtree_find_node() - find node
- * @t: tree to search through
- * @f: comparison function
- * @k: key to search for
- *
- * This searches through @t for a node that compares equal to @k. The function
- * @f must be provided by the caller, which is used to compare nodes to @k. See
- * the documentation of CRBCompareFunc for details.
- *
- * If there are multiple entries that compare equal to @k, this will return a
- * pseudo-randomly picked node. If you need stable lookup functions for trees
- * where duplicate entries are allowed, you better code your own lookup.
- *
- * Return: Pointer to matching node, or NULL.
- */
-static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) {
- CRBNode *i;
-
- assert(t);
- assert(f);
-
- i = t->root;
- while (i) {
- int v = f(t, (void *)k, i);
- if (v < 0)
- i = i->left;
- else if (v > 0)
- i = i->right;
- else
- return i;
- }
-
- return NULL;
-}
-
-/**
- * c_rbtree_find_entry() - find entry
- * @_t: tree to search through
- * @_f: comparison function
- * @_k: key to search for
- * @_t: type of the structure that embeds the nodes
- * @_o: name of the node-member in type @_t
- *
- * This is very similar to c_rbtree_find_node(), but instead of returning a
- * pointer to the CRBNode, it returns a pointer to the surrounding object. This
- * object must embed the CRBNode object. The type of the surrounding object
- * must be given as @_t, and the name of the embedded CRBNode member as @_o.
- *
- * See c_rbtree_find_node() for more details.
- *
- * Return: Pointer to found entry, NULL if not found.
- */
-#define c_rbtree_find_entry(_m, _f, _k, _t, _o) \
- ((_t *)(((char *)c_rbtree_find_node((_m), (_f), (_k)) ?: \
- (char *)NULL + offsetof(_t, _o)) - offsetof(_t, _o)))
-
-/**
- * c_rbtree_find_slot() - find slot to insert new node
- * @t: tree to search through
- * @f: comparison function
- * @k: key to search for
- * @p: output storage for parent pointer
- *
- * This searches through @t just like c_rbtree_find_node() does. However,
- * instead of returning a pointer to a node that compares equal to @k, this
- * searches for a slot to insert a node with key @k. A pointer to the slot is
- * returned, and a pointer to the parent of the slot is stored in @p. Both
- * can be passed directly to c_rbtree_add(), together with your node to insert.
- *
- * If there already is a node in the tree, that compares equal to @k, this will
- * return NULL and store the conflicting node in @p. In all other cases,
- * this will return a pointer (non-NULL) to the empty slot to insert the node
- * at. @p will point to the parent node of that slot.
- *
- * If you want trees that allow duplicate nodes, you better code your own
- * insertion function.
- *
- * Return: Pointer to slot to insert node, or NULL on conflicts.
- */
-static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) {
- CRBNode **i;
-
- assert(t);
- assert(f);
- assert(p);
-
- i = &t->root;
- *p = NULL;
- while (*i) {
- int v = f(t, (void *)k, *i);
- *p = *i;
- if (v < 0)
- i = &(*i)->left;
- else if (v > 0)
- i = &(*i)->right;
- else
- return NULL;
- }
-
- return i;
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/src/libbasic/calendarspec.c b/src/libbasic/calendarspec.c
index 775879076d..6e0bab9b94 100644
--- a/src/libbasic/calendarspec.c
+++ b/src/libbasic/calendarspec.c
@@ -114,7 +114,7 @@ static void sort_chain(CalendarComponent **c) {
static void fix_year(CalendarComponent *c) {
/* Turns 12 → 2012, 89 → 1989 */
- while(c) {
+ while (c) {
CalendarComponent *n = c->next;
if (c->value >= 0 && c->value < 70)
@@ -978,7 +978,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
for (;;) {
/* Normalize the current date */
- mktime_or_timegm(&c, spec->utc);
+ (void) mktime_or_timegm(&c, spec->utc);
c.tm_isdst = -1;
c.tm_year += 1900;
@@ -990,8 +990,10 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
}
- if (r < 0 || tm_out_of_bounds(&c, spec->utc))
+ if (r < 0)
return r;
+ if (tm_out_of_bounds(&c, spec->utc))
+ return -ENOENT;
c.tm_mon += 1;
r = find_matching_component(spec->month, &c.tm_mon);
@@ -1002,7 +1004,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
}
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
- c.tm_year ++;
+ c.tm_year++;
c.tm_mon = 0;
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
@@ -1013,7 +1015,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
if (r > 0)
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
- c.tm_mon ++;
+ c.tm_mon++;
c.tm_mday = 1;
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
continue;
@@ -1027,18 +1029,18 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
r = find_matching_component(spec->hour, &c.tm_hour);
if (r > 0)
- c.tm_min = c.tm_sec = 0;
+ c.tm_min = c.tm_sec = tm_usec = 0;
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
- c.tm_mday ++;
+ c.tm_mday++;
c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0;
continue;
}
r = find_matching_component(spec->minute, &c.tm_min);
if (r > 0)
- c.tm_sec = 0;
+ c.tm_sec = tm_usec = 0;
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
- c.tm_hour ++;
+ c.tm_hour++;
c.tm_min = c.tm_sec = tm_usec = 0;
continue;
}
@@ -1049,7 +1051,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) {
c.tm_sec /= USEC_PER_SEC;
if (r < 0 || tm_out_of_bounds(&c, spec->utc)) {
- c.tm_min ++;
+ c.tm_min++;
c.tm_sec = tm_usec = 0;
continue;
}
diff --git a/src/libbasic/cgroup-util.c b/src/libbasic/cgroup-util.c
index 6ef00d51df..7cdc97ee3c 100644
--- a/src/libbasic/cgroup-util.c
+++ b/src/libbasic/cgroup-util.c
@@ -101,6 +101,39 @@ int cg_read_pid(FILE *f, pid_t *_pid) {
return 1;
}
+int cg_read_event(const char *controller, const char *path, const char *event,
+ char **val)
+{
+ _cleanup_free_ char *events = NULL, *content = NULL;
+ char *p, *line;
+ int r;
+
+ r = cg_get_path(controller, path, "cgroup.events", &events);
+ if (r < 0)
+ return r;
+
+ r = read_full_file(events, &content, NULL);
+ if (r < 0)
+ return r;
+
+ p = content;
+ while ((line = strsep(&p, "\n"))) {
+ char *key;
+
+ key = strsep(&line, " ");
+ if (!key || !line)
+ return -EINVAL;
+
+ if (strcmp(key, event))
+ continue;
+
+ *val = strdup(line);
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d) {
_cleanup_free_ char *fs = NULL;
int r;
@@ -1007,18 +1040,12 @@ int cg_is_empty_recursive(const char *controller, const char *path) {
return unified;
if (unified > 0) {
- _cleanup_free_ char *populated = NULL, *t = NULL;
+ _cleanup_free_ char *t = NULL;
/* On the unified hierarchy we can check empty state
- * via the "cgroup.populated" attribute. */
+ * via the "populated" attribute of "cgroup.events". */
- r = cg_get_path(controller, path, "cgroup.populated", &populated);
- if (r < 0)
- return r;
-
- r = read_one_line_file(populated, &t);
- if (r == -ENOENT)
- return 1;
+ r = cg_read_event(controller, path, "populated", &t);
if (r < 0)
return r;
@@ -1248,7 +1275,7 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **cgroup) {
return 0;
}
-int cg_path_decode_unit(const char *cgroup, char **unit){
+int cg_path_decode_unit(const char *cgroup, char **unit) {
char *c, *s;
size_t n;
@@ -2033,10 +2060,10 @@ int cg_mask_supported(CGroupMask *ret) {
mask |= CGROUP_CONTROLLER_TO_MASK(v);
}
- /* Currently, we only support the memory and pids
+ /* Currently, we only support the memory, io and pids
* controller in the unified hierarchy, mask
* everything else off. */
- mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS;
+ mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_IO | CGROUP_MASK_PIDS;
} else {
CGroupController c;
@@ -2129,7 +2156,7 @@ int cg_unified(void) {
if (statfs("/sys/fs/cgroup/", &fs) < 0)
return -errno;
- if (F_TYPE_EQUAL(fs.f_type, CGROUP_SUPER_MAGIC))
+ if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC))
unified_cache = true;
else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))
unified_cache = false;
@@ -2222,6 +2249,42 @@ bool cg_is_legacy_wanted(void) {
return !cg_is_unified_wanted();
}
+int cg_weight_parse(const char *s, uint64_t *ret) {
+ uint64_t u;
+ int r;
+
+ if (isempty(s)) {
+ *ret = CGROUP_WEIGHT_INVALID;
+ return 0;
+ }
+
+ r = safe_atou64(s, &u);
+ if (r < 0)
+ return r;
+
+ if (u < CGROUP_WEIGHT_MIN || u > CGROUP_WEIGHT_MAX)
+ return -ERANGE;
+
+ *ret = u;
+ return 0;
+}
+
+const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = {
+ [CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_RIOPS_MAX] = CGROUP_LIMIT_MAX,
+ [CGROUP_IO_WIOPS_MAX] = CGROUP_LIMIT_MAX,
+};
+
+static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = {
+ [CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax",
+ [CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax",
+ [CGROUP_IO_RIOPS_MAX] = "IOReadIOPSMax",
+ [CGROUP_IO_WIOPS_MAX] = "IOWriteIOPSMax",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType);
+
int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
uint64_t u;
int r;
@@ -2265,6 +2328,7 @@ int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
[CGROUP_CONTROLLER_CPU] = "cpu",
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
+ [CGROUP_CONTROLLER_IO] = "io",
[CGROUP_CONTROLLER_BLKIO] = "blkio",
[CGROUP_CONTROLLER_MEMORY] = "memory",
[CGROUP_CONTROLLER_DEVICES] = "devices",
diff --git a/src/libbasic/cgroup-util.h b/src/libbasic/cgroup-util.h
index ad1edd9cdb..4bb5291296 100644
--- a/src/libbasic/cgroup-util.h
+++ b/src/libbasic/cgroup-util.h
@@ -34,6 +34,7 @@
typedef enum CGroupController {
CGROUP_CONTROLLER_CPU,
CGROUP_CONTROLLER_CPUACCT,
+ CGROUP_CONTROLLER_IO,
CGROUP_CONTROLLER_BLKIO,
CGROUP_CONTROLLER_MEMORY,
CGROUP_CONTROLLER_DEVICES,
@@ -48,6 +49,7 @@ typedef enum CGroupController {
typedef enum CGroupMask {
CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
+ CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
@@ -55,6 +57,37 @@ typedef enum CGroupMask {
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
} CGroupMask;
+/* Special values for all weight knobs on unified hierarchy */
+#define CGROUP_WEIGHT_INVALID ((uint64_t) -1)
+#define CGROUP_WEIGHT_MIN UINT64_C(1)
+#define CGROUP_WEIGHT_MAX UINT64_C(10000)
+#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)
+
+#define CGROUP_LIMIT_MIN UINT64_C(0)
+#define CGROUP_LIMIT_MAX ((uint64_t) -1)
+
+static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
+ return
+ x == CGROUP_WEIGHT_INVALID ||
+ (x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX);
+}
+
+/* IO limits on unified hierarchy */
+typedef enum CGroupIOLimitType {
+ CGROUP_IO_RBPS_MAX,
+ CGROUP_IO_WBPS_MAX,
+ CGROUP_IO_RIOPS_MAX,
+ CGROUP_IO_WIOPS_MAX,
+
+ _CGROUP_IO_LIMIT_TYPE_MAX,
+ _CGROUP_IO_LIMIT_TYPE_INVALID = -1
+} CGroupIOLimitType;
+
+extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
+
+const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
+CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
+
/* Special values for the cpu.shares attribute */
#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
#define CGROUP_CPU_SHARES_MIN UINT64_C(2)
@@ -96,6 +129,8 @@ static inline bool CGROUP_BLKIO_WEIGHT_IS_OK(uint64_t x) {
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f);
int cg_read_pid(FILE *f, pid_t *_pid);
+int cg_read_event(const char *controller, const char *path, const char *event,
+ char **val);
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d);
int cg_read_subgroup(DIR *d, char **fn);
@@ -188,5 +223,6 @@ bool cg_is_legacy_wanted(void);
const char* cgroup_controller_to_string(CGroupController c) _const_;
CGroupController cgroup_controller_from_string(const char *s) _pure_;
+int cg_weight_parse(const char *s, uint64_t *ret);
int cg_cpu_shares_parse(const char *s, uint64_t *ret);
int cg_blkio_weight_parse(const char *s, uint64_t *ret);
diff --git a/src/libbasic/clock-util.c b/src/libbasic/clock-util.c
index 507e757ff0..7fe8d35ea5 100644
--- a/src/libbasic/clock-util.c
+++ b/src/libbasic/clock-util.c
@@ -69,9 +69,12 @@ int clock_set_hwclock(const struct tm *tm) {
return 0;
}
-int clock_is_localtime(void) {
+int clock_is_localtime(const char* adjtime_path) {
_cleanup_fclose_ FILE *f;
+ if (adjtime_path == NULL)
+ adjtime_path = "/etc/adjtime";
+
/*
* The third line of adjtime is "UTC" or "LOCAL" or nothing.
* # /etc/adjtime
@@ -79,7 +82,7 @@ int clock_is_localtime(void) {
* 0
* UTC
*/
- f = fopen("/etc/adjtime", "re");
+ f = fopen(adjtime_path, "re");
if (f) {
char line[LINE_MAX];
bool b;
@@ -88,7 +91,8 @@ int clock_is_localtime(void) {
fgets(line, sizeof(line), f) &&
fgets(line, sizeof(line), f);
if (!b)
- return -EIO;
+ /* less than three lines -> default to UTC */
+ return 0;
truncate_nl(line);
return streq(line, "LOCAL");
@@ -96,6 +100,7 @@ int clock_is_localtime(void) {
} else if (errno != ENOENT)
return -errno;
+ /* adjtime not present -> default to UTC */
return 0;
}
diff --git a/src/libbasic/clock-util.h b/src/libbasic/clock-util.h
index f471f2abcf..8830cd2f38 100644
--- a/src/libbasic/clock-util.h
+++ b/src/libbasic/clock-util.h
@@ -21,7 +21,7 @@
#include <time.h>
-int clock_is_localtime(void);
+int clock_is_localtime(const char* adjtime_path);
int clock_set_timezone(int *min);
int clock_reset_timewarp(void);
int clock_get_hwclock(struct tm *tm);
diff --git a/src/libbasic/copy.c b/src/libbasic/copy.c
index 519b412941..c3586728d0 100644
--- a/src/libbasic/copy.c
+++ b/src/libbasic/copy.c
@@ -40,17 +40,38 @@
#include "fs-util.h"
#include "io-util.h"
#include "macro.h"
+#include "missing.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
#include "umask-util.h"
#include "xattr-util.h"
-#define COPY_BUFFER_SIZE (16*1024)
+#define COPY_BUFFER_SIZE (16*1024u)
+
+static ssize_t try_copy_file_range(int fd_in, loff_t *off_in,
+ int fd_out, loff_t *off_out,
+ size_t len,
+ unsigned int flags) {
+ static int have = -1;
+ ssize_t r;
+
+ if (have == false)
+ return -ENOSYS;
+
+ r = copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
+ if (_unlikely_(have < 0))
+ have = r >= 0 || errno != ENOSYS;
+ if (r >= 0)
+ return r;
+ else
+ return -errno;
+}
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
- bool try_sendfile = true, try_splice = true;
+ bool try_cfr = true, try_sendfile = true, try_splice = true;
int r;
+ size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
assert(fdf >= 0);
assert(fdt >= 0);
@@ -67,56 +88,69 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
}
for (;;) {
- size_t m = COPY_BUFFER_SIZE;
ssize_t n;
if (max_bytes != (uint64_t) -1) {
-
if (max_bytes <= 0)
return 1; /* return > 0 if we hit the max_bytes limit */
- if ((uint64_t) m > max_bytes)
- m = (size_t) max_bytes;
+ if (m > max_bytes)
+ m = max_bytes;
+ }
+
+ /* First try copy_file_range(), unless we already tried */
+ if (try_cfr) {
+ n = try_copy_file_range(fdf, NULL, fdt, NULL, m, 0u);
+ if (n < 0) {
+ if (!IN_SET(n, -EINVAL, -ENOSYS, -EXDEV, -EBADF))
+ return n;
+
+ try_cfr = false;
+ /* use fallback below */
+ } else if (n == 0) /* EOF */
+ break;
+ else
+ /* Success! */
+ goto next;
}
/* First try sendfile(), unless we already tried */
if (try_sendfile) {
-
n = sendfile(fdt, fdf, NULL, m);
if (n < 0) {
- if (errno != EINVAL && errno != ENOSYS)
+ if (!IN_SET(errno, EINVAL, ENOSYS))
return -errno;
try_sendfile = false;
/* use fallback below */
} else if (n == 0) /* EOF */
break;
- else if (n > 0)
+ else
/* Success! */
goto next;
}
- /* The try splice, unless we already tried */
+ /* Then try splice, unless we already tried */
if (try_splice) {
n = splice(fdf, NULL, fdt, NULL, m, 0);
if (n < 0) {
- if (errno != EINVAL && errno != ENOSYS)
+ if (!IN_SET(errno, EINVAL, ENOSYS))
return -errno;
try_splice = false;
/* use fallback below */
} else if (n == 0) /* EOF */
break;
- else if (n > 0)
+ else
/* Success! */
goto next;
}
/* As a fallback just copy bits by hand */
{
- uint8_t buf[m];
+ uint8_t buf[MIN(m, COPY_BUFFER_SIZE)];
- n = read(fdf, buf, m);
+ n = read(fdf, buf, sizeof buf);
if (n < 0)
return -errno;
if (n == 0) /* EOF */
@@ -132,6 +166,11 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
assert(max_bytes >= (uint64_t) n);
max_bytes -= n;
}
+ /* sendfile accepts at most SSIZE_MAX-offset bytes to copy,
+ * so reduce our maximum by the amount we already copied,
+ * but don't go below our copy buffer size, unless we are
+ * close the the limit of bytes we are allowed to copy. */
+ m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n);
}
return 0; /* return 0 if we hit EOF earlier than the size limit */
@@ -266,6 +305,8 @@ static int fd_copy_directory(
fdf = openat(df, from, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
else
fdf = fcntl(df, F_DUPFD_CLOEXEC, 3);
+ if (fdf < 0)
+ return -errno;
d = fdopendir(fdf);
if (!d)
@@ -286,22 +327,6 @@ static int fd_copy_directory(
r = 0;
- if (created) {
- struct timespec ut[2] = {
- st->st_atim,
- st->st_mtim
- };
-
- if (fchown(fdt, st->st_uid, st->st_gid) < 0)
- r = -errno;
-
- if (fchmod(fdt, st->st_mode & 07777) < 0)
- r = -errno;
-
- (void) futimens(fdt, ut);
- (void) copy_xattr(dirfd(d), fdt);
- }
-
FOREACH_DIRENT_ALL(de, d, return -errno) {
struct stat buf;
int q;
@@ -325,7 +350,7 @@ static int fd_copy_directory(
q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
else if (S_ISFIFO(buf.st_mode))
q = fd_copy_fifo(dirfd(d), de->d_name, &buf, fdt, de->d_name);
- else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode))
+ else if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode) || S_ISSOCK(buf.st_mode))
q = fd_copy_node(dirfd(d), de->d_name, &buf, fdt, de->d_name);
else
q = -EOPNOTSUPP;
@@ -337,6 +362,22 @@ static int fd_copy_directory(
r = q;
}
+ if (created) {
+ struct timespec ut[2] = {
+ st->st_atim,
+ st->st_mtim
+ };
+
+ if (fchown(fdt, st->st_uid, st->st_gid) < 0)
+ r = -errno;
+
+ if (fchmod(fdt, st->st_mode & 07777) < 0)
+ r = -errno;
+
+ (void) copy_xattr(dirfd(d), fdt);
+ (void) futimens(fdt, ut);
+ }
+
return r;
}
@@ -357,7 +398,7 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
return fd_copy_symlink(fdf, from, &st, fdt, to);
else if (S_ISFIFO(st.st_mode))
return fd_copy_fifo(fdf, from, &st, fdt, to);
- else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode))
+ else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode) || S_ISSOCK(st.st_mode))
return fd_copy_node(fdf, from, &st, fdt, to);
else
return -EOPNOTSUPP;
@@ -368,7 +409,6 @@ int copy_tree(const char *from, const char *to, bool merge) {
}
int copy_directory_fd(int dirfd, const char *to, bool merge) {
-
struct stat st;
assert(dirfd >= 0);
@@ -383,6 +423,21 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
}
+int copy_directory(const char *from, const char *to, bool merge) {
+ struct stat st;
+
+ assert(from);
+ assert(to);
+
+ if (lstat(from, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode))
+ return -ENOTDIR;
+
+ return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
+}
+
int copy_file_fd(const char *from, int fdt, bool try_reflink) {
_cleanup_close_ int fdf = -1;
int r;
diff --git a/src/libbasic/copy.h b/src/libbasic/copy.h
index 3e5eb52506..b5d08ebafe 100644
--- a/src/libbasic/copy.h
+++ b/src/libbasic/copy.h
@@ -30,6 +30,7 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
int copy_tree(const char *from, const char *to, bool merge);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
int copy_directory_fd(int dirfd, const char *to, bool merge);
+int copy_directory(const char *from, const char *to, bool merge);
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink);
int copy_times(int fdf, int fdt);
int copy_xattr(int fdf, int fdt);
diff --git a/src/libbasic/def.h b/src/libbasic/def.h
index 963343eb7d..1a7a0f4928 100644
--- a/src/libbasic/def.h
+++ b/src/libbasic/def.h
@@ -41,8 +41,6 @@
#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
#define SIGNALS_IGNORE SIGPIPE
-#define REBOOT_PARAM_FILE "/run/systemd/reboot-param"
-
#ifdef HAVE_SPLIT_USR
#define KBD_KEYMAP_DIRS \
"/usr/share/keymaps/\0" \
diff --git a/src/libbasic/dirent-util.c b/src/libbasic/dirent-util.c
index 5fb535cb13..59067121b7 100644
--- a/src/libbasic/dirent-util.c
+++ b/src/libbasic/dirent-util.c
@@ -52,12 +52,10 @@ int dirent_ensure_type(DIR *d, struct dirent *de) {
bool dirent_is_file(const struct dirent *de) {
assert(de);
- if (hidden_file(de->d_name))
+ if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
return false;
- if (de->d_type != DT_REG &&
- de->d_type != DT_LNK &&
- de->d_type != DT_UNKNOWN)
+ if (hidden_or_backup_file(de->d_name))
return false;
return true;
@@ -66,12 +64,10 @@ bool dirent_is_file(const struct dirent *de) {
bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
assert(de);
- if (de->d_type != DT_REG &&
- de->d_type != DT_LNK &&
- de->d_type != DT_UNKNOWN)
+ if (!IN_SET(de->d_type, DT_REG, DT_LNK, DT_UNKNOWN))
return false;
- if (hidden_file_allow_backup(de->d_name))
+ if (de->d_name[0] == '.')
return false;
return endswith(de->d_name, suffix);
diff --git a/src/libbasic/dirent-util.h b/src/libbasic/dirent-util.h
index 6bf099b46c..b91d04908f 100644
--- a/src/libbasic/dirent-util.h
+++ b/src/libbasic/dirent-util.h
@@ -38,7 +38,7 @@ bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pu
on_error; \
} \
break; \
- } else if (hidden_file((de)->d_name)) \
+ } else if (hidden_or_backup_file((de)->d_name)) \
continue; \
else
diff --git a/src/libbasic/escape.c b/src/libbasic/escape.c
index 2e483880c8..01daf11ce7 100644
--- a/src/libbasic/escape.c
+++ b/src/libbasic/escape.c
@@ -413,6 +413,34 @@ char *xescape(const char *s, const char *bad) {
return r;
}
+char *octescape(const char *s, size_t len) {
+ char *r, *t;
+ const char *f;
+
+ /* Escapes all chars in bad, in addition to \ and " chars,
+ * in \nnn style escaping. */
+
+ r = new(char, len * 4 + 1);
+ if (!r)
+ return NULL;
+
+ for (f = s, t = r; f < s + len; f++) {
+
+ if (*f < ' ' || *f >= 127 || *f == '\\' || *f == '"') {
+ *(t++) = '\\';
+ *(t++) = '0' + (*f >> 6);
+ *(t++) = '0' + ((*f >> 3) & 8);
+ *(t++) = '0' + (*f & 8);
+ } else
+ *(t++) = *f;
+ }
+
+ *t = 0;
+
+ return r;
+
+}
+
static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
assert(bad);
diff --git a/src/libbasic/escape.h b/src/libbasic/escape.h
index 1b28bd10af..deaa4def28 100644
--- a/src/libbasic/escape.h
+++ b/src/libbasic/escape.h
@@ -48,6 +48,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi
int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit);
char *xescape(const char *s, const char *bad);
+char *octescape(const char *s, size_t len);
char *shell_escape(const char *s, const char *bad);
char *shell_maybe_quote(const char *s);
diff --git a/src/libbasic/ether-addr-util.c b/src/libbasic/ether-addr-util.c
index ded6d31f4b..5697e8d132 100644
--- a/src/libbasic/ether-addr-util.c
+++ b/src/libbasic/ether-addr-util.c
@@ -23,6 +23,7 @@
#include "ether-addr-util.h"
#include "macro.h"
+#include "string-util.h"
char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) {
assert(addr);
@@ -42,3 +43,83 @@ char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR
return buffer;
}
+
+bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b) {
+ assert(a);
+ assert(b);
+
+ return a->ether_addr_octet[0] == b->ether_addr_octet[0] &&
+ a->ether_addr_octet[1] == b->ether_addr_octet[1] &&
+ a->ether_addr_octet[2] == b->ether_addr_octet[2] &&
+ a->ether_addr_octet[3] == b->ether_addr_octet[3] &&
+ a->ether_addr_octet[4] == b->ether_addr_octet[4] &&
+ a->ether_addr_octet[5] == b->ether_addr_octet[5];
+}
+
+int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset) {
+ size_t pos = 0, n, field;
+ char sep = '\0';
+ const char *hex = HEXDIGITS, *hexoff;
+ size_t x;
+ bool touched;
+
+#define parse_fields(v) \
+ for (field = 0; field < ELEMENTSOF(v); field++) { \
+ touched = false; \
+ for (n = 0; n < (2 * sizeof(v[0])); n++) { \
+ if (s[pos] == '\0') \
+ break; \
+ hexoff = strchr(hex, s[pos]); \
+ if (hexoff == NULL) \
+ break; \
+ assert(hexoff >= hex); \
+ x = hexoff - hex; \
+ if (x >= 16) \
+ x -= 6; /* A-F */ \
+ assert(x < 16); \
+ touched = true; \
+ v[field] <<= 4; \
+ v[field] += x; \
+ pos++; \
+ } \
+ if (!touched) \
+ return -EINVAL; \
+ if (field < (ELEMENTSOF(v)-1)) { \
+ if (s[pos] != sep) \
+ return -EINVAL; \
+ else \
+ pos++; \
+ } \
+ }
+
+ assert(s);
+ assert(ret);
+
+ sep = s[strspn(s, hex)];
+ if (sep == '\n')
+ return -EINVAL;
+ if (strchr(":.-", sep) == NULL)
+ return -EINVAL;
+
+ if (sep == '.') {
+ uint16_t shorts[3] = { 0 };
+
+ parse_fields(shorts);
+
+ for (n = 0; n < ELEMENTSOF(shorts); n++) {
+ ret->ether_addr_octet[2*n] = ((shorts[n] & (uint16_t)0xff00) >> 8);
+ ret->ether_addr_octet[2*n + 1] = (shorts[n] & (uint16_t)0x00ff);
+ }
+ } else {
+ struct ether_addr out = { .ether_addr_octet = { 0 } };
+
+ parse_fields(out.ether_addr_octet);
+
+ for (n = 0; n < ELEMENTSOF(out.ether_addr_octet); n++)
+ ret->ether_addr_octet[n] = out.ether_addr_octet[n];
+ }
+
+ if (offset)
+ *offset = pos;
+ return 0;
+}
diff --git a/src/libbasic/ether-addr-util.h b/src/libbasic/ether-addr-util.h
index 4487149efd..74e125a95f 100644
--- a/src/libbasic/ether-addr-util.h
+++ b/src/libbasic/ether-addr-util.h
@@ -20,10 +20,20 @@
***/
#include <net/ethernet.h>
+#include <stdbool.h>
#define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X"
#define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5]
#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]);
+
+bool ether_addr_equal(const struct ether_addr *a, const struct ether_addr *b);
+
+#define ETHER_ADDR_NULL ((const struct ether_addr){})
+
+static inline bool ether_addr_is_null(const struct ether_addr *addr) {
+ return ether_addr_equal(addr, &ETHER_ADDR_NULL);
+}
+
+int ether_addr_from_string(const char *s, struct ether_addr *ret, size_t *offset);
diff --git a/src/libbasic/exit-status.c b/src/libbasic/exit-status.c
index 5e0bc415c8..92fa5ace61 100644
--- a/src/libbasic/exit-status.c
+++ b/src/libbasic/exit-status.c
@@ -147,9 +147,6 @@ const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) {
case EXIT_MAKE_STARTER:
return "MAKE_STARTER";
- case EXIT_BUS_ENDPOINT:
- return "BUS_ENDPOINT";
-
case EXIT_SMACK_PROCESS_LABEL:
return "SMACK_PROCESS_LABEL";
}
diff --git a/src/libbasic/exit-status.h b/src/libbasic/exit-status.h
index 79525d30ee..1208c8feed 100644
--- a/src/libbasic/exit-status.h
+++ b/src/libbasic/exit-status.h
@@ -77,7 +77,6 @@ typedef enum ExitStatus {
EXIT_RUNTIME_DIRECTORY,
EXIT_MAKE_STARTER,
EXIT_CHOWN,
- EXIT_BUS_ENDPOINT,
EXIT_SMACK_PROCESS_LABEL,
} ExitStatus;
diff --git a/src/libbasic/extract-word.c b/src/libbasic/extract-word.c
index ee35d2a0ec..d6c1228463 100644
--- a/src/libbasic/extract-word.c
+++ b/src/libbasic/extract-word.c
@@ -63,12 +63,12 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
if (!GREEDY_REALLOC(s, allocated, sz+1))
return -ENOMEM;
- for (;; (*p) ++, c = **p) {
+ for (;; (*p)++, c = **p) {
if (c == 0)
goto finish_force_terminate;
else if (strchr(separators, c)) {
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
- (*p) ++;
+ (*p)++;
goto finish_force_next;
}
} else {
@@ -81,7 +81,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
}
}
- for (;; (*p) ++, c = **p) {
+ for (;; (*p)++, c = **p) {
if (backslash) {
if (!GREEDY_REALLOC(s, allocated, sz+7))
return -ENOMEM;
@@ -129,7 +129,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
backslash = false;
} else if (quote) { /* inside either single or double quotes */
- for (;; (*p) ++, c = **p) {
+ for (;; (*p)++, c = **p) {
if (c == 0) {
if (flags & EXTRACT_RELAX)
goto finish_force_terminate;
@@ -149,7 +149,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
}
} else {
- for (;; (*p) ++, c = **p) {
+ for (;; (*p)++, c = **p) {
if (c == 0)
goto finish_force_terminate;
else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) {
@@ -160,11 +160,11 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra
break;
} else if (strchr(separators, c)) {
if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
- (*p) ++;
+ (*p)++;
goto finish_force_next;
}
/* Skip additional coalesced separators. */
- for (;; (*p) ++, c = **p) {
+ for (;; (*p)++, c = **p) {
if (c == 0)
goto finish_force_terminate;
if (!strchr(separators, c))
diff --git a/src/libbasic/fd-util.c b/src/libbasic/fd-util.c
index ec9560cd07..8b466cff15 100644
--- a/src/libbasic/fd-util.c
+++ b/src/libbasic/fd-util.c
@@ -25,11 +25,13 @@
#include <unistd.h>
#include "fd-util.h"
+#include "fs-util.h"
#include "macro.h"
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
#include "socket-util.h"
+#include "stdio-util.h"
#include "util.h"
int close_nointr(int fd) {
@@ -229,7 +231,7 @@ int close_all_fds(const int except[], unsigned n_except) {
while ((de = readdir(d))) {
int fd = -1;
- if (hidden_file(de->d_name))
+ if (hidden_or_backup_file(de->d_name))
continue;
if (safe_atoi(de->d_name, &fd) < 0)
@@ -356,3 +358,17 @@ bool fdname_is_valid(const char *s) {
return p - s < 256;
}
+
+int fd_get_path(int fd, char **ret) {
+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
+ int r;
+
+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+
+ r = readlink_malloc(procfs_path, ret);
+
+ if (r == -ENOENT) /* If the file doesn't exist the fd is invalid */
+ return -EBADF;
+
+ return r;
+}
diff --git a/src/libbasic/fd-util.h b/src/libbasic/fd-util.h
index 44528c6e35..b86e41698a 100644
--- a/src/libbasic/fd-util.h
+++ b/src/libbasic/fd-util.h
@@ -72,6 +72,8 @@ void cmsg_close_all(struct msghdr *mh);
bool fdname_is_valid(const char *s);
+int fd_get_path(int fd, char **ret);
+
/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
#define ERRNO_IS_DISCONNECT(r) \
IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH)
diff --git a/src/libbasic/fdset.c b/src/libbasic/fdset.c
index da1162991f..b52bf1ad05 100644
--- a/src/libbasic/fdset.c
+++ b/src/libbasic/fdset.c
@@ -94,19 +94,6 @@ int fdset_put(FDSet *s, int fd) {
return set_put(MAKE_SET(s), FD_TO_PTR(fd));
}
-int fdset_consume(FDSet *s, int fd) {
- int r;
-
- assert(s);
- assert(fd >= 0);
-
- r = fdset_put(s, fd);
- if (r <= 0)
- safe_close(fd);
-
- return r;
-}
-
int fdset_put_dup(FDSet *s, int fd) {
int copy, r;
@@ -164,7 +151,7 @@ int fdset_new_fill(FDSet **_s) {
while ((de = readdir(d))) {
int fd = -1;
- if (hidden_file(de->d_name))
+ if (hidden_or_backup_file(de->d_name))
continue;
r = safe_atoi(de->d_name, &fd);
diff --git a/src/libbasic/fdset.h b/src/libbasic/fdset.h
index 12d0cef761..16efe5bdf2 100644
--- a/src/libbasic/fdset.h
+++ b/src/libbasic/fdset.h
@@ -32,7 +32,6 @@ FDSet* fdset_free(FDSet *s);
int fdset_put(FDSet *s, int fd);
int fdset_put_dup(FDSet *s, int fd);
-int fdset_consume(FDSet *s, int fd);
bool fdset_contains(FDSet *s, int fd);
int fdset_remove(FDSet *s, int fd);
diff --git a/src/libbasic/fileio.c b/src/libbasic/fileio.c
index e43ca6d29e..29f5374222 100644
--- a/src/libbasic/fileio.c
+++ b/src/libbasic/fileio.c
@@ -352,7 +352,7 @@ static int parse_env_file_internal(
case KEY:
if (strchr(newline, c)) {
state = PRE_KEY;
- line ++;
+ line++;
n_key = 0;
} else if (c == '=') {
state = PRE_VALUE;
@@ -376,7 +376,7 @@ static int parse_env_file_internal(
case PRE_VALUE:
if (strchr(newline, c)) {
state = PRE_KEY;
- line ++;
+ line++;
key[n_key] = 0;
if (value)
@@ -416,7 +416,7 @@ static int parse_env_file_internal(
case VALUE:
if (strchr(newline, c)) {
state = PRE_KEY;
- line ++;
+ line++;
key[n_key] = 0;
@@ -535,7 +535,7 @@ static int parse_env_file_internal(
state = COMMENT_ESCAPE;
else if (strchr(newline, c)) {
state = PRE_KEY;
- line ++;
+ line++;
}
break;
@@ -588,7 +588,7 @@ static int parse_env_file_push(
va_list aq, *ap = userdata;
if (!utf8_is_valid(key)) {
- _cleanup_free_ char *p;
+ _cleanup_free_ char *p = NULL;
p = utf8_escape_invalid(key);
log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p);
@@ -596,7 +596,7 @@ static int parse_env_file_push(
}
if (value && !utf8_is_valid(value)) {
- _cleanup_free_ char *p;
+ _cleanup_free_ char *p = NULL;
p = utf8_escape_invalid(value);
log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p);
@@ -908,7 +908,7 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin
/* Back off one char if there's nothing but whitespace
and zeros */
if (!*t || isspace(*t))
- t --;
+ t--;
}
len = strcspn(t, terminator);
@@ -1069,7 +1069,7 @@ int fflush_and_check(FILE *f) {
/* This is much like like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern, int flags) {
- _cleanup_umask_ mode_t u;
+ _cleanup_umask_ mode_t u = 0;
int fd;
assert(pattern);
@@ -1083,30 +1083,6 @@ int mkostemp_safe(char *pattern, int flags) {
return fd;
}
-int open_tmpfile(const char *path, int flags) {
- char *p;
- int fd;
-
- assert(path);
-
-#ifdef O_TMPFILE
- /* Try O_TMPFILE first, if it is supported */
- fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
- if (fd >= 0)
- return fd;
-#endif
-
- /* Fall back to unguessable name + unlinking */
- p = strjoina(path, "/systemd-tmp-XXXXXX");
-
- fd = mkostemp_safe(p, flags);
- if (fd < 0)
- return fd;
-
- unlink(p);
- return fd;
-}
-
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
const char *fn;
char *t;
@@ -1278,3 +1254,103 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
return fputs(s, f);
}
+
+int open_tmpfile_unlinkable(const char *directory, int flags) {
+ char *p;
+ int fd;
+
+ assert(directory);
+
+ /* Returns an unlinked temporary file that cannot be linked into the file system anymore */
+
+#ifdef O_TMPFILE
+ /* Try O_TMPFILE first, if it is supported */
+ fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
+ if (fd >= 0)
+ return fd;
+#endif
+
+ /* Fall back to unguessable name + unlinking */
+ p = strjoina(directory, "/systemd-tmp-XXXXXX");
+
+ fd = mkostemp_safe(p, flags);
+ if (fd < 0)
+ return fd;
+
+ (void) unlink(p);
+
+ return fd;
+}
+
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
+ _cleanup_free_ char *tmp = NULL;
+ int r, fd;
+
+ assert(target);
+ assert(ret_path);
+
+ /* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
+ assert((flags & O_EXCL) == 0);
+
+ /* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE – in
+ * which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
+ * "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
+
+#ifdef O_TMPFILE
+ {
+ _cleanup_free_ char *dn = NULL;
+
+ dn = dirname_malloc(target);
+ if (!dn)
+ return -ENOMEM;
+
+ fd = open(dn, O_TMPFILE|flags, 0640);
+ if (fd >= 0) {
+ *ret_path = NULL;
+ return fd;
+ }
+
+ log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn);
+ }
+#endif
+
+ r = tempfn_random(target, NULL, &tmp);
+ if (r < 0)
+ return r;
+
+ fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
+ if (fd < 0)
+ return -errno;
+
+ *ret_path = tmp;
+ tmp = NULL;
+
+ return fd;
+}
+
+int link_tmpfile(int fd, const char *path, const char *target) {
+
+ assert(fd >= 0);
+ assert(target);
+
+ /* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
+ * created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
+ * on the directory, and renameat2() is used instead.
+ *
+ * Note that in both cases we will not replace existing files. This is because linkat() does not support this
+ * operation currently (renameat2() does), and there is no nice way to emulate this. */
+
+ if (path) {
+ if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
+ return -errno;
+ } else {
+ char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
+
+ xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
+
+ if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
+ return -errno;
+ }
+
+ return 0;
+}
diff --git a/src/libbasic/fileio.h b/src/libbasic/fileio.h
index 8084895ff3..58dbc80c24 100644
--- a/src/libbasic/fileio.h
+++ b/src/libbasic/fileio.h
@@ -72,7 +72,6 @@ int fflush_and_check(FILE *f);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
int mkostemp_safe(char *pattern, int flags);
-int open_tmpfile(const char *path, int flags);
int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
int tempfn_random(const char *p, const char *extra, char **ret);
@@ -82,3 +81,8 @@ int write_timestamp_file_atomic(const char *fn, usec_t n);
int read_timestamp_file(const char *fn, usec_t *ret);
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
+
+int open_tmpfile_unlinkable(const char *directory, int flags);
+int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
+
+int link_tmpfile(int fd, const char *path, const char *target);
diff --git a/src/libbasic/formats-util.h b/src/libbasic/formats-util.h
index ce516b117d..9b4e8e98fa 100644
--- a/src/libbasic/formats-util.h
+++ b/src/libbasic/formats-util.h
@@ -49,7 +49,7 @@
#if SIZEOF_TIME_T == 8
# define PRI_TIME PRIi64
#elif SIZEOF_TIME_T == 4
-# define PRI_TIME PRIu32
+# define PRI_TIME "li"
#else
# error Unknown time_t size
#endif
diff --git a/src/libbasic/fs-util.c b/src/libbasic/fs-util.c
index 3ef1b90edd..e24e7036f7 100644
--- a/src/libbasic/fs-util.c
+++ b/src/libbasic/fs-util.c
@@ -38,6 +38,7 @@
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
@@ -283,24 +284,6 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
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;
@@ -511,3 +494,17 @@ int get_files_in_directory(const char *path, char ***list) {
return n;
}
+
+int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
+ char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+ int r;
+
+ /* This is like inotify_add_watch(), except that the file to watch is not referenced by a path, but by an fd */
+ xsprintf(path, "/proc/self/fd/%i", what);
+
+ r = inotify_add_watch(fd, path, mask);
+ if (r < 0)
+ return -errno;
+
+ return r;
+}
diff --git a/src/libbasic/fs-util.h b/src/libbasic/fs-util.h
index 0e2fcb21b9..517b599d6f 100644
--- a/src/libbasic/fs-util.h
+++ b/src/libbasic/fs-util.h
@@ -43,7 +43,6 @@ int readlink_and_canonicalize(const char *p, char **r);
int readlink_and_make_absolute_root(const char *root, const char *path, char **ret);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
-int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
int fchmod_umask(int fd, mode_t mode);
@@ -73,3 +72,5 @@ union inotify_event_buffer {
struct inotify_event ev;
uint8_t raw[INOTIFY_EVENT_MAX];
};
+
+int inotify_add_watch_fd(int fd, int what, uint32_t mask);
diff --git a/src/libbasic/gunicode.h b/src/libbasic/gunicode.h
index b03aa43160..5975bc8fc9 100644
--- a/src/libbasic/gunicode.h
+++ b/src/libbasic/gunicode.h
@@ -1,11 +1,11 @@
+#pragma once
+
/* gunicode.h - Unicode manipulation functions
*
* Copyright (C) 1999, 2000 Tom Tromey
* Copyright 2000, 2005 Red Hat, Inc.
*/
-#pragma once
-
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
diff --git a/src/libbasic/hashmap.c b/src/libbasic/hashmap.c
index 6f1a049d47..49a0479592 100644
--- a/src/libbasic/hashmap.c
+++ b/src/libbasic/hashmap.c
@@ -176,7 +176,7 @@ enum HashmapType {
};
struct _packed_ indirect_storage {
- char *storage; /* where buckets and DIBs are stored */
+ void *storage; /* where buckets and DIBs are stored */
uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */
unsigned n_entries; /* number of stored entries */
@@ -193,7 +193,7 @@ struct direct_storage {
/* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
* That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
* or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
- char storage[sizeof(struct indirect_storage)];
+ uint8_t storage[sizeof(struct indirect_storage)];
};
#define DIRECT_BUCKETS(entry_t) \
@@ -302,7 +302,7 @@ static void n_entries_dec(HashmapBase *h) {
h->n_direct_entries--;
}
-static char *storage_ptr(HashmapBase *h) {
+static void *storage_ptr(HashmapBase *h) {
return h->has_indirect ? h->indirect.storage
: h->direct.storage;
}
@@ -347,7 +347,7 @@ static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) {
return (struct hashmap_base_entry*)
- (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
+ ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
}
static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) {
@@ -381,7 +381,7 @@ static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_
static dib_raw_t *dib_raw_ptr(HashmapBase *h) {
return (dib_raw_t*)
- (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
+ ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
}
static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) {
@@ -1028,7 +1028,7 @@ static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
*/
static int resize_buckets(HashmapBase *h, unsigned entries_add) {
struct swap_entries swap;
- char *new_storage;
+ void *new_storage;
dib_raw_t *old_dibs, *new_dibs;
const struct hashmap_type_info *hi;
unsigned idx, optimal_idx;
@@ -1095,7 +1095,7 @@ static int resize_buckets(HashmapBase *h, unsigned entries_add) {
h->indirect.n_buckets = (1U << new_shift) /
(hi->entry_size + sizeof(dib_raw_t));
- old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets);
+ old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets);
new_dibs = dib_raw_ptr(h);
/*
@@ -1773,20 +1773,18 @@ int set_consume(Set *s, void *value) {
int set_put_strdup(Set *s, const char *p) {
char *c;
- int r;
assert(s);
assert(p);
+ if (set_contains(s, (char*) p))
+ return 0;
+
c = strdup(p);
if (!c)
return -ENOMEM;
- r = set_consume(s, c);
- if (r == -EEXIST)
- return 0;
-
- return r;
+ return set_consume(s, c);
}
int set_put_strdupv(Set *s, char **l) {
diff --git a/src/libbasic/hexdecoct.c b/src/libbasic/hexdecoct.c
index 592df53cb5..c5bda6c4d6 100644
--- a/src/libbasic/hexdecoct.c
+++ b/src/libbasic/hexdecoct.c
@@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "hexdecoct.h"
#include "macro.h"
+#include "util.h"
char octchar(int x) {
return '0' + (x & 7);
@@ -275,8 +276,8 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l
if (padding) {
/* strip the padding */
while (l > 0 && p[l - 1] == '=' && pad < 7) {
- pad ++;
- l --;
+ pad++;
+ l--;
}
}
@@ -504,7 +505,7 @@ int unbase64char(char c) {
if (c == '+')
return offset;
- offset ++;
+ offset++;
if (c == '/')
return offset;
@@ -572,7 +573,7 @@ static int base64_append_width(char **prefix, int plen,
if (!t)
return -ENOMEM;
- memcpy(t + plen, sep, slen);
+ memcpy_safe(t + plen, sep, slen);
for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) {
int act = MIN(width, avail);
@@ -620,9 +621,9 @@ int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) {
/* strip the padding */
if (l > 0 && p[l - 1] == '=')
- l --;
+ l--;
if (l > 0 && p[l - 1] == '=')
- l --;
+ l--;
/* a group of four input bytes needs three output bytes, in case of
padding we need to add two or three extra bytes */
diff --git a/src/libbasic/hostname-util.c b/src/libbasic/hostname-util.c
index 7bb23448ed..13c3bb6446 100644
--- a/src/libbasic/hostname-util.c
+++ b/src/libbasic/hostname-util.c
@@ -17,7 +17,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <bits/local_lim.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
@@ -49,6 +48,10 @@ bool hostname_is_set(void) {
char* gethostname_malloc(void) {
struct utsname u;
+ /* This call tries to return something useful, either the actual hostname
+ * or it makes something up. The only reason it might fail is OOM.
+ * It might even return "localhost" if that's set. */
+
assert_se(uname(&u) >= 0);
if (isempty(u.nodename) || streq(u.nodename, "(none)"))
@@ -57,6 +60,31 @@ char* gethostname_malloc(void) {
return strdup(u.nodename);
}
+int gethostname_strict(char **ret) {
+ struct utsname u;
+ char *k;
+
+ /* This call will rather fail than make up a name. It will not return "localhost" either. */
+
+ assert_se(uname(&u) >= 0);
+
+ if (isempty(u.nodename))
+ return -ENXIO;
+
+ if (streq(u.nodename, "(none)"))
+ return -ENXIO;
+
+ if (is_localhost(u.nodename))
+ return -ENXIO;
+
+ k = strdup(u.nodename);
+ if (!k)
+ return -ENOMEM;
+
+ *ret = k;
+ return 0;
+}
+
static bool hostname_valid_char(char c) {
return
(c >= 'a' && c <= 'z') ||
@@ -96,7 +124,7 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) {
return false;
dot = true;
- n_dots ++;
+ n_dots++;
} else {
if (!hostname_valid_char(*p))
return false;
@@ -122,6 +150,8 @@ char* hostname_cleanup(char *s) {
assert(s);
+ strshorten(s, HOST_NAME_MAX);
+
for (p = s, d = s, dot = true; *p; p++) {
if (*p == '.') {
if (dot)
@@ -141,8 +171,6 @@ char* hostname_cleanup(char *s) {
else
*d = 0;
- strshorten(s, HOST_NAME_MAX);
-
return s;
}
@@ -150,16 +178,16 @@ bool is_localhost(const char *hostname) {
assert(hostname);
/* This tries to identify local host and domain names
- * described in RFC6761 plus the redhatism of .localdomain */
+ * described in RFC6761 plus the redhatism of localdomain */
return strcaseeq(hostname, "localhost") ||
strcaseeq(hostname, "localhost.") ||
- strcaseeq(hostname, "localdomain.") ||
- strcaseeq(hostname, "localdomain") ||
+ strcaseeq(hostname, "localhost.localdomain") ||
+ strcaseeq(hostname, "localhost.localdomain.") ||
endswith_no_case(hostname, ".localhost") ||
endswith_no_case(hostname, ".localhost.") ||
- endswith_no_case(hostname, ".localdomain") ||
- endswith_no_case(hostname, ".localdomain.");
+ endswith_no_case(hostname, ".localhost.localdomain") ||
+ endswith_no_case(hostname, ".localhost.localdomain.");
}
bool is_gateway_hostname(const char *hostname) {
diff --git a/src/libbasic/hostname-util.h b/src/libbasic/hostname-util.h
index d062eddea1..7af4e6c7ec 100644
--- a/src/libbasic/hostname-util.h
+++ b/src/libbasic/hostname-util.h
@@ -26,6 +26,7 @@
bool hostname_is_set(void);
char* gethostname_malloc(void);
+int gethostname_strict(char **ret);
bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_;
char* hostname_cleanup(char *s);
diff --git a/src/libbasic/io-util.c b/src/libbasic/io-util.c
index 3ec8d61236..cc6dfa8c1b 100644
--- a/src/libbasic/io-util.c
+++ b/src/libbasic/io-util.c
@@ -33,6 +33,11 @@ int flush_fd(int fd) {
.events = POLLIN,
};
+ /* Read from the specified file descriptor, until POLLIN is not set anymore, throwing away everything
+ * read. Note that some file descriptors (notable IP sockets) will trigger POLLIN even when no data can be read
+ * (due to IP packet checksum mismatches), hence this function is only safe to be non-blocking if the fd used
+ * was set to non-blocking too. */
+
for (;;) {
char buf[LINE_MAX];
ssize_t l;
@@ -249,7 +254,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
} else if (n > 0)
q += n;
else
- q ++;
+ q++;
}
if (q > w) {
diff --git a/src/libbasic/io-util.h b/src/libbasic/io-util.h
index 142c940d92..4684ed3bfc 100644
--- a/src/libbasic/io-util.h
+++ b/src/libbasic/io-util.h
@@ -46,7 +46,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
char *_s = (char *)(s); \
_i->iov_base = _s; \
_i->iov_len = strlen(_s); \
- } while(false)
+ } while (false)
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) {
unsigned j;
diff --git a/src/libbasic/json.c b/src/libbasic/json.c
deleted file mode 100644
index daa98fc815..0000000000
--- a/src/libbasic/json.c
+++ /dev/null
@@ -1,871 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-
-#include "alloc-util.h"
-#include "hexdecoct.h"
-#include "json.h"
-#include "macro.h"
-#include "string-util.h"
-#include "utf8.h"
-
-int json_variant_new(JsonVariant **ret, JsonVariantType type) {
- JsonVariant *v;
-
- v = new0(JsonVariant, 1);
- if (!v)
- return -ENOMEM;
- v->type = type;
- *ret = v;
- return 0;
-}
-
-static int json_variant_deep_copy(JsonVariant *ret, JsonVariant *variant) {
- int r;
-
- assert(ret);
- assert(variant);
-
- ret->type = variant->type;
- ret->size = variant->size;
-
- if (variant->type == JSON_VARIANT_STRING) {
- ret->string = memdup(variant->string, variant->size+1);
- if (!ret->string)
- return -ENOMEM;
- } else if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT) {
- size_t i;
-
- ret->objects = new0(JsonVariant, variant->size);
- if (!ret->objects)
- return -ENOMEM;
-
- for (i = 0; i < variant->size; ++i) {
- r = json_variant_deep_copy(&ret->objects[i], &variant->objects[i]);
- if (r < 0)
- return r;
- }
- } else
- ret->value = variant->value;
-
- return 0;
-}
-
-static JsonVariant *json_object_unref(JsonVariant *variant);
-
-static JsonVariant *json_variant_unref_inner(JsonVariant *variant) {
- if (!variant)
- return NULL;
-
- if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT)
- return json_object_unref(variant);
- else if (variant->type == JSON_VARIANT_STRING)
- free(variant->string);
-
- return NULL;
-}
-
-static JsonVariant *json_raw_unref(JsonVariant *variant, size_t size) {
- if (!variant)
- return NULL;
-
- for (size_t i = 0; i < size; ++i)
- json_variant_unref_inner(&variant[i]);
-
- free(variant);
- return NULL;
-}
-
-static JsonVariant *json_object_unref(JsonVariant *variant) {
- size_t i;
-
- assert(variant);
-
- if (!variant->objects)
- return NULL;
-
- for (i = 0; i < variant->size; ++i)
- json_variant_unref_inner(&variant->objects[i]);
-
- free(variant->objects);
- return NULL;
-}
-
-static JsonVariant **json_variant_array_unref(JsonVariant **variant) {
- size_t i = 0;
- JsonVariant *p = NULL;
-
- if (!variant)
- return NULL;
-
- while((p = (variant[i++])) != NULL) {
- if (p->type == JSON_VARIANT_STRING)
- free(p->string);
- free(p);
- }
-
- free(variant);
-
- return NULL;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant **, json_variant_array_unref);
-
-JsonVariant *json_variant_unref(JsonVariant *variant) {
- if (!variant)
- return NULL;
-
- if (variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT)
- json_object_unref(variant);
- else if (variant->type == JSON_VARIANT_STRING)
- free(variant->string);
-
- free(variant);
-
- return NULL;
-}
-
-char *json_variant_string(JsonVariant *variant){
- assert(variant);
- assert(variant->type == JSON_VARIANT_STRING);
-
- return variant->string;
-}
-
-bool json_variant_bool(JsonVariant *variant) {
- assert(variant);
- assert(variant->type == JSON_VARIANT_BOOLEAN);
-
- return variant->value.boolean;
-}
-
-intmax_t json_variant_integer(JsonVariant *variant) {
- assert(variant);
- assert(variant->type == JSON_VARIANT_INTEGER);
-
- return variant->value.integer;
-}
-
-double json_variant_real(JsonVariant *variant) {
- assert(variant);
- assert(variant->type == JSON_VARIANT_REAL);
-
- return variant->value.real;
-}
-
-JsonVariant *json_variant_element(JsonVariant *variant, unsigned index) {
- assert(variant);
- assert(variant->type == JSON_VARIANT_ARRAY || variant->type == JSON_VARIANT_OBJECT);
- assert(index < variant->size);
- assert(variant->objects);
-
- return &variant->objects[index];
-}
-
-JsonVariant *json_variant_value(JsonVariant *variant, const char *key) {
- size_t i;
-
- assert(variant);
- assert(variant->type == JSON_VARIANT_OBJECT);
- assert(variant->objects);
-
- for (i = 0; i < variant->size; i += 2) {
- JsonVariant *p = &variant->objects[i];
- if (p->type == JSON_VARIANT_STRING && streq(key, p->string))
- return &variant->objects[i + 1];
- }
-
- return NULL;
-}
-
-static void inc_lines(unsigned *line, const char *s, size_t n) {
- const char *p = s;
-
- if (!line)
- return;
-
- for (;;) {
- const char *f;
-
- f = memchr(p, '\n', n);
- if (!f)
- return;
-
- n -= (f - p) + 1;
- p = f + 1;
- (*line)++;
- }
-}
-
-static int unhex_ucs2(const char *c, uint16_t *ret) {
- int aa, bb, cc, dd;
- uint16_t x;
-
- assert(c);
- assert(ret);
-
- aa = unhexchar(c[0]);
- if (aa < 0)
- return -EINVAL;
-
- bb = unhexchar(c[1]);
- if (bb < 0)
- return -EINVAL;
-
- cc = unhexchar(c[2]);
- if (cc < 0)
- return -EINVAL;
-
- dd = unhexchar(c[3]);
- if (dd < 0)
- return -EINVAL;
-
- x = ((uint16_t) aa << 12) |
- ((uint16_t) bb << 8) |
- ((uint16_t) cc << 4) |
- ((uint16_t) dd);
-
- if (x <= 0)
- return -EINVAL;
-
- *ret = x;
-
- return 0;
-}
-
-static int json_parse_string(const char **p, char **ret) {
- _cleanup_free_ char *s = NULL;
- size_t n = 0, allocated = 0;
- const char *c;
-
- assert(p);
- assert(*p);
- assert(ret);
-
- c = *p;
-
- if (*c != '"')
- return -EINVAL;
-
- c++;
-
- for (;;) {
- int len;
-
- /* Check for EOF */
- if (*c == 0)
- return -EINVAL;
-
- /* Check for control characters 0x00..0x1f */
- if (*c > 0 && *c < ' ')
- return -EINVAL;
-
- /* Check for control character 0x7f */
- if (*c == 0x7f)
- return -EINVAL;
-
- if (*c == '"') {
- if (!s) {
- s = strdup("");
- if (!s)
- return -ENOMEM;
- } else
- s[n] = 0;
-
- *p = c + 1;
-
- *ret = s;
- s = NULL;
- return JSON_STRING;
- }
-
- if (*c == '\\') {
- char ch = 0;
- c++;
-
- if (*c == 0)
- return -EINVAL;
-
- if (IN_SET(*c, '"', '\\', '/'))
- ch = *c;
- else if (*c == 'b')
- ch = '\b';
- else if (*c == 'f')
- ch = '\f';
- else if (*c == 'n')
- ch = '\n';
- else if (*c == 'r')
- ch = '\r';
- else if (*c == 't')
- ch = '\t';
- else if (*c == 'u') {
- char16_t x;
- int r;
-
- r = unhex_ucs2(c + 1, &x);
- if (r < 0)
- return r;
-
- c += 5;
-
- if (!GREEDY_REALLOC(s, allocated, n + 4))
- return -ENOMEM;
-
- if (!utf16_is_surrogate(x))
- n += utf8_encode_unichar(s + n, (char32_t) x);
- else if (utf16_is_trailing_surrogate(x))
- return -EINVAL;
- else {
- char16_t y;
-
- if (c[0] != '\\' || c[1] != 'u')
- return -EINVAL;
-
- r = unhex_ucs2(c + 2, &y);
- if (r < 0)
- return r;
-
- c += 6;
-
- if (!utf16_is_trailing_surrogate(y))
- return -EINVAL;
-
- n += utf8_encode_unichar(s + n, utf16_surrogate_pair_to_unichar(x, y));
- }
-
- continue;
- } else
- return -EINVAL;
-
- if (!GREEDY_REALLOC(s, allocated, n + 2))
- return -ENOMEM;
-
- s[n++] = ch;
- c ++;
- continue;
- }
-
- len = utf8_encoded_valid_unichar(c);
- if (len < 0)
- return len;
-
- if (!GREEDY_REALLOC(s, allocated, n + len + 1))
- return -ENOMEM;
-
- memcpy(s + n, c, len);
- n += len;
- c += len;
- }
-}
-
-static int json_parse_number(const char **p, union json_value *ret) {
- bool negative = false, exponent_negative = false, is_double = false;
- double x = 0.0, y = 0.0, exponent = 0.0, shift = 1.0;
- intmax_t i = 0;
- const char *c;
-
- assert(p);
- assert(*p);
- assert(ret);
-
- c = *p;
-
- if (*c == '-') {
- negative = true;
- c++;
- }
-
- if (*c == '0')
- c++;
- else {
- if (!strchr("123456789", *c) || *c == 0)
- return -EINVAL;
-
- do {
- if (!is_double) {
- int64_t t;
-
- t = 10 * i + (*c - '0');
- if (t < i) /* overflow */
- is_double = false;
- else
- i = t;
- }
-
- x = 10.0 * x + (*c - '0');
- c++;
- } while (strchr("0123456789", *c) && *c != 0);
- }
-
- if (*c == '.') {
- is_double = true;
- c++;
-
- if (!strchr("0123456789", *c) || *c == 0)
- return -EINVAL;
-
- do {
- y = 10.0 * y + (*c - '0');
- shift = 10.0 * shift;
- c++;
- } while (strchr("0123456789", *c) && *c != 0);
- }
-
- if (*c == 'e' || *c == 'E') {
- is_double = true;
- c++;
-
- if (*c == '-') {
- exponent_negative = true;
- c++;
- } else if (*c == '+')
- c++;
-
- if (!strchr("0123456789", *c) || *c == 0)
- return -EINVAL;
-
- do {
- exponent = 10.0 * exponent + (*c - '0');
- c++;
- } while (strchr("0123456789", *c) && *c != 0);
- }
-
- *p = c;
-
- if (is_double) {
- ret->real = ((negative ? -1.0 : 1.0) * (x + (y / shift))) * exp10((exponent_negative ? -1.0 : 1.0) * exponent);
- return JSON_REAL;
- } else {
- ret->integer = negative ? -i : i;
- return JSON_INTEGER;
- }
-}
-
-int json_tokenize(
- const char **p,
- char **ret_string,
- union json_value *ret_value,
- void **state,
- unsigned *line) {
-
- const char *c;
- int t;
- int r;
-
- enum {
- STATE_NULL,
- STATE_VALUE,
- STATE_VALUE_POST,
- };
-
- assert(p);
- assert(*p);
- assert(ret_string);
- assert(ret_value);
- assert(state);
-
- t = PTR_TO_INT(*state);
- c = *p;
-
- if (t == STATE_NULL) {
- if (line)
- *line = 1;
- t = STATE_VALUE;
- }
-
- for (;;) {
- const char *b;
-
- b = c + strspn(c, WHITESPACE);
- if (*b == 0)
- return JSON_END;
-
- inc_lines(line, c, b - c);
- c = b;
-
- switch (t) {
-
- case STATE_VALUE:
-
- if (*c == '{') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE);
- return JSON_OBJECT_OPEN;
-
- } else if (*c == '}') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return JSON_OBJECT_CLOSE;
-
- } else if (*c == '[') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE);
- return JSON_ARRAY_OPEN;
-
- } else if (*c == ']') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return JSON_ARRAY_CLOSE;
-
- } else if (*c == '"') {
- r = json_parse_string(&c, ret_string);
- if (r < 0)
- return r;
-
- *ret_value = JSON_VALUE_NULL;
- *p = c;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return r;
-
- } else if (strchr("-0123456789", *c)) {
- r = json_parse_number(&c, ret_value);
- if (r < 0)
- return r;
-
- *ret_string = NULL;
- *p = c;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return r;
-
- } else if (startswith(c, "true")) {
- *ret_string = NULL;
- ret_value->boolean = true;
- *p = c + 4;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return JSON_BOOLEAN;
-
- } else if (startswith(c, "false")) {
- *ret_string = NULL;
- ret_value->boolean = false;
- *p = c + 5;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return JSON_BOOLEAN;
-
- } else if (startswith(c, "null")) {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 4;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return JSON_NULL;
-
- } else
- return -EINVAL;
-
- case STATE_VALUE_POST:
-
- if (*c == ':') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE);
- return JSON_COLON;
- } else if (*c == ',') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE);
- return JSON_COMMA;
- } else if (*c == '}') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return JSON_OBJECT_CLOSE;
- } else if (*c == ']') {
- *ret_string = NULL;
- *ret_value = JSON_VALUE_NULL;
- *p = c + 1;
- *state = INT_TO_PTR(STATE_VALUE_POST);
- return JSON_ARRAY_CLOSE;
- } else
- return -EINVAL;
- }
-
- }
-}
-
-static bool json_is_value(JsonVariant *var) {
- assert(var);
-
- return var->type != JSON_VARIANT_CONTROL;
-}
-
-static int json_scoped_parse(JsonVariant **tokens, size_t *i, size_t n, JsonVariant *scope) {
- bool arr = scope->type == JSON_VARIANT_ARRAY;
- int terminator = arr ? JSON_ARRAY_CLOSE : JSON_OBJECT_CLOSE;
- size_t allocated = 0, size = 0;
- JsonVariant *key = NULL, *value = NULL, *var = NULL, *items = NULL;
- enum {
- STATE_KEY,
- STATE_COLON,
- STATE_COMMA,
- STATE_VALUE
- } state = arr ? STATE_VALUE : STATE_KEY;
-
- assert(tokens);
- assert(i);
- assert(scope);
-
- while((var = *i < n ? tokens[(*i)++] : NULL) != NULL) {
- bool stopper;
- int r;
-
- stopper = !json_is_value(var) && var->value.integer == terminator;
-
- if (stopper) {
- if (state != STATE_COMMA && size > 0)
- goto error;
-
- goto out;
- }
-
- if (state == STATE_KEY) {
- if (var->type != JSON_VARIANT_STRING)
- goto error;
- else {
- key = var;
- state = STATE_COLON;
- }
- }
- else if (state == STATE_COLON) {
- if (key == NULL)
- goto error;
-
- if (json_is_value(var))
- goto error;
-
- if (var->value.integer != JSON_COLON)
- goto error;
-
- state = STATE_VALUE;
- }
- else if (state == STATE_VALUE) {
- _cleanup_json_variant_unref_ JsonVariant *v = NULL;
- size_t toadd = arr ? 1 : 2;
-
- if (!json_is_value(var)) {
- int type = (var->value.integer == JSON_ARRAY_OPEN) ? JSON_VARIANT_ARRAY : JSON_VARIANT_OBJECT;
-
- r = json_variant_new(&v, type);
- if (r < 0)
- goto error;
-
- r = json_scoped_parse(tokens, i, n, v);
- if (r < 0)
- goto error;
-
- value = v;
- }
- else
- value = var;
-
- if(!GREEDY_REALLOC(items, allocated, size + toadd))
- goto error;
-
- if (arr) {
- r = json_variant_deep_copy(&items[size], value);
- if (r < 0)
- goto error;
- } else {
- r = json_variant_deep_copy(&items[size], key);
- if (r < 0)
- goto error;
-
- r = json_variant_deep_copy(&items[size+1], value);
- if (r < 0)
- goto error;
- }
-
- size += toadd;
- state = STATE_COMMA;
- }
- else if (state == STATE_COMMA) {
- if (json_is_value(var))
- goto error;
-
- if (var->value.integer != JSON_COMMA)
- goto error;
-
- key = NULL;
- value = NULL;
-
- state = arr ? STATE_VALUE : STATE_KEY;
- }
- }
-
-error:
- json_raw_unref(items, size);
- return -EBADMSG;
-
-out:
- scope->size = size;
- scope->objects = items;
-
- return scope->type;
-}
-
-static int json_parse_tokens(JsonVariant **tokens, size_t ntokens, JsonVariant **rv) {
- size_t it = 0;
- int r;
- JsonVariant *e;
- _cleanup_json_variant_unref_ JsonVariant *p = NULL;
-
- assert(tokens);
- assert(ntokens);
-
- e = tokens[it++];
- r = json_variant_new(&p, JSON_VARIANT_OBJECT);
- if (r < 0)
- return r;
-
- if (e->type != JSON_VARIANT_CONTROL && e->value.integer != JSON_OBJECT_OPEN)
- return -EBADMSG;
-
- r = json_scoped_parse(tokens, &it, ntokens, p);
- if (r < 0)
- return r;
-
- *rv = p;
- p = NULL;
-
- return 0;
-}
-
-static int json_tokens(const char *string, size_t size, JsonVariant ***tokens, size_t *n) {
- _cleanup_free_ char *buf = NULL;
- _cleanup_(json_variant_array_unrefp) JsonVariant **items = NULL;
- union json_value v = {};
- void *json_state = NULL;
- const char *p;
- int t, r;
- size_t allocated = 0, s = 0;
-
- assert(string);
- assert(n);
-
- if (size <= 0)
- return -EBADMSG;
-
- buf = strndup(string, size);
- if (!buf)
- return -ENOMEM;
-
- p = buf;
- for (;;) {
- _cleanup_json_variant_unref_ JsonVariant *var = NULL;
- _cleanup_free_ char *rstr = NULL;
-
- t = json_tokenize(&p, &rstr, &v, &json_state, NULL);
-
- if (t < 0)
- return t;
- else if (t == JSON_END)
- break;
-
- if (t <= JSON_ARRAY_CLOSE) {
- r = json_variant_new(&var, JSON_VARIANT_CONTROL);
- if (r < 0)
- return r;
- var->value.integer = t;
- } else {
- switch (t) {
- case JSON_STRING:
- r = json_variant_new(&var, JSON_VARIANT_STRING);
- if (r < 0)
- return r;
- var->size = strlen(rstr);
- var->string = strdup(rstr);
- if (!var->string) {
- return -ENOMEM;
- }
- break;
- case JSON_INTEGER:
- r = json_variant_new(&var, JSON_VARIANT_INTEGER);
- if (r < 0)
- return r;
- var->value = v;
- break;
- case JSON_REAL:
- r = json_variant_new(&var, JSON_VARIANT_REAL);
- if (r < 0)
- return r;
- var->value = v;
- break;
- case JSON_BOOLEAN:
- r = json_variant_new(&var, JSON_VARIANT_BOOLEAN);
- if (r < 0)
- return r;
- var->value = v;
- break;
- case JSON_NULL:
- r = json_variant_new(&var, JSON_VARIANT_NULL);
- if (r < 0)
- return r;
- break;
- }
- }
-
- if (!GREEDY_REALLOC(items, allocated, s+2))
- return -ENOMEM;
-
- items[s++] = var;
- items[s] = NULL;
- var = NULL;
- }
-
- *n = s;
- *tokens = items;
- items = NULL;
-
- return 0;
-}
-
-int json_parse(const char *string, JsonVariant **rv) {
- _cleanup_(json_variant_array_unrefp) JsonVariant **s = NULL;
- JsonVariant *v = NULL;
- size_t n = 0;
- int r;
-
- assert(string);
- assert(rv);
-
- r = json_tokens(string, strlen(string), &s, &n);
- if (r < 0)
- return r;
-
- r = json_parse_tokens(s, n, &v);
- if (r < 0)
- return r;
-
- *rv = v;
- return 0;
-}
diff --git a/src/libbasic/json.h b/src/libbasic/json.h
deleted file mode 100644
index a4509f680f..0000000000
--- a/src/libbasic/json.h
+++ /dev/null
@@ -1,90 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include "macro.h"
-#include "util.h"
-
-enum {
- JSON_END,
- JSON_COLON,
- JSON_COMMA,
- JSON_OBJECT_OPEN,
- JSON_OBJECT_CLOSE,
- JSON_ARRAY_OPEN,
- JSON_ARRAY_CLOSE,
- JSON_STRING,
- JSON_REAL,
- JSON_INTEGER,
- JSON_BOOLEAN,
- JSON_NULL,
-};
-
-typedef enum {
- JSON_VARIANT_CONTROL,
- JSON_VARIANT_STRING,
- JSON_VARIANT_INTEGER,
- JSON_VARIANT_BOOLEAN,
- JSON_VARIANT_REAL,
- JSON_VARIANT_ARRAY,
- JSON_VARIANT_OBJECT,
- JSON_VARIANT_NULL
-} JsonVariantType;
-
-union json_value {
- bool boolean;
- double real;
- intmax_t integer;
-};
-
-typedef struct JsonVariant {
- JsonVariantType type;
- size_t size;
- union {
- char *string;
- struct JsonVariant *objects;
- union json_value value;
- };
-} JsonVariant;
-
-int json_variant_new(JsonVariant **ret, JsonVariantType type);
-JsonVariant *json_variant_unref(JsonVariant *v);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(JsonVariant *, json_variant_unref);
-#define _cleanup_json_variant_unref_ _cleanup_(json_variant_unrefp)
-
-char *json_variant_string(JsonVariant *v);
-bool json_variant_bool(JsonVariant *v);
-intmax_t json_variant_integer(JsonVariant *v);
-double json_variant_real(JsonVariant *v);
-
-JsonVariant *json_variant_element(JsonVariant *v, unsigned index);
-JsonVariant *json_variant_value(JsonVariant *v, const char *key);
-
-#define JSON_VALUE_NULL ((union json_value) {})
-
-int json_tokenize(const char **p, char **ret_string, union json_value *ret_value, void **state, unsigned *line);
-
-int json_parse(const char *string, JsonVariant **rv);
-int json_parse_measure(const char *string, size_t *size);
diff --git a/src/libbasic/list.h b/src/libbasic/list.h
index c68185f587..5962aa4211 100644
--- a/src/libbasic/list.h
+++ b/src/libbasic/list.h
@@ -32,7 +32,7 @@
#define LIST_HEAD_INIT(head) \
do { \
(head) = NULL; } \
- while(false)
+ while (false)
/* Initialize a list item */
#define LIST_INIT(name,item) \
@@ -40,7 +40,7 @@
typeof(*(item)) *_item = (item); \
assert(_item); \
_item->name##_prev = _item->name##_next = NULL; \
- } while(false)
+ } while (false)
/* Prepend an item to the list */
#define LIST_PREPEND(name,head,item) \
@@ -51,7 +51,7 @@
_item->name##_next->name##_prev = _item; \
_item->name##_prev = NULL; \
*_head = _item; \
- } while(false)
+ } while (false)
/* Append an item to the list */
#define LIST_APPEND(name,head,item) \
@@ -59,7 +59,7 @@
typeof(*(head)) *_tail; \
LIST_FIND_TAIL(name,head,_tail); \
LIST_INSERT_AFTER(name,head,_tail,item); \
- } while(false)
+ } while (false)
/* Remove an item from the list */
#define LIST_REMOVE(name,head,item) \
@@ -75,7 +75,7 @@
*_head = _item->name##_next; \
} \
_item->name##_next = _item->name##_prev = NULL; \
- } while(false)
+ } while (false)
/* Find the head of the list */
#define LIST_FIND_HEAD(name,item,head) \
@@ -119,7 +119,7 @@
_b->name##_prev = _a; \
_a->name##_next = _b; \
} \
- } while(false)
+ } while (false)
/* Insert an item before another one (a = where, b = what) */
#define LIST_INSERT_BEFORE(name,head,a,b) \
@@ -145,7 +145,7 @@
_b->name##_next = _a; \
_a->name##_prev = _b; \
} \
- } while(false)
+ } while (false)
#define LIST_JUST_US(name,item) \
(!(item)->name##_prev && !(item)->name##_next) \
diff --git a/src/libbasic/locale-util.c b/src/libbasic/locale-util.c
index cda6b2895d..ada0a28cd8 100644
--- a/src/libbasic/locale-util.c
+++ b/src/libbasic/locale-util.c
@@ -153,6 +153,8 @@ static int add_locales_from_libdir (Set *locales) {
FOREACH_DIRENT(entry, dir, return -errno) {
char *z;
+ dirent_ensure_type(dir, entry);
+
if (entry->d_type != DT_DIR)
continue;
@@ -269,34 +271,35 @@ out:
}
-const char *draw_special_char(DrawSpecialChar ch) {
-
- static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = {
+const char *special_glyph(SpecialGlyph code) {
- /* 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", /* – */
+ static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = {
+ /* ASCII fallback */
+ [false] = {
+ [TREE_VERTICAL] = "| ",
+ [TREE_BRANCH] = "|-",
+ [TREE_RIGHT] = "`-",
+ [TREE_SPACE] = " ",
+ [TRIANGULAR_BULLET] = ">",
+ [BLACK_CIRCLE] = "*",
+ [ARROW] = "->",
+ [MDASH] = "-",
},
- /* ASCII fallback */ {
- [DRAW_TREE_VERTICAL] = "| ",
- [DRAW_TREE_BRANCH] = "|-",
- [DRAW_TREE_RIGHT] = "`-",
- [DRAW_TREE_SPACE] = " ",
- [DRAW_TRIANGULAR_BULLET] = ">",
- [DRAW_BLACK_CIRCLE] = "*",
- [DRAW_ARROW] = "->",
- [DRAW_DASH] = "-",
- }
+ /* UTF-8 */
+ [ true ] = {
+ [TREE_VERTICAL] = "\342\224\202 ", /* │ */
+ [TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */
+ [TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */
+ [TREE_SPACE] = " ", /* */
+ [TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */
+ [BLACK_CIRCLE] = "\342\227\217", /* ● */
+ [ARROW] = "\342\206\222", /* → */
+ [MDASH] = "\342\200\223", /* – */
+ },
};
- return draw_table[!is_locale_utf8()][ch];
+ return draw_table[is_locale_utf8()][code];
}
static const char * const locale_variable_table[_VARIABLE_LC_MAX] = {
diff --git a/src/libbasic/locale-util.h b/src/libbasic/locale-util.h
index b0f9679286..0630a034ab 100644
--- a/src/libbasic/locale-util.h
+++ b/src/libbasic/locale-util.h
@@ -55,19 +55,19 @@ 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;
+typedef enum {
+ TREE_VERTICAL,
+ TREE_BRANCH,
+ TREE_RIGHT,
+ TREE_SPACE,
+ TRIANGULAR_BULLET,
+ BLACK_CIRCLE,
+ ARROW,
+ MDASH,
+ _SPECIAL_GLYPH_MAX
+} SpecialGlyph;
-const char *draw_special_char(DrawSpecialChar ch);
+const char *special_glyph(SpecialGlyph code) _const_;
const char* locale_variable_to_string(LocaleVariable i) _const_;
LocaleVariable locale_variable_from_string(const char *s) _pure_;
diff --git a/src/libbasic/log.c b/src/libbasic/log.c
index f625e3bd95..05c4896f55 100644
--- a/src/libbasic/log.c
+++ b/src/libbasic/log.c
@@ -165,7 +165,7 @@ static int log_open_syslog(void) {
goto fail;
}
- if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
safe_close(syslog_fd);
/* Some legacy syslog systems still use stream
@@ -177,7 +177,7 @@ static int log_open_syslog(void) {
goto fail;
}
- if (connect(syslog_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(syslog_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
@@ -215,7 +215,7 @@ static int log_open_journal(void) {
goto fail;
}
- if (connect(journal_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(journal_fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = -errno;
goto fail;
}
diff --git a/src/libbasic/log.h b/src/libbasic/log.h
index 8ccbf8ed70..d2a22b5829 100644
--- a/src/libbasic/log.h
+++ b/src/libbasic/log.h
@@ -193,7 +193,7 @@ void log_assert_failed_return(
#ifdef LOG_TRACE
# define log_trace(...) log_debug(__VA_ARGS__)
#else
-# define log_trace(...) do {} while(0)
+# define log_trace(...) do {} while (0)
#endif
/* Structured logging */
@@ -246,5 +246,4 @@ int log_syntax_internal(
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/libbasic/login-util.h b/src/libbasic/login-util.h
index 89a337d7c1..b01ee25c88 100644
--- a/src/libbasic/login-util.h
+++ b/src/libbasic/login-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <stdbool.h>
#include <unistd.h>
diff --git a/src/libbasic/macro.h b/src/libbasic/macro.h
index 2695d0edb7..e41aa4260f 100644
--- a/src/libbasic/macro.h
+++ b/src/libbasic/macro.h
@@ -23,10 +23,15 @@
#include <inttypes.h>
#include <stdbool.h>
#include <sys/param.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#define _printf_(a,b) __attribute__ ((format (printf, a, b)))
-#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
+#ifdef __clang__
+# define _alloc_(...)
+#else
+# define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__)))
+#endif
#define _sentinel_ __attribute__ ((sentinel))
#define _unused_ __attribute__ ((unused))
#define _destructor_ __attribute__ ((destructor))
@@ -224,7 +229,7 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
/* We override the glibc assert() here. */
#undef assert
#ifdef NDEBUG
-#define assert(expr) do {} while(false)
+#define assert(expr) do {} while (false)
#else
#define assert(expr) assert_message_se(expr, #expr)
#endif
@@ -361,6 +366,12 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) {
_found; \
})
+#define SWAP_TWO(x, y) do { \
+ typeof(x) _t = (x); \
+ (x) = (y); \
+ (y) = (_t); \
+ } while (false)
+
/* Define C11 thread_local attribute even on older gcc compiler
* version */
#ifndef thread_local
diff --git a/src/libbasic/mempool.h b/src/libbasic/mempool.h
index fea7841bcf..0618b8dd22 100644
--- a/src/libbasic/mempool.h
+++ b/src/libbasic/mempool.h
@@ -36,7 +36,7 @@ void* mempool_alloc0_tile(struct mempool *mp);
void mempool_free_tile(struct mempool *mp, void *p);
#define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \
-struct mempool pool_name = { \
+static struct mempool pool_name = { \
.tile_size = sizeof(tile_type), \
.at_least = alloc_at_least, \
}
diff --git a/src/libbasic/missing.h b/src/libbasic/missing.h
index 36b060496a..651e414395 100644
--- a/src/libbasic/missing.h
+++ b/src/libbasic/missing.h
@@ -31,6 +31,7 @@
#include <linux/neighbour.h>
#include <linux/oom.h>
#include <linux/rtnetlink.h>
+#include <net/ethernet.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/syscall.h>
@@ -134,84 +135,6 @@
#define SOL_SCTP 132
#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);
-}
-#endif
-
-#ifndef __NR_memfd_create
-# if defined __x86_64__
-# define __NR_memfd_create 319
-# elif defined __arm__
-# define __NR_memfd_create 385
-# elif defined __aarch64__
-# define __NR_memfd_create 279
-# elif defined __s390__
-# define __NR_memfd_create 350
-# elif defined _MIPS_SIM
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define __NR_memfd_create 4354
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32
-# define __NR_memfd_create 6318
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64
-# define __NR_memfd_create 5314
-# endif
-# elif defined __i386__
-# define __NR_memfd_create 356
-# else
-# warning "__NR_memfd_create unknown for your architecture"
-# define __NR_memfd_create 0xffffffff
-# endif
-#endif
-
-#ifndef HAVE_MEMFD_CREATE
-static inline int memfd_create(const char *name, unsigned int flags) {
- return syscall(__NR_memfd_create, name, flags);
-}
-#endif
-
-#ifndef __NR_getrandom
-# if defined __x86_64__
-# define __NR_getrandom 318
-# elif defined(__i386__)
-# define __NR_getrandom 355
-# elif defined(__arm__)
-# define __NR_getrandom 384
-# elif defined(__aarch64__)
-# define __NR_getrandom 278
-# elif defined(__ia64__)
-# define __NR_getrandom 1339
-# elif defined(__m68k__)
-# define __NR_getrandom 352
-# elif defined(__s390x__)
-# define __NR_getrandom 349
-# elif defined(__powerpc__)
-# define __NR_getrandom 359
-# elif defined _MIPS_SIM
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define __NR_getrandom 4353
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32
-# define __NR_getrandom 6317
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64
-# define __NR_getrandom 5313
-# endif
-# else
-# warning "__NR_getrandom unknown for your architecture"
-# define __NR_getrandom 0xffffffff
-# endif
-#endif
-
-#if !HAVE_DECL_GETRANDOM
-static inline int getrandom(void *buffer, size_t count, unsigned flags) {
- return syscall(__NR_getrandom, buffer, count, flags);
-}
-#endif
-
#ifndef GRND_NONBLOCK
#define GRND_NONBLOCK 0x0001
#endif
@@ -466,6 +389,10 @@ struct btrfs_ioctl_quota_ctl_args {
struct btrfs_ioctl_qgroup_limit_args)
#endif
+#ifndef BTRFS_IOC_QUOTA_RESCAN_WAIT
+#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46)
+#endif
+
#ifndef BTRFS_FIRST_FREE_OBJECTID
#define BTRFS_FIRST_FREE_OBJECTID 256
#endif
@@ -514,10 +441,18 @@ struct btrfs_ioctl_quota_ctl_args {
#define CGROUP_SUPER_MAGIC 0x27e0eb
#endif
+#ifndef CGROUP2_SUPER_MAGIC
+#define CGROUP2_SUPER_MAGIC 0x63677270
+#endif
+
#ifndef TMPFS_MAGIC
#define TMPFS_MAGIC 0x01021994
#endif
+#ifndef MQUEUE_MAGIC
+#define MQUEUE_MAGIC 0x19800202
+#endif
+
#ifndef MS_MOVE
#define MS_MOVE 8192
#endif
@@ -526,12 +461,6 @@ struct btrfs_ioctl_quota_ctl_args {
#define MS_PRIVATE (1 << 18)
#endif
-#if !HAVE_DECL_GETTID
-static inline pid_t gettid(void) {
- return (pid_t) syscall(SYS_gettid);
-}
-#endif
-
#ifndef SCM_SECURITY
#define SCM_SECURITY 0x03
#endif
@@ -560,32 +489,6 @@ static inline pid_t gettid(void) {
#define MAX_HANDLE_SZ 128
#endif
-#ifndef __NR_name_to_handle_at
-# if defined(__x86_64__)
-# define __NR_name_to_handle_at 303
-# elif defined(__i386__)
-# define __NR_name_to_handle_at 341
-# elif defined(__arm__)
-# define __NR_name_to_handle_at 370
-# elif defined(__powerpc__)
-# define __NR_name_to_handle_at 345
-# else
-# error "__NR_name_to_handle_at is not defined"
-# endif
-#endif
-
-#if !HAVE_DECL_NAME_TO_HANDLE_AT
-struct file_handle {
- unsigned int handle_bytes;
- int handle_type;
- unsigned char f_handle[0];
-};
-
-static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) {
- return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags);
-}
-#endif
-
#ifndef HAVE_SECURE_GETENV
# ifdef HAVE___SECURE_GETENV
# define secure_getenv __secure_getenv
@@ -634,22 +537,6 @@ static inline int name_to_handle_at(int fd, const char *name, struct file_handle
#endif
-#ifndef __NR_setns
-# if defined(__x86_64__)
-# define __NR_setns 308
-# elif defined(__i386__)
-# define __NR_setns 346
-# else
-# error "__NR_setns is not defined"
-# endif
-#endif
-
-#if !HAVE_DECL_SETNS
-static inline int setns(int fd, int nstype) {
- return syscall(__NR_setns, fd, nstype);
-}
-#endif
-
#if !HAVE_DECL_LO_FLAGS_PARTSCAN
#define LO_FLAGS_PARTSCAN 8
#endif
@@ -674,7 +561,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_INET6_ADDR_GEN_MODE 8
#define __IFLA_INET6_MAX 9
-#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
#define IN6_ADDR_GEN_MODE_EUI64 0
#define IN6_ADDR_GEN_MODE_NONE 1
@@ -714,6 +601,7 @@ static inline int setns(int fd, int nstype) {
#endif
#if !HAVE_DECL_IFLA_PHYS_PORT_ID
+#define IFLA_EXT_MASK 29
#undef IFLA_PROMISCUITY
#define IFLA_PROMISCUITY 30
#define IFLA_NUM_TX_QUEUES 31
@@ -858,7 +746,7 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1)
#endif
-#if !HAVE_DECL_IFLA_BR_PRIORITY
+#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID
#define IFLA_BR_UNSPEC 0
#define IFLA_BR_FORWARD_DELAY 1
#define IFLA_BR_HELLO_TIME 2
@@ -866,7 +754,40 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BR_AGEING_TIME 4
#define IFLA_BR_STP_STATE 5
#define IFLA_BR_PRIORITY 6
-#define __IFLA_BR_MAX 7
+#define IFLA_BR_VLAN_FILTERING 7
+#define IFLA_BR_VLAN_PROTOCOL 8
+#define IFLA_BR_GROUP_FWD_MASK 9
+#define IFLA_BR_ROOT_ID 10
+#define IFLA_BR_BRIDGE_ID 11
+#define IFLA_BR_ROOT_PORT 12
+#define IFLA_BR_ROOT_PATH_COST 13
+#define IFLA_BR_TOPOLOGY_CHANGE 14
+#define IFLA_BR_TOPOLOGY_CHANGE_DETECTED 15
+#define IFLA_BR_HELLO_TIMER 16
+#define IFLA_BR_TCN_TIMER 17
+#define IFLA_BR_TOPOLOGY_CHANGE_TIMER 18
+#define IFLA_BR_GC_TIMER 19
+#define IFLA_BR_GROUP_ADDR 20
+#define IFLA_BR_FDB_FLUSH 21
+#define IFLA_BR_MCAST_ROUTER 22
+#define IFLA_BR_MCAST_SNOOPING 23
+#define IFLA_BR_MCAST_QUERY_USE_IFADDR 24
+#define IFLA_BR_MCAST_QUERIER 25
+#define IFLA_BR_MCAST_HASH_ELASTICITY 26
+#define IFLA_BR_MCAST_HASH_MAX 27
+#define IFLA_BR_MCAST_LAST_MEMBER_CNT 28
+#define IFLA_BR_MCAST_STARTUP_QUERY_CNT 29
+#define IFLA_BR_MCAST_LAST_MEMBER_INTVL 30
+#define IFLA_BR_MCAST_MEMBERSHIP_INTVL 31
+#define IFLA_BR_MCAST_QUERIER_INTVL 32
+#define IFLA_BR_MCAST_QUERY_INTVL 33
+#define IFLA_BR_MCAST_QUERY_RESPONSE_INTVL 34
+#define IFLA_BR_MCAST_STARTUP_QUERY_INTVL 35
+#define IFLA_BR_NF_CALL_IPTABLES 36
+#define IFLA_BR_NF_CALL_IP6TABLES 37
+#define IFLA_BR_NF_CALL_ARPTABLES 38
+#define IFLA_BR_VLAN_DEFAULT_PVID 39
+#define __IFLA_BR_MAX 40
#define IFLA_BR_MAX (__IFLA_BR_MAX - 1)
#endif
@@ -882,13 +803,16 @@ static inline int setns(int fd, int nstype) {
#define IFLA_BRPORT_FAST_LEAVE 7
#define IFLA_BRPORT_LEARNING 8
#define IFLA_BRPORT_UNICAST_FLOOD 9
-#define IFLA_BRPORT_PROXYARP 10
#define IFLA_BRPORT_LEARNING_SYNC 11
#define __IFLA_BRPORT_MAX 12
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
#endif
+#if !HAVE_DECL_IFLA_BRPORT_PROXYARP
+#define IFLA_BRPORT_PROXYARP 10
+#endif
+
#if !HAVE_DECL_NDA_IFINDEX
#define NDA_UNSPEC 0
#define NDA_DST 1
@@ -912,6 +836,10 @@ static inline int setns(int fd, int nstype) {
#define IPV6_UNICAST_IF 76
#endif
+#ifndef IPV6_MIN_MTU
+#define IPV6_MIN_MTU 1280
+#endif
+
#ifndef IFF_MULTI_QUEUE
#define IFF_MULTI_QUEUE 0x100
#endif
@@ -1013,69 +941,10 @@ static inline int setns(int fd, int nstype) {
#define CAP_AUDIT_READ 37
#endif
-static inline int raw_clone(unsigned long flags, void *child_stack) {
-#if defined(__s390__) || defined(__CRIS__)
- /* On s390 and cris the order of the first and second arguments
- * of the raw clone() system call is reversed. */
- return (int) syscall(__NR_clone, child_stack, flags);
-#else
- return (int) syscall(__NR_clone, flags, child_stack);
-#endif
-}
-
-static inline pid_t raw_getpid(void) {
-#if defined(__alpha__)
- return (pid_t) syscall(__NR_getxpid);
-#else
- return (pid_t) syscall(__NR_getpid);
-#endif
-}
-
-#if !HAVE_DECL_RENAMEAT2
-
-#ifndef __NR_renameat2
-# if defined __x86_64__
-# define __NR_renameat2 316
-# elif defined __arm__
-# define __NR_renameat2 382
-# elif defined _MIPS_SIM
-# if _MIPS_SIM == _MIPS_SIM_ABI32
-# define __NR_renameat2 4351
-# endif
-# if _MIPS_SIM == _MIPS_SIM_NABI32
-# define __NR_renameat2 6315
-# endif
-# if _MIPS_SIM == _MIPS_SIM_ABI64
-# define __NR_renameat2 5311
-# endif
-# elif defined __i386__
-# define __NR_renameat2 353
-# else
-# warning "__NR_renameat2 unknown for your architecture"
-# define __NR_renameat2 0xffffffff
-# endif
-#endif
-
-static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
- return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags);
-}
-#endif
-
#ifndef RENAME_NOREPLACE
#define RENAME_NOREPLACE (1 << 0)
#endif
-#if !HAVE_DECL_KCMP
-static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
-#if defined(__NR_kcmp)
- return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-#endif
-
#ifndef KCMP_FILE
#define KCMP_FILE 0
#endif
@@ -1088,39 +957,10 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns
#define INPUT_PROP_ACCELEROMETER 0x06
#endif
-#if !HAVE_DECL_KEY_SERIAL_T
+#ifndef HAVE_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
@@ -1159,12 +999,18 @@ static inline key_serial_t request_key(const char *type, const char *description
#ifndef IF_OPER_UP
#define IF_OPER_UP 6
-#ifndef HAVE_DECL_CHAR32_T
+#ifndef HAVE_CHAR32_T
#define char32_t uint32_t
#endif
-#ifndef HAVE_DECL_CHAR16_T
+#ifndef HAVE_CHAR16_T
#define char16_t uint16_t
#endif
+#ifndef ETHERTYPE_LLDP
+#define ETHERTYPE_LLDP 0x88cc
#endif
+
+#endif
+
+#include "missing_syscall.h"
diff --git a/src/libbasic/missing_syscall.h b/src/libbasic/missing_syscall.h
new file mode 100644
index 0000000000..d502d3b9ca
--- /dev/null
+++ b/src/libbasic/missing_syscall.h
@@ -0,0 +1,310 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+/* Missing glibc definitions to access certain kernel APIs */
+
+#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);
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_MEMFD_CREATE
+# ifndef __NR_memfd_create
+# if defined __x86_64__
+# define __NR_memfd_create 319
+# elif defined __arm__
+# define __NR_memfd_create 385
+# elif defined __aarch64__
+# define __NR_memfd_create 279
+# elif defined __s390__
+# define __NR_memfd_create 350
+# elif defined _MIPS_SIM
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_memfd_create 4354
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_memfd_create 6318
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_memfd_create 5314
+# endif
+# elif defined __i386__
+# define __NR_memfd_create 356
+# else
+# warning "__NR_memfd_create unknown for your architecture"
+# endif
+# endif
+
+static inline int memfd_create(const char *name, unsigned int flags) {
+# ifdef __NR_memfd_create
+ return syscall(__NR_memfd_create, name, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_GETRANDOM
+# ifndef __NR_getrandom
+# if defined __x86_64__
+# define __NR_getrandom 318
+# elif defined(__i386__)
+# define __NR_getrandom 355
+# elif defined(__arm__)
+# define __NR_getrandom 384
+# elif defined(__aarch64__)
+# define __NR_getrandom 278
+# elif defined(__ia64__)
+# define __NR_getrandom 1339
+# elif defined(__m68k__)
+# define __NR_getrandom 352
+# elif defined(__s390x__)
+# define __NR_getrandom 349
+# elif defined(__powerpc__)
+# define __NR_getrandom 359
+# elif defined _MIPS_SIM
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_getrandom 4353
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_getrandom 6317
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_getrandom 5313
+# endif
+# else
+# warning "__NR_getrandom unknown for your architecture"
+# endif
+# endif
+
+static inline int getrandom(void *buffer, size_t count, unsigned flags) {
+# ifdef __NR_getrandom
+ return syscall(__NR_getrandom, buffer, count, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_GETTID
+static inline pid_t gettid(void) {
+ return (pid_t) syscall(SYS_gettid);
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_NAME_TO_HANDLE_AT
+# ifndef __NR_name_to_handle_at
+# if defined(__x86_64__)
+# define __NR_name_to_handle_at 303
+# elif defined(__i386__)
+# define __NR_name_to_handle_at 341
+# elif defined(__arm__)
+# define __NR_name_to_handle_at 370
+# elif defined(__powerpc__)
+# define __NR_name_to_handle_at 345
+# else
+# error "__NR_name_to_handle_at is not defined"
+# endif
+# endif
+
+struct file_handle {
+ unsigned int handle_bytes;
+ int handle_type;
+ unsigned char f_handle[0];
+};
+
+static inline int name_to_handle_at(int fd, const char *name, struct file_handle *handle, int *mnt_id, int flags) {
+# ifdef __NR_name_to_handle_at
+ return syscall(__NR_name_to_handle_at, fd, name, handle, mnt_id, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_SETNS
+# ifndef __NR_setns
+# if defined(__x86_64__)
+# define __NR_setns 308
+# elif defined(__i386__)
+# define __NR_setns 346
+# else
+# error "__NR_setns is not defined"
+# endif
+# endif
+
+static inline int setns(int fd, int nstype) {
+# ifdef __NR_setns
+ return syscall(__NR_setns, fd, nstype);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+/* ======================================================================= */
+
+static inline int raw_clone(unsigned long flags, void *child_stack) {
+#if defined(__s390__) || defined(__CRIS__)
+ /* On s390 and cris the order of the first and second arguments
+ * of the raw clone() system call is reversed. */
+ return (int) syscall(__NR_clone, child_stack, flags);
+#else
+ return (int) syscall(__NR_clone, flags, child_stack);
+#endif
+}
+
+/* ======================================================================= */
+
+static inline pid_t raw_getpid(void) {
+#if defined(__alpha__)
+ return (pid_t) syscall(__NR_getxpid);
+#else
+ return (pid_t) syscall(__NR_getpid);
+#endif
+}
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_RENAMEAT2
+# ifndef __NR_renameat2
+# if defined __x86_64__
+# define __NR_renameat2 316
+# elif defined __arm__
+# define __NR_renameat2 382
+# elif defined _MIPS_SIM
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_renameat2 4351
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_renameat2 6315
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_renameat2 5311
+# endif
+# elif defined __i386__
+# define __NR_renameat2 353
+# else
+# warning "__NR_renameat2 unknown for your architecture"
+# endif
+# endif
+
+static inline int renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) {
+# ifdef __NR_renameat2
+ return syscall(__NR_renameat2, oldfd, oldname, newfd, newname, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_KCMP
+static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
+# ifdef __NR_kcmp
+ return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_KEYCTL
+static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) {
+# ifdef __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) {
+# ifdef __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) {
+# ifdef __NR_request_key
+ return syscall(__NR_request_key, type, description, callout_info, destringid);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
+
+/* ======================================================================= */
+
+#if !HAVE_DECL_COPY_FILE_RANGE
+# ifndef __NR_copy_file_range
+# if defined(__x86_64__)
+# define __NR_copy_file_range 326
+# elif defined(__i386__)
+# define __NR_copy_file_range 377
+# elif defined __s390__
+# define __NR_copy_file_range 375
+# elif defined __arm__
+# define __NR_copy_file_range 391
+# elif defined __aarch64__
+# define __NR_copy_file_range 285
+# else
+# warning "__NR_copy_file_range not defined for your architecture"
+# endif
+# endif
+
+static inline ssize_t copy_file_range(int fd_in, loff_t *off_in,
+ int fd_out, loff_t *off_out,
+ size_t len,
+ unsigned int flags) {
+# ifdef __NR_copy_file_range
+ return syscall(__NR_copy_file_range, fd_in, off_in, fd_out, off_out, len, flags);
+# else
+ errno = ENOSYS;
+ return -1;
+# endif
+}
+#endif
diff --git a/src/libbasic/mount-util.c b/src/libbasic/mount-util.c
index 33f2ee96d8..ba698959b7 100644
--- a/src/libbasic/mount-util.c
+++ b/src/libbasic/mount-util.c
@@ -47,7 +47,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id
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);
+ subfd = openat(fd, filename, O_CLOEXEC|O_PATH);
if (subfd < 0)
return -errno;
@@ -230,7 +230,7 @@ int path_is_mount_point(const char *t, int flags) {
if (!parent)
return -ENOMEM;
- fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH);
+ fd = openat(AT_FDCWD, parent, O_DIRECTORY|O_CLOEXEC|O_PATH);
if (fd < 0)
return -errno;
@@ -498,7 +498,9 @@ bool fstype_is_network(const char *fstype) {
"nfs4\0"
"gfs\0"
"gfs2\0"
- "glusterfs\0";
+ "glusterfs\0"
+ "pvfs2\0" /* OrangeFS */
+ ;
const char *x;
diff --git a/src/libbasic/nss-util.h b/src/libbasic/nss-util.h
index df565a3593..bf7c4854fc 100644
--- a/src/libbasic/nss-util.h
+++ b/src/libbasic/nss-util.h
@@ -154,3 +154,46 @@ enum nss_status _nss_##module##_getgrgid_r( \
struct group *gr, \
char *buffer, size_t buflen, \
int *errnop) _public_
+
+typedef enum nss_status (*_nss_gethostbyname4_r_t)(
+ const char *name,
+ struct gaih_addrtuple **pat,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp);
+
+typedef enum nss_status (*_nss_gethostbyname3_r_t)(
+ const char *name,
+ int af,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp,
+ char **canonp);
+
+typedef enum nss_status (*_nss_gethostbyname2_r_t)(
+ const char *name,
+ int af,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop);
+
+typedef enum nss_status (*_nss_gethostbyname_r_t)(
+ const char *name,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop);
+
+typedef enum nss_status (*_nss_gethostbyaddr2_r_t)(
+ const void* addr, socklen_t len,
+ int af,
+ struct hostent *result,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop,
+ int32_t *ttlp);
+typedef enum nss_status (*_nss_gethostbyaddr_r_t)(
+ const void* addr, socklen_t len,
+ int af,
+ struct hostent *host,
+ char *buffer, size_t buflen,
+ int *errnop, int *h_errnop);
diff --git a/src/libbasic/parse-util.c b/src/libbasic/parse-util.c
index a3cb81b040..6c11b605a9 100644
--- a/src/libbasic/parse-util.c
+++ b/src/libbasic/parse-util.c
@@ -505,7 +505,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) {
s = *p;
/* accept any number of digits, strtoull is limted to 19 */
- for(i=0; i < digits; i++,s++) {
+ for (i=0; i < digits; i++,s++) {
if (*s < '0' || *s > '9') {
if (i == 0)
return -EINVAL;
diff --git a/src/libbasic/parse-util.h b/src/libbasic/parse-util.h
index d8dc26a36e..7dc579a159 100644
--- a/src/libbasic/parse-util.h
+++ b/src/libbasic/parse-util.h
@@ -90,6 +90,18 @@ static inline int safe_atoli(const char *s, long int *ret_u) {
}
#endif
+#if SIZE_MAX == UINT_MAX
+static inline int safe_atozu(const char *s, size_t *ret_u) {
+ assert_cc(sizeof(size_t) == sizeof(unsigned));
+ return safe_atou(s, (unsigned *) ret_u);
+}
+#else
+static inline int safe_atozu(const char *s, size_t *ret_u) {
+ assert_cc(sizeof(size_t) == sizeof(long unsigned));
+ return safe_atolu(s, ret_u);
+}
+#endif
+
int safe_atod(const char *s, double *ret_d);
int parse_fractional_part_u(const char **s, size_t digits, unsigned *res);
diff --git a/src/libbasic/path-util.c b/src/libbasic/path-util.c
index 822c09bfba..b2fa81a294 100644
--- a/src/libbasic/path-util.c
+++ b/src/libbasic/path-util.c
@@ -569,10 +569,10 @@ static int binary_is_good(const char *binary) {
if (r < 0)
return r;
- return !path_equal(d, "true") &&
- !path_equal(d, "/bin/true") &&
- !path_equal(d, "/usr/bin/true") &&
- !path_equal(d, "/dev/null");
+ return !PATH_IN_SET(d, "true"
+ "/bin/true",
+ "/usr/bin/true",
+ "/dev/null");
}
int fsck_exists(const char *fstype) {
@@ -756,34 +756,53 @@ char *file_in_same_dir(const char *path, const char *filename) {
return ret;
}
-bool hidden_file_allow_backup(const char *filename) {
- assert(filename);
-
- return
- filename[0] == '.' ||
- streq(filename, "lost+found") ||
- streq(filename, "aquota.user") ||
- streq(filename, "aquota.group") ||
- endswith(filename, ".rpmnew") ||
- endswith(filename, ".rpmsave") ||
- endswith(filename, ".rpmorig") ||
- endswith(filename, ".dpkg-old") ||
- endswith(filename, ".dpkg-new") ||
- endswith(filename, ".dpkg-tmp") ||
- endswith(filename, ".dpkg-dist") ||
- endswith(filename, ".dpkg-bak") ||
- endswith(filename, ".dpkg-backup") ||
- endswith(filename, ".dpkg-remove") ||
- endswith(filename, ".swp");
-}
+bool hidden_or_backup_file(const char *filename) {
+ const char *p;
-bool hidden_file(const char *filename) {
assert(filename);
- if (endswith(filename, "~"))
+ if (filename[0] == '.' ||
+ streq(filename, "lost+found") ||
+ streq(filename, "aquota.user") ||
+ streq(filename, "aquota.group") ||
+ endswith(filename, "~"))
return true;
- return hidden_file_allow_backup(filename);
+ p = strrchr(filename, '.');
+ if (!p)
+ return false;
+
+ /* Please, let's not add more entries to the list below. If external projects think it's a good idea to come up
+ * with always new suffixes and that everybody else should just adjust to that, then it really should be on
+ * them. Hence, in future, let's not add any more entries. Instead, let's ask those packages to instead adopt
+ * one of the generic suffixes/prefixes for hidden files or backups, possibly augmented with an additional
+ * string. Specifically: there's now:
+ *
+ * The generic suffixes "~" and ".bak" for backup files
+ * The generic prefix "." for hidden files
+ *
+ * Thus, if a new package manager "foopkg" wants its own set of ".foopkg-new", ".foopkg-old", ".foopkg-dist"
+ * or so registered, let's refuse that and ask them to use ".foopkg.new", ".foopkg.old" or ".foopkg~" instead.
+ */
+
+ return STR_IN_SET(p + 1,
+ "rpmnew",
+ "rpmsave",
+ "rpmorig",
+ "dpkg-old",
+ "dpkg-new",
+ "dpkg-tmp",
+ "dpkg-dist",
+ "dpkg-bak",
+ "dpkg-backup",
+ "dpkg-remove",
+ "ucf-new",
+ "ucf-old",
+ "ucf-dist",
+ "swp",
+ "bak",
+ "old",
+ "new");
}
bool is_device_path(const char *path) {
diff --git a/src/libbasic/path-util.h b/src/libbasic/path-util.h
index 2c2f87a9f2..a27c13fcc3 100644
--- a/src/libbasic/path-util.h
+++ b/src/libbasic/path-util.h
@@ -48,6 +48,23 @@ bool path_equal(const char *a, const char *b) _pure_;
bool path_equal_or_files_same(const char *a, const char *b);
char* path_join(const char *root, const char *path, const char *rest);
+static inline bool path_equal_ptr(const char *a, const char *b) {
+ return !!a == !!b && (!a || path_equal(a, b));
+}
+
+/* Note: the search terminates on the first NULL item. */
+#define PATH_IN_SET(p, ...) \
+ ({ \
+ char **s; \
+ bool _found = false; \
+ STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__)) \
+ if (path_equal(p, *s)) { \
+ _found = true; \
+ break; \
+ } \
+ _found; \
+ })
+
int path_strv_make_absolute_cwd(char **l);
char** path_strv_resolve(char **l, const char *prefix);
char** path_strv_resolve_uniq(char **l, const char *prefix);
@@ -105,7 +122,6 @@ bool path_is_safe(const char *p) _pure_;
char *file_in_same_dir(const char *path, const char *filename);
-bool hidden_file_allow_backup(const char *filename);
-bool hidden_file(const char *filename) _pure_;
+bool hidden_or_backup_file(const char *filename) _pure_;
bool is_device_path(const char *path);
diff --git a/src/libbasic/process-util.c b/src/libbasic/process-util.c
index 189ef9ab60..1ad8816206 100644
--- a/src/libbasic/process-util.c
+++ b/src/libbasic/process-util.c
@@ -38,6 +38,7 @@
#endif
#include "alloc-util.h"
+#include "architecture.h"
#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
@@ -205,7 +206,7 @@ void rename_process(const char name[8]) {
* "systemd"). If you pass a longer string it will be
* truncated */
- prctl(PR_SET_NAME, name);
+ (void) prctl(PR_SET_NAME, name);
if (program_invocation_name)
strncpy(program_invocation_name, name, strlen(program_invocation_name));
@@ -527,14 +528,20 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod
return -EPROTO;
}
-void sigkill_wait(pid_t *pid) {
+void sigkill_wait(pid_t pid) {
+ assert(pid > 1);
+
+ if (kill(pid, SIGKILL) > 0)
+ (void) wait_for_terminate(pid, NULL);
+}
+
+void sigkill_waitp(pid_t *pid) {
if (!pid)
return;
if (*pid <= 1)
return;
- if (kill(*pid, SIGKILL) > 0)
- (void) wait_for_terminate(*pid, NULL);
+ sigkill_wait(*pid);
}
int kill_and_sigcont(pid_t pid, int sig) {
@@ -660,6 +667,8 @@ bool is_main_thread(void) {
noreturn void freeze(void) {
+ log_close();
+
/* Make sure nobody waits for us on a socket anymore */
close_all_fds(NULL, 0);
@@ -674,75 +683,43 @@ bool oom_score_adjust_is_valid(int oa) {
}
unsigned long personality_from_string(const char *p) {
+ int architecture;
- /* 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 (!p)
+ return PERSONALITY_INVALID;
- if (streq(p, "x86-64"))
- return PER_LINUX;
+ /* Parse a personality specifier. We use 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. */
-#elif defined(__i386__)
+ architecture = architecture_from_string(p);
+ if (architecture < 0)
+ return PERSONALITY_INVALID;
- if (streq(p, "x86"))
+ if (architecture == native_architecture())
return PER_LINUX;
-
-#elif defined(__s390x__)
-
- if (streq(p, "s390"))
+#ifdef SECONDARY_ARCHITECTURE
+ if (architecture == SECONDARY_ARCHITECTURE)
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__)
+ int architecture = _ARCHITECTURE_INVALID;
if (p == PER_LINUX)
- return "s390";
-
+ architecture = native_architecture();
+#ifdef SECONDARY_ARCHITECTURE
+ else if (p == PER_LINUX32)
+ architecture = SECONDARY_ARCHITECTURE;
#endif
- return NULL;
+ if (architecture < 0)
+ return NULL;
+
+ return architecture_to_string(architecture);
}
void valgrind_summary_hack(void) {
@@ -762,6 +739,18 @@ void valgrind_summary_hack(void) {
#endif
}
+int pid_compare_func(const void *a, const void *b) {
+ const pid_t *p = a, *q = b;
+
+ /* Suitable for usage in qsort() */
+
+ if (*p < *q)
+ return -1;
+ if (*p > *q)
+ return 1;
+ return 0;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
diff --git a/src/libbasic/process-util.h b/src/libbasic/process-util.h
index f5d193e762..9f75088796 100644
--- a/src/libbasic/process-util.h
+++ b/src/libbasic/process-util.h
@@ -58,8 +58,8 @@ int get_process_ppid(pid_t pid, pid_t *ppid);
int wait_for_terminate(pid_t pid, siginfo_t *status);
int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code);
-void sigkill_wait(pid_t *pid);
-#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait)
+void sigkill_wait(pid_t pid);
+void sigkill_waitp(pid_t *pid);
int kill_and_sigcont(pid_t pid, int sig);
@@ -101,3 +101,5 @@ int sched_policy_from_string(const char *s);
#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
void valgrind_summary_hack(void);
+
+int pid_compare_func(const void *a, const void *b);
diff --git a/src/libbasic/rlimit-util.c b/src/libbasic/rlimit-util.c
index 7540b43215..ee063720ed 100644
--- a/src/libbasic/rlimit-util.c
+++ b/src/libbasic/rlimit-util.c
@@ -153,6 +153,56 @@ static int rlimit_parse_usec(const char *val, rlim_t *ret) {
return 0;
}
+static int rlimit_parse_nice(const char *val, rlim_t *ret) {
+ uint64_t rl;
+ int r;
+
+ /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the
+ * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is
+ * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight
+ * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we
+ * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0.
+ *
+ * Yeah, Linux is quality engineering sometimes... */
+
+ if (val[0] == '+') {
+
+ /* Prefixed with "+": Parse as positive user-friendly nice value */
+ r = safe_atou64(val + 1, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl >= PRIO_MAX)
+ return -ERANGE;
+
+ rl = 20 - rl;
+
+ } else if (val[0] == '-') {
+
+ /* Prefixed with "-": Parse as negative user-friendly nice value */
+ r = safe_atou64(val + 1, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl > (uint64_t) (-PRIO_MIN))
+ return -ERANGE;
+
+ rl = 20 + rl;
+ } else {
+
+ /* Not prefixed: parse as raw resource limit value */
+ r = safe_atou64(val, &rl);
+ if (r < 0)
+ return r;
+
+ if (rl > (uint64_t) (20 - PRIO_MIN))
+ return -ERANGE;
+ }
+
+ *ret = (rlim_t) rl;
+ return 0;
+}
+
static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = {
[RLIMIT_CPU] = rlimit_parse_sec,
[RLIMIT_FSIZE] = rlimit_parse_size,
@@ -167,7 +217,7 @@ static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret
[RLIMIT_LOCKS] = rlimit_parse_u64,
[RLIMIT_SIGPENDING] = rlimit_parse_u64,
[RLIMIT_MSGQUEUE] = rlimit_parse_size,
- [RLIMIT_NICE] = rlimit_parse_u64,
+ [RLIMIT_NICE] = rlimit_parse_nice,
[RLIMIT_RTPRIO] = rlimit_parse_u64,
[RLIMIT_RTTIME] = rlimit_parse_usec,
};
diff --git a/src/libbasic/rm-rf.h b/src/libbasic/rm-rf.h
index 6d03268919..f693a5bb7c 100644
--- a/src/libbasic/rm-rf.h
+++ b/src/libbasic/rm-rf.h
@@ -30,3 +30,12 @@ typedef enum RemoveFlags {
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev);
int rm_rf(const char *path, RemoveFlags flags);
+
+/* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */
+static inline void rm_rf_physical_and_free(char *p) {
+ if (!p)
+ return;
+ (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
+ free(p);
+}
+DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_physical_and_free);
diff --git a/src/libbasic/selinux-util.c b/src/libbasic/selinux-util.c
index 6c63b9d652..10c2f39369 100644
--- a/src/libbasic/selinux-util.c
+++ b/src/libbasic/selinux-util.c
@@ -80,31 +80,23 @@ void mac_selinux_retest(void) {
#endif
}
-int mac_selinux_init(const char *prefix) {
+int mac_selinux_init(void) {
int r = 0;
#ifdef HAVE_SELINUX
usec_t before_timestamp, after_timestamp;
struct mallinfo before_mallinfo, after_mallinfo;
- if (!mac_selinux_use())
+ if (label_hnd)
return 0;
- if (label_hnd)
+ if (!mac_selinux_use())
return 0;
before_mallinfo = mallinfo();
before_timestamp = now(CLOCK_MONOTONIC);
- if (prefix) {
- struct selinux_opt options[] = {
- { .type = SELABEL_OPT_SUBSET, .value = prefix },
- };
-
- label_hnd = selabel_open(SELABEL_CTX_FILE, options, ELEMENTSOF(options));
- } else
- label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
-
+ label_hnd = selabel_open(SELABEL_CTX_FILE, NULL, 0);
if (!label_hnd) {
log_enforcing("Failed to initialize SELinux context: %m");
r = security_getenforce() == 1 ? -errno : 0;
@@ -160,7 +152,7 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {
return 0;
if (r >= 0) {
- r = lsetfilecon(path, fcon);
+ r = lsetfilecon_raw(path, fcon);
/* If the FS doesn't support labels, then exit without warning */
if (r < 0 && errno == EOPNOTSUPP)
@@ -225,7 +217,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {
return -errno;
sclass = string_to_security_class("process");
- r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
+ r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label);
if (r < 0)
return -errno;
#endif
@@ -270,7 +262,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
if (r < 0)
return -errno;
- r = getpeercon(socket_fd, &peercon);
+ r = getpeercon_raw(socket_fd, &peercon);
if (r < 0)
return -errno;
@@ -304,7 +296,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
return -ENOMEM;
sclass = string_to_security_class("process");
- r = security_compute_create(mycon, fcon, sclass, (security_context_t *) label);
+ r = security_compute_create_raw(mycon, fcon, sclass, (security_context_t *) label);
if (r < 0)
return -errno;
#endif
@@ -358,7 +350,7 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
log_enforcing("Failed to determine SELinux security context for %s: %m", path);
} else {
- if (setfscreatecon(filecon) >= 0)
+ if (setfscreatecon_raw(filecon) >= 0)
return 0; /* Success! */
log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path);
@@ -379,7 +371,7 @@ void mac_selinux_create_file_clear(void) {
if (!mac_selinux_use())
return;
- setfscreatecon(NULL);
+ setfscreatecon_raw(NULL);
#endif
}
@@ -410,7 +402,7 @@ void mac_selinux_create_socket_clear(void) {
if (!mac_selinux_use())
return;
- setsockcreatecon(NULL);
+ setsockcreatecon_raw(NULL);
#endif
}
@@ -469,7 +461,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
return -errno;
} else {
- if (setfscreatecon(fcon) < 0) {
+ if (setfscreatecon_raw(fcon) < 0) {
log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path);
if (security_getenforce() > 0)
return -errno;
@@ -480,7 +472,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
r = bind(fd, addr, addrlen) < 0 ? -errno : 0;
if (context_changed)
- setfscreatecon(NULL);
+ setfscreatecon_raw(NULL);
return r;
diff --git a/src/libbasic/selinux-util.h b/src/libbasic/selinux-util.h
index 27e8edb41b..ce6bc8e44c 100644
--- a/src/libbasic/selinux-util.h
+++ b/src/libbasic/selinux-util.h
@@ -29,7 +29,7 @@ bool mac_selinux_use(void);
bool mac_selinux_have(void);
void mac_selinux_retest(void);
-int mac_selinux_init(const char *prefix);
+int mac_selinux_init(void);
void mac_selinux_finish(void);
int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs);
diff --git a/src/libbasic/set.h b/src/libbasic/set.h
index 2bff5062da..e0d9dd001c 100644
--- a/src/libbasic/set.h
+++ b/src/libbasic/set.h
@@ -126,6 +126,9 @@ int set_put_strdupv(Set *s, char **l);
#define SET_FOREACH(e, s, i) \
for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); )
+#define SET_FOREACH_MOVE(e, d, s) \
+ for (; ({ e = set_first(s); assert_se(!e || set_move_one(d, s, e) >= 0); e; }); )
+
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free);
DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free);
diff --git a/src/libbasic/sigbus.h b/src/libbasic/sigbus.h
index cce9eb201b..980243d9ce 100644
--- a/src/libbasic/sigbus.h
+++ b/src/libbasic/sigbus.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
void sigbus_install(void);
void sigbus_reset(void);
diff --git a/src/libbasic/signal-util.c b/src/libbasic/signal-util.c
index e3047b209b..280b5c3251 100644
--- a/src/libbasic/signal-util.c
+++ b/src/libbasic/signal-util.c
@@ -255,7 +255,7 @@ int signal_from_string(const char *s) {
}
if (safe_atou(s, &u) >= 0) {
signo = (int) u + offset;
- if (signo > 0 && signo < _NSIG)
+ if (SIGNAL_VALID(signo))
return signo;
}
return -EINVAL;
diff --git a/src/libbasic/signal-util.h b/src/libbasic/signal-util.h
index 72b10e8712..dfd6eb564d 100644
--- a/src/libbasic/signal-util.h
+++ b/src/libbasic/signal-util.h
@@ -44,9 +44,13 @@ static inline void block_signals_reset(sigset_t *ss) {
assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0);
}
-#define BLOCK_SIGNALS(...) \
- _cleanup_(block_signals_reset) sigset_t _saved_sigset = ({ \
- sigset_t t; \
+#define BLOCK_SIGNALS(...) \
+ _cleanup_(block_signals_reset) _unused_ sigset_t _saved_sigset = ({ \
+ sigset_t t; \
assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \
- t; \
+ t; \
})
+
+static inline bool SIGNAL_VALID(int signo) {
+ return signo > 0 && signo < _NSIG;
+}
diff --git a/src/libbasic/socket-label.c b/src/libbasic/socket-label.c
index 35e9573aa4..6d1dc83874 100644
--- a/src/libbasic/socket-label.c
+++ b/src/libbasic/socket-label.c
@@ -23,7 +23,6 @@
#include <stddef.h>
#include <string.h>
#include <sys/socket.h>
-#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
@@ -35,6 +34,7 @@
#include "mkdir.h"
#include "selinux-util.h"
#include "socket-util.h"
+#include "umask-util.h"
int socket_address_listen(
const SocketAddress *a,
@@ -112,28 +112,24 @@ int socket_address_listen(
return -errno;
if (socket_address_family(a) == AF_UNIX && a->sockaddr.un.sun_path[0] != 0) {
- mode_t old_mask;
-
/* Create parents */
- mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
+ (void) mkdir_parents_label(a->sockaddr.un.sun_path, directory_mode);
/* Enforce the right access mode for the socket */
- old_mask = umask(~ socket_mode);
-
- r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
-
- if (r < 0 && errno == EADDRINUSE) {
- /* Unlink and try again */
- unlink(a->sockaddr.un.sun_path);
- r = bind(fd, &a->sockaddr.sa, a->size);
+ RUN_WITH_UMASK(~socket_mode) {
+ r = mac_selinux_bind(fd, &a->sockaddr.sa, a->size);
+ if (r == -EADDRINUSE) {
+ /* Unlink and try again */
+ unlink(a->sockaddr.un.sun_path);
+ if (bind(fd, &a->sockaddr.sa, a->size) < 0)
+ return -errno;
+ } else if (r < 0)
+ return r;
}
-
- umask(old_mask);
- } else
- r = bind(fd, &a->sockaddr.sa, a->size);
-
- if (r < 0)
- return -errno;
+ } else {
+ if (bind(fd, &a->sockaddr.sa, a->size) < 0)
+ return -errno;
+ }
if (socket_address_can_accept(a))
if (listen(fd, backlog) < 0)
diff --git a/src/libbasic/socket-util.c b/src/libbasic/socket-util.c
index 58512686e3..c8769a54f4 100644
--- a/src/libbasic/socket-util.c
+++ b/src/libbasic/socket-util.c
@@ -23,6 +23,7 @@
#include <net/if.h>
#include <netdb.h>
#include <netinet/ip.h>
+#include <poll.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -42,7 +43,9 @@
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "user-util.h"
+#include "utf8.h"
#include "util.h"
int socket_address_parse(SocketAddress *a, const char *s) {
@@ -794,6 +797,42 @@ static const char* const ip_tos_table[] = {
DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
+bool ifname_valid(const char *p) {
+ bool numeric = true;
+
+ /* Checks whether a network interface name is valid. This is inspired by dev_valid_name() in the kernel sources
+ * but slightly stricter, as we only allow non-control, non-space ASCII characters in the interface name. We
+ * also don't permit names that only container numbers, to avoid confusion with numeric interface indexes. */
+
+ if (isempty(p))
+ return false;
+
+ if (strlen(p) >= IFNAMSIZ)
+ return false;
+
+ if (STR_IN_SET(p, ".", ".."))
+ return false;
+
+ while (*p) {
+ if ((unsigned char) *p >= 127U)
+ return false;
+
+ if ((unsigned char) *p <= 32U)
+ return false;
+
+ if (*p == ':' || *p == '/')
+ return false;
+
+ numeric = numeric && (*p >= '0' && *p <= '9');
+ p++;
+ }
+
+ if (numeric)
+ return false;
+
+ return true;
+}
+
int getpeercred(int fd, struct ucred *ucred) {
socklen_t n = sizeof(struct ucred);
struct ucred u;
@@ -942,7 +981,7 @@ ssize_t next_datagram_size_fd(int fd) {
int k;
/* This is a bit like FIONREAD/SIOCINQ, however a bit more powerful. The difference being: recv(MSG_PEEK) will
- * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD dosn't
+ * actually cause the next datagram in the queue to be validated regarding checksums, which FIONREAD doesn't
* do. This difference is actually of major importance as we need to be sure that the size returned here
* actually matches what we will read with recvmsg() next, as otherwise we might end up allocating a buffer of
* the wrong size. */
@@ -970,3 +1009,42 @@ fallback:
return (ssize_t) k;
}
+
+int flush_accept(int fd) {
+
+ struct pollfd pollfd = {
+ .fd = fd,
+ .events = POLLIN,
+ };
+ int r;
+
+
+ /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */
+
+ for (;;) {
+ int cfd;
+
+ r = poll(&pollfd, 1, 0);
+ if (r < 0) {
+ if (errno == EINTR)
+ continue;
+
+ return -errno;
+
+ } else if (r == 0)
+ return 0;
+
+ cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
+ if (cfd < 0) {
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EAGAIN)
+ return 0;
+
+ return -errno;
+ }
+
+ close(cfd);
+ }
+}
diff --git a/src/libbasic/socket-util.h b/src/libbasic/socket-util.h
index d17a2f35f8..e9230e4a9f 100644
--- a/src/libbasic/socket-util.h
+++ b/src/libbasic/socket-util.h
@@ -123,6 +123,8 @@ int fd_inc_rcvbuf(int fd, size_t n);
int ip_tos_to_string_alloc(int i, char **s);
int ip_tos_from_string(const char *s);
+bool ifname_valid(const char *p);
+
int getpeercred(int fd, struct ucred *ucred);
int getpeersec(int fd, char **ret);
@@ -135,5 +137,18 @@ int receive_one_fd(int transport_fd, int flags);
ssize_t next_datagram_size_fd(int fd);
+int flush_accept(int fd);
+
#define CMSG_FOREACH(cmsg, mh) \
for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg)))
+
+/* Covers only file system and abstract AF_UNIX socket addresses, but not unnamed socket addresses. */
+#define SOCKADDR_UN_LEN(sa) \
+ ({ \
+ const struct sockaddr_un *_sa = &(sa); \
+ assert(_sa->sun_family == AF_UNIX); \
+ offsetof(struct sockaddr_un, sun_path) + \
+ (_sa->sun_path[0] == 0 ? \
+ 1 + strnlen(_sa->sun_path+1, sizeof(_sa->sun_path)-1) : \
+ strnlen(_sa->sun_path, sizeof(_sa->sun_path))); \
+ })
diff --git a/src/libbasic/special.h b/src/libbasic/special.h
index 2fd03d9f75..084d3dfa23 100644
--- a/src/libbasic/special.h
+++ b/src/libbasic/special.h
@@ -52,6 +52,7 @@
#define SPECIAL_LOCAL_FS_TARGET "local-fs.target"
#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target"
#define SPECIAL_INITRD_FS_TARGET "initrd-fs.target"
+#define SPECIAL_INITRD_ROOT_DEVICE_TARGET "initrd-root-device.target"
#define SPECIAL_INITRD_ROOT_FS_TARGET "initrd-root-fs.target"
#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */
#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
diff --git a/src/libbasic/stdio-util.h b/src/libbasic/stdio-util.h
index 0a675571ff..bd1144b4c9 100644
--- a/src/libbasic/stdio-util.h
+++ b/src/libbasic/stdio-util.h
@@ -73,4 +73,4 @@ do { \
assert_not_reached("Unknown format string argument."); \
} \
} \
-} while(false)
+} while (false)
diff --git a/src/libbasic/strbuf.c b/src/libbasic/strbuf.c
index 77220c0251..4bef87d3c2 100644
--- a/src/libbasic/strbuf.c
+++ b/src/libbasic/strbuf.c
@@ -121,7 +121,7 @@ static void bubbleinsert(struct strbuf_node *node,
sizeof(struct strbuf_child_entry) * (node->children_count - left));
node->children[left] = new;
- node->children_count ++;
+ node->children_count++;
}
/* add string, return the index/offset into the buffer */
@@ -156,8 +156,13 @@ ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len) {
return off;
}
- /* lookup child node */
c = s[len - 1 - depth];
+
+ /* bsearch is not allowed on a NULL sequence */
+ if (node->children_count == 0)
+ break;
+
+ /* lookup child node */
search.c = c;
child = bsearch(&search, node->children, node->children_count,
sizeof(struct strbuf_child_entry),
diff --git a/src/libbasic/string-table.h b/src/libbasic/string-table.h
index b180488fe8..d88625fca7 100644
--- a/src/libbasic/string-table.h
+++ b/src/libbasic/string-table.h
@@ -56,26 +56,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
}
-#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
- _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
- _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
- struct __useless_struct_to_allow_trailing_semicolon__
-
-#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \
- _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
- _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
- struct __useless_struct_to_allow_trailing_semicolon__
-
-#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
-#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
-
-#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
-
-/* For string conversions where numbers are also acceptable */
-#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
- int name##_to_string_alloc(type i, char **str) { \
+#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,scope) \
+ scope int name##_to_string_alloc(type i, char **str) { \
char *s; \
if (i < 0 || i > max) \
return -ERANGE; \
@@ -89,7 +71,9 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
} \
*str = s; \
return 0; \
- } \
+ }
+
+#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
type name##_from_string(const char *s) { \
type i; \
unsigned u = 0; \
@@ -102,4 +86,32 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
return (type) u; \
return (type) -1; \
} \
+
+
+#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static)
+
+#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,)
+
+/* For string conversions where numbers are also acceptable */
+#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \
+ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,) \
struct __useless_struct_to_allow_trailing_semicolon__
+
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max) \
+ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(name,type,max,static)
+#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max) \
+ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,static)
diff --git a/src/libbasic/string-util.c b/src/libbasic/string-util.c
index 0bde55f9d5..293a15f9c0 100644
--- a/src/libbasic/string-util.c
+++ b/src/libbasic/string-util.c
@@ -477,7 +477,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne
}
if (k > x) /* last character was wide and went over quota */
- x ++;
+ x++;
for (j = s + old_length; k < new_length && j > i; ) {
char32_t c;
diff --git a/src/libbasic/string-util.h b/src/libbasic/string-util.h
index ad0c813761..139cc8c91b 100644
--- a/src/libbasic/string-util.h
+++ b/src/libbasic/string-util.h
@@ -37,6 +37,7 @@
#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS
#define ALPHANUMERICAL LETTERS DIGITS
+#define HEXDIGITS DIGITS "abcdefABCDEF"
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
diff --git a/src/libbasic/strv.c b/src/libbasic/strv.c
index b5d4d8191b..97a96e5762 100644
--- a/src/libbasic/strv.c
+++ b/src/libbasic/strv.c
@@ -371,7 +371,7 @@ char *strv_join(char **l, const char *separator) {
n = 0;
STRV_FOREACH(s, l) {
- if (n != 0)
+ if (s != l)
n += k;
n += strlen(*s);
}
@@ -382,7 +382,7 @@ char *strv_join(char **l, const char *separator) {
e = r;
STRV_FOREACH(s, l) {
- if (e != r)
+ if (s != l)
e = stpcpy(e, separator);
e = stpcpy(e, *s);
@@ -558,6 +558,42 @@ int strv_extend(char ***l, const char *value) {
return strv_consume(l, v);
}
+int strv_extend_front(char ***l, const char *value) {
+ size_t n, m;
+ char *v, **c;
+
+ assert(l);
+
+ /* Like strv_extend(), but prepends rather than appends the new entry */
+
+ if (!value)
+ return 0;
+
+ n = strv_length(*l);
+
+ /* Increase and overflow check. */
+ m = n + 2;
+ if (m < n)
+ return -ENOMEM;
+
+ v = strdup(value);
+ if (!v)
+ return -ENOMEM;
+
+ c = realloc_multiply(*l, sizeof(char*), m);
+ if (!c) {
+ free(v);
+ return -ENOMEM;
+ }
+
+ memmove(c+1, c, n * sizeof(char*));
+ c[0] = v;
+ c[n+1] = NULL;
+
+ *l = c;
+ return 0;
+}
+
char **strv_uniq(char **l) {
char **i;
diff --git a/src/libbasic/strv.h b/src/libbasic/strv.h
index 7bfa54408d..f61bbb5386 100644
--- a/src/libbasic/strv.h
+++ b/src/libbasic/strv.h
@@ -50,6 +50,7 @@ int strv_extend_strv(char ***a, char **b, bool filter_duplicates);
int strv_extend_strv_concat(char ***a, char **b, const char *suffix);
int strv_extend(char ***l, const char *value);
int strv_extendf(char ***l, const char *format, ...) _printf_(2,0);
+int strv_extend_front(char ***l, const char *value);
int strv_push(char ***l, char *value);
int strv_push_pair(char ***l, char *a, char *b);
int strv_push_prepend(char ***l, char *value);
diff --git a/src/libbasic/terminal-util.c b/src/libbasic/terminal-util.c
index 0a9d2bbdef..9521b79daa 100644
--- a/src/libbasic/terminal-util.c
+++ b/src/libbasic/terminal-util.c
@@ -1135,14 +1135,19 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
}
bool colors_enabled(void) {
- const char *colors;
+ static int enabled = -1;
- colors = getenv("SYSTEMD_COLORS");
- if (!colors) {
- if (streq_ptr(getenv("TERM"), "dumb"))
- return false;
- return on_tty();
+ if (_unlikely_(enabled < 0)) {
+ const char *colors;
+
+ colors = getenv("SYSTEMD_COLORS");
+ if (colors)
+ enabled = parse_boolean(colors) != 0;
+ else if (streq_ptr(getenv("TERM"), "dumb"))
+ enabled = false;
+ else
+ enabled = on_tty();
}
- return parse_boolean(colors) != 0;
+ return enabled;
}
diff --git a/src/libbasic/time-util.c b/src/libbasic/time-util.c
index 3973850b44..edd9179cb8 100644
--- a/src/libbasic/time-util.c
+++ b/src/libbasic/time-util.c
@@ -42,10 +42,30 @@
static nsec_t timespec_load_nsec(const struct timespec *ts);
+static clockid_t map_clock_id(clockid_t c) {
+
+ /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will
+ * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is
+ * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on
+ * those archs. */
+
+ switch (c) {
+
+ case CLOCK_BOOTTIME_ALARM:
+ return CLOCK_BOOTTIME;
+
+ case CLOCK_REALTIME_ALARM:
+ return CLOCK_REALTIME;
+
+ default:
+ return c;
+ }
+}
+
usec_t now(clockid_t clock_id) {
struct timespec ts;
- assert_se(clock_gettime(clock_id, &ts) == 0);
+ assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
return timespec_load(&ts);
}
@@ -53,7 +73,7 @@ usec_t now(clockid_t clock_id) {
nsec_t now_nsec(clockid_t clock_id) {
struct timespec ts;
- assert_se(clock_gettime(clock_id, &ts) == 0);
+ assert_se(clock_gettime(map_clock_id(clock_id), &ts) == 0);
return timespec_load_nsec(&ts);
}
@@ -119,8 +139,7 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us
usec_t timespec_load(const struct timespec *ts) {
assert(ts);
- if (ts->tv_sec == (time_t) -1 &&
- ts->tv_nsec == (long) -1)
+ if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
return USEC_INFINITY;
if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC)
@@ -134,13 +153,13 @@ usec_t timespec_load(const struct timespec *ts) {
static nsec_t timespec_load_nsec(const struct timespec *ts) {
assert(ts);
- if (ts->tv_sec == (time_t) -1 &&
- ts->tv_nsec == (long) -1)
+ if (ts->tv_sec == (time_t) -1 && ts->tv_nsec == (long) -1)
return NSEC_INFINITY;
- return
- (nsec_t) ts->tv_sec * NSEC_PER_SEC +
- (nsec_t) ts->tv_nsec;
+ if ((nsec_t) ts->tv_sec >= (UINT64_MAX - ts->tv_nsec) / NSEC_PER_SEC)
+ return NSEC_INFINITY;
+
+ return (nsec_t) ts->tv_sec * NSEC_PER_SEC + (nsec_t) ts->tv_nsec;
}
struct timespec *timespec_store(struct timespec *ts, usec_t u) {
@@ -429,7 +448,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
assert(t);
if (sscanf(value, "%llu %llu", &a, &b) != 2) {
- log_debug("Failed to parse finish timestamp value %s.", value);
+ log_debug("Failed to parse dual timestamp value \"%s\": %m", value);
return -EINVAL;
}
@@ -439,6 +458,18 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t) {
return 0;
}
+int timestamp_deserialize(const char *value, usec_t *timestamp) {
+ int r;
+
+ assert(value);
+
+ r = safe_atou64(value, timestamp);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to parse timestamp value \"%s\": %m", value);
+
+ return r;
+}
+
int parse_timestamp(const char *t, usec_t *usec) {
static const struct {
const char *name;
@@ -545,12 +576,12 @@ int parse_timestamp(const char *t, usec_t *usec) {
goto from_tm;
} else if (streq(t, "yesterday")) {
- tm.tm_mday --;
+ 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_mday++;
tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
goto from_tm;
}
@@ -673,8 +704,7 @@ finish:
return 0;
}
-int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
-
+static char* extract_multiplier(char *p, usec_t *multiplier) {
static const struct {
const char *suffix;
usec_t usec;
@@ -708,7 +738,22 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
{ "usec", 1ULL },
{ "us", 1ULL },
};
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(table); i++) {
+ char *e;
+ e = startswith(p, table[i].suffix);
+ if (e) {
+ *multiplier = table[i].usec;
+ return e;
+ }
+ }
+
+ return p;
+}
+
+int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
const char *p, *s;
usec_t r = 0;
bool something = false;
@@ -733,8 +778,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
for (;;) {
long long l, z = 0;
char *e;
- unsigned i, n = 0;
- usec_t multiplier, k;
+ unsigned n = 0;
+ usec_t multiplier = default_unit, k;
p += strspn(p, WHITESPACE);
@@ -747,10 +792,8 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
errno = 0;
l = strtoll(p, &e, 10);
-
if (errno > 0)
return -errno;
-
if (l < 0)
return -ERANGE;
@@ -774,18 +817,7 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) {
return -EINVAL;
e += strspn(e, WHITESPACE);
-
- for (i = 0; i < ELEMENTSOF(table); i++)
- if (startswith(e, table[i].suffix)) {
- multiplier = table[i].usec;
- p = e + strlen(table[i].suffix);
- break;
- }
-
- if (i >= ELEMENTSOF(table)) {
- multiplier = default_unit;
- p = e;
- }
+ p = extract_multiplier(e, &multiplier);
something = true;
@@ -1048,22 +1080,31 @@ bool timezone_is_valid(const char *name) {
return true;
}
-clockid_t clock_boottime_or_monotonic(void) {
- static clockid_t clock = -1;
- int fd;
-
- if (clock != -1)
- return clock;
-
- fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
- if (fd < 0)
- clock = CLOCK_MONOTONIC;
- else {
- safe_close(fd);
- clock = CLOCK_BOOTTIME;
+bool clock_boottime_supported(void) {
+ static int supported = -1;
+
+ /* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
+
+ if (supported < 0) {
+ int fd;
+
+ fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
+ if (fd < 0)
+ supported = false;
+ else {
+ safe_close(fd);
+ supported = true;
+ }
}
- return clock;
+ return supported;
+}
+
+clockid_t clock_boottime_or_monotonic(void) {
+ if (clock_boottime_supported())
+ return CLOCK_BOOTTIME;
+ else
+ return CLOCK_MONOTONIC;
}
int get_timezone(char **tz) {
diff --git a/src/libbasic/time-util.h b/src/libbasic/time-util.h
index 9894e626c5..a5e3f567ec 100644
--- a/src/libbasic/time-util.h
+++ b/src/libbasic/time-util.h
@@ -99,6 +99,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy);
void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t);
int dual_timestamp_deserialize(const char *value, dual_timestamp *t);
+int timestamp_deserialize(const char *value, usec_t *timestamp);
int parse_timestamp(const char *t, usec_t *usec);
@@ -111,6 +112,7 @@ bool ntp_synced(void);
int get_timezones(char ***l);
bool timezone_is_valid(const char *name);
+bool clock_boottime_supported(void);
clockid_t clock_boottime_or_monotonic(void);
#define xstrftime(buf, fmt, tm) \
diff --git a/src/libbasic/user-util.c b/src/libbasic/user-util.c
index 19155bce53..f65ca3edaa 100644
--- a/src/libbasic/user-util.c
+++ b/src/libbasic/user-util.c
@@ -30,6 +30,7 @@
#include <sys/stat.h>
#include <unistd.h>
+#include "missing.h"
#include "alloc-util.h"
#include "fd-util.h"
#include "formats-util.h"
diff --git a/src/libbasic/user-util.h b/src/libbasic/user-util.h
index c23f1d485d..8026eca3f4 100644
--- a/src/libbasic/user-util.h
+++ b/src/libbasic/user-util.h
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include <sys/types.h>
+#include <unistd.h>
bool uid_is_valid(uid_t uid);
@@ -63,3 +64,7 @@ int take_etc_passwd_lock(const char *root);
#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1))
#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1))
+
+static inline bool userns_supported(void) {
+ return access("/proc/self/uid_map", F_OK) >= 0;
+}
diff --git a/src/libbasic/utf8.c b/src/libbasic/utf8.c
index 629db123cd..6eae2b983d 100644
--- a/src/libbasic/utf8.c
+++ b/src/libbasic/utf8.c
@@ -241,7 +241,7 @@ char *utf8_escape_non_printable(const char *str) {
*(s++) = hexchar((int) *str);
str += 1;
- len --;
+ len--;
}
}
} else {
diff --git a/src/libbasic/utf8.h b/src/libbasic/utf8.h
index 12c272d66e..f9b9c9468b 100644
--- a/src/libbasic/utf8.h
+++ b/src/libbasic/utf8.h
@@ -28,6 +28,7 @@
#include "missing.h"
#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd"
+#define UTF8_BYTE_ORDER_MARK "\xef\xbb\xbf"
bool unichar_is_valid(char32_t c);
diff --git a/src/libbasic/util.c b/src/libbasic/util.c
index ea1bed7ceb..756c663be4 100644
--- a/src/libbasic/util.c
+++ b/src/libbasic/util.c
@@ -55,6 +55,7 @@
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
+#include "umask-util.h"
#include "user-util.h"
#include "util.h"
@@ -419,13 +420,17 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
_exit(EXIT_FAILURE);
}
- if (!stdout_is_tty)
- dup2(fd, STDOUT_FILENO);
+ if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
+ log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
- if (!stderr_is_tty)
- dup2(fd, STDERR_FILENO);
+ if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
+ log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
+ _exit(EXIT_FAILURE);
+ }
- if (fd > 2)
+ if (fd > STDERR_FILENO)
close(fd);
}
@@ -517,7 +522,7 @@ int on_ac_power(void) {
if (!de)
break;
- if (hidden_file(de->d_name))
+ if (hidden_or_backup_file(de->d_name))
continue;
device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
@@ -773,15 +778,25 @@ uint64_t physical_memory(void) {
return (uint64_t) mem * (uint64_t) page_size();
}
-int update_reboot_param_file(const char *param) {
- int r = 0;
+int update_reboot_parameter_and_warn(const char *param) {
+ int r;
+
+ if (isempty(param)) {
+ if (unlink("/run/systemd/reboot-param") < 0) {
+ if (errno == ENOENT)
+ return 0;
+
+ return log_warning_errno(errno, "Failed to unlink reboot parameter file: %m");
+ }
- if (param) {
- r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE);
+ return 0;
+ }
+
+ RUN_WITH_UMASK(0022) {
+ r = write_string_file("/run/systemd/reboot-param", param, WRITE_STRING_FILE_CREATE);
if (r < 0)
- return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m");
- } else
- (void) unlink(REBOOT_PARAM_FILE);
+ return log_warning_errno(r, "Failed to write reboot parameter file: %m");
+ }
return 0;
}
diff --git a/src/libbasic/util.h b/src/libbasic/util.h
index 6f42c85a33..1c032c15c9 100644
--- a/src/libbasic/util.h
+++ b/src/libbasic/util.h
@@ -36,6 +36,7 @@
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/statfs.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
@@ -102,6 +103,16 @@ static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_
qsort(base, nmemb, size, compar);
}
+/**
+ * Normal memcpy requires src to be nonnull. We do nothing if n is 0.
+ */
+static inline void memcpy_safe(void *dst, const void *src, size_t n) {
+ if (n == 0)
+ return;
+ assert(src);
+ memcpy(dst, src, n);
+}
+
int on_ac_power(void);
#define memzero(x,l) (memset((x), 0, (l)))
@@ -173,6 +184,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
uint64_t physical_memory(void);
-int update_reboot_param_file(const char *param);
+int update_reboot_parameter_and_warn(const char *param);
int version(void);
diff --git a/src/libbasic/virt.c b/src/libbasic/virt.c
index 19b6318e3d..dace1f4328 100644
--- a/src/libbasic/virt.c
+++ b/src/libbasic/virt.c
@@ -98,6 +98,8 @@ static int detect_vm_cpuid(void) {
: "0" (eax)
);
+ log_debug("Virtualization found, CPUID=%s", sig.text);
+
for (j = 0; j < ELEMENTSOF(cpuid_vendor_table); j ++)
if (streq(sig.text, cpuid_vendor_table[j].cpuid))
return cpuid_vendor_table[j].id;
@@ -105,6 +107,7 @@ static int detect_vm_cpuid(void) {
return VIRTUALIZATION_VM_OTHER;
}
#endif
+ log_debug("No virtualization found in CPUID");
return VIRTUALIZATION_NONE;
}
@@ -121,19 +124,25 @@ static int detect_vm_device_tree(void) {
dir = opendir("/proc/device-tree");
if (!dir) {
- if (errno == ENOENT)
+ if (errno == ENOENT) {
+ log_debug_errno(errno, "/proc/device-tree: %m");
return VIRTUALIZATION_NONE;
+ }
return -errno;
}
FOREACH_DIRENT(dent, dir, return -errno)
- if (strstr(dent->d_name, "fw-cfg"))
+ if (strstr(dent->d_name, "fw-cfg")) {
+ log_debug("Virtualization QEMU: \"fw-cfg\" present in /proc/device-tree/%s", dent->d_name);
return VIRTUALIZATION_QEMU;
+ }
+ log_debug("No virtualization found in /proc/device-tree/*");
return VIRTUALIZATION_NONE;
} else if (r < 0)
return r;
+ log_debug("Virtualization %s found in /proc/device-tree/hypervisor/compatible", hvtype);
if (streq(hvtype, "linux,kvm"))
return VIRTUALIZATION_KVM;
else if (strstr(hvtype, "xen"))
@@ -141,6 +150,7 @@ static int detect_vm_device_tree(void) {
else
return VIRTUALIZATION_VM_OTHER;
#else
+ log_debug("This platform does not support /proc/device-tree");
return VIRTUALIZATION_NONE;
#endif
}
@@ -184,30 +194,58 @@ static int detect_vm_dmi(void) {
return r;
}
+
+
for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
- if (startswith(s, dmi_vendor_table[j].vendor))
+ if (startswith(s, dmi_vendor_table[j].vendor)) {
+ log_debug("Virtualization %s found in DMI (%s)", s, dmi_vendors[i]);
return dmi_vendor_table[j].id;
+ }
}
#endif
+ log_debug("No virtualization found in DMI");
+
return VIRTUALIZATION_NONE;
}
static int detect_vm_xen(void) {
+ /* Check for Dom0 will be executed later in detect_vm_xen_dom0
+ Thats why we dont check the content of /proc/xen/capabilities here. */
+ if (access("/proc/xen/capabilities", F_OK) < 0) {
+ log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist");
+ return VIRTUALIZATION_NONE;
+ }
+
+ log_debug("Virtualization XEN found (/proc/xen/capabilities exists)");
+ return VIRTUALIZATION_XEN;
+
+}
+
+static bool detect_vm_xen_dom0(void) {
_cleanup_free_ char *domcap = NULL;
char *cap, *i;
int r;
r = read_one_line_file("/proc/xen/capabilities", &domcap);
- if (r == -ENOENT)
- return VIRTUALIZATION_NONE;
+ if (r == -ENOENT) {
+ log_debug("Virtualization XEN not found, /proc/xen/capabilities does not exist");
+ return false;
+ }
+ if (r < 0)
+ return r;
i = domcap;
while ((cap = strsep(&i, ",")))
if (streq(cap, "control_d"))
break;
+ if (!cap) {
+ log_debug("Virtualization XEN DomU found (/proc/xen/capabilites)");
+ return false;
+ }
- return cap ? VIRTUALIZATION_NONE : VIRTUALIZATION_XEN;
+ log_debug("Virtualization XEN Dom0 ignored (/proc/xen/capabilities)");
+ return true;
}
static int detect_vm_hypervisor(void) {
@@ -220,6 +258,8 @@ static int detect_vm_hypervisor(void) {
if (r < 0)
return r;
+ log_debug("Virtualization %s found in /sys/hypervisor/type", hvtype);
+
if (streq(hvtype, "xen"))
return VIRTUALIZATION_XEN;
else
@@ -234,9 +274,13 @@ static int detect_vm_uml(void) {
r = read_full_file("/proc/cpuinfo", &cpuinfo_contents, NULL);
if (r < 0)
return r;
- if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n"))
+
+ if (strstr(cpuinfo_contents, "\nvendor_id\t: User Mode Linux\n")) {
+ log_debug("UML virtualization found in /proc/cpuinfo");
return VIRTUALIZATION_UML;
+ }
+ log_debug("No virtualization found in /proc/cpuinfo.");
return VIRTUALIZATION_NONE;
}
@@ -252,11 +296,13 @@ static int detect_vm_zvm(void) {
if (r < 0)
return r;
+ log_debug("Virtualization %s found in /proc/sysinfo", t);
if (streq(t, "z/VM"))
return VIRTUALIZATION_ZVM;
else
return VIRTUALIZATION_KVM;
#else
+ log_debug("This platform does not support /proc/sysinfo");
return VIRTUALIZATION_NONE;
#endif
}
@@ -324,7 +370,14 @@ int detect_vm(void) {
return r;
finish:
+ /* x86 xen Dom0 is detected as XEN in hypervisor and maybe others.
+ * In order to detect the Dom0 as not virtualization we need to
+ * double-check it */
+ if (r == VIRTUALIZATION_XEN && detect_vm_xen_dom0())
+ r = VIRTUALIZATION_NONE;
+
cached_found = r;
+ log_debug("Found VM virtualization %s", virtualization_to_string(r));
return r;
}
@@ -412,6 +465,7 @@ int detect_container(void) {
r = VIRTUALIZATION_CONTAINER_OTHER;
finish:
+ log_debug("Found container virtualization %s", virtualization_to_string(r));
cached_found = r;
return r;
}
@@ -420,10 +474,10 @@ int detect_virtualization(void) {
int r;
r = detect_container();
- if (r != 0)
- return r;
+ if (r == 0)
+ r = detect_vm();
- return detect_vm();
+ return r;
}
int running_in_chroot(void) {
diff --git a/src/libbasic/xattr-util.c b/src/libbasic/xattr-util.c
index 8d7f14f382..8256899eda 100644
--- a/src/libbasic/xattr-util.c
+++ b/src/libbasic/xattr-util.c
@@ -110,7 +110,7 @@ ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute,
/* 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));
+ fd = openat(dirfd, filename, O_CLOEXEC|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0));
if (fd < 0)
return -errno;
diff --git a/src/libbus-proxy-core/bus-xml-policy.c b/src/libbus-proxy-core/bus-xml-policy.c
deleted file mode 100644
index 86a8362142..0000000000
--- a/src/libbus-proxy-core/bus-xml-policy.c
+++ /dev/null
@@ -1,1327 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2013 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 <systemd/sd-login.h>
-
-#include "alloc-util.h"
-#include "bus-internal.h"
-#include "bus-xml-policy.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);
-
- free(i->interface);
- free(i->member);
- free(i->error);
- free(i->name);
- free(i->path);
- free(i);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(PolicyItem*, policy_item_free);
-
-static void item_append(PolicyItem *i, PolicyItem **list) {
-
- PolicyItem *tail;
-
- LIST_FIND_TAIL(items, *list, tail);
- LIST_INSERT_AFTER(items, *list, tail, i);
-}
-
-static int file_load(Policy *p, const char *path) {
-
- _cleanup_free_ char *c = NULL, *policy_user = NULL, *policy_group = NULL;
- _cleanup_(policy_item_freep) PolicyItem *i = NULL;
- void *xml_state = NULL;
- unsigned n_other = 0;
- const char *q;
- int r;
-
- enum {
- STATE_OUTSIDE,
- STATE_BUSCONFIG,
- STATE_POLICY,
- STATE_POLICY_CONTEXT,
- STATE_POLICY_CONSOLE,
- STATE_POLICY_USER,
- STATE_POLICY_GROUP,
- STATE_POLICY_OTHER_ATTRIBUTE,
- STATE_ALLOW_DENY,
- STATE_ALLOW_DENY_INTERFACE,
- STATE_ALLOW_DENY_MEMBER,
- STATE_ALLOW_DENY_ERROR,
- STATE_ALLOW_DENY_PATH,
- STATE_ALLOW_DENY_MESSAGE_TYPE,
- STATE_ALLOW_DENY_NAME,
- STATE_ALLOW_DENY_OTHER_ATTRIBUTE,
- STATE_OTHER,
- } state = STATE_OUTSIDE;
-
- enum {
- POLICY_CATEGORY_NONE,
- POLICY_CATEGORY_DEFAULT,
- POLICY_CATEGORY_MANDATORY,
- POLICY_CATEGORY_ON_CONSOLE,
- POLICY_CATEGORY_NO_CONSOLE,
- POLICY_CATEGORY_USER,
- POLICY_CATEGORY_GROUP
- } policy_category = POLICY_CATEGORY_NONE;
-
- unsigned line = 0;
-
- assert(p);
-
- r = read_full_file(path, &c, NULL);
- if (r < 0) {
- if (r == -ENOENT)
- return 0;
- if (r == -EISDIR)
- return r;
-
- return log_error_errno(r, "Failed to load %s: %m", path);
- }
-
- q = c;
- for (;;) {
- _cleanup_free_ char *name = NULL;
- int t;
-
- t = xml_tokenize(&q, &name, &xml_state, &line);
- if (t < 0)
- return log_error_errno(t, "XML parse failure in %s: %m", path);
-
- switch (state) {
-
- case STATE_OUTSIDE:
-
- if (t == XML_TAG_OPEN) {
- if (streq(name, "busconfig"))
- state = STATE_BUSCONFIG;
- else {
- log_error("Unexpected tag %s at %s:%u.", name, path, line);
- return -EINVAL;
- }
-
- } else if (t == XML_END)
- return 0;
- else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
- log_error("Unexpected token (1) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_BUSCONFIG:
-
- if (t == XML_TAG_OPEN) {
- if (streq(name, "policy")) {
- state = STATE_POLICY;
- policy_category = POLICY_CATEGORY_NONE;
- free(policy_user);
- free(policy_group);
- policy_user = policy_group = NULL;
- } else {
- state = STATE_OTHER;
- n_other = 0;
- }
- } else if (t == XML_TAG_CLOSE_EMPTY ||
- (t == XML_TAG_CLOSE && streq(name, "busconfig")))
- state = STATE_OUTSIDE;
- else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
- log_error("Unexpected token (2) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_POLICY:
-
- if (t == XML_ATTRIBUTE_NAME) {
- if (streq(name, "context"))
- state = STATE_POLICY_CONTEXT;
- else if (streq(name, "at_console"))
- state = STATE_POLICY_CONSOLE;
- else if (streq(name, "user"))
- state = STATE_POLICY_USER;
- else if (streq(name, "group"))
- state = STATE_POLICY_GROUP;
- else {
- log_warning("Attribute %s of <policy> tag unknown at %s:%u, ignoring.", name, path, line);
- state = STATE_POLICY_OTHER_ATTRIBUTE;
- }
- } else if (t == XML_TAG_CLOSE_EMPTY ||
- (t == XML_TAG_CLOSE && streq(name, "policy")))
- state = STATE_BUSCONFIG;
- else if (t == XML_TAG_OPEN) {
- PolicyItemType it;
-
- if (streq(name, "allow"))
- it = POLICY_ITEM_ALLOW;
- else if (streq(name, "deny"))
- it = POLICY_ITEM_DENY;
- else {
- log_warning("Unknown tag %s in <policy> %s:%u.", name, path, line);
- return -EINVAL;
- }
-
- assert(!i);
- i = new0(PolicyItem, 1);
- if (!i)
- return log_oom();
-
- i->type = it;
- state = STATE_ALLOW_DENY;
-
- } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
- log_error("Unexpected token (3) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_POLICY_CONTEXT:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- if (streq(name, "default")) {
- policy_category = POLICY_CATEGORY_DEFAULT;
- state = STATE_POLICY;
- } else if (streq(name, "mandatory")) {
- policy_category = POLICY_CATEGORY_MANDATORY;
- state = STATE_POLICY;
- } else {
- log_error("context= parameter %s unknown for <policy> at %s:%u.", name, path, line);
- return -EINVAL;
- }
- } else {
- log_error("Unexpected token (4) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_POLICY_CONSOLE:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- if (streq(name, "true")) {
- policy_category = POLICY_CATEGORY_ON_CONSOLE;
- state = STATE_POLICY;
- } else if (streq(name, "false")) {
- policy_category = POLICY_CATEGORY_NO_CONSOLE;
- state = STATE_POLICY;
- } else {
- log_error("at_console= parameter %s unknown for <policy> at %s:%u.", name, path, line);
- return -EINVAL;
- }
- } else {
- log_error("Unexpected token (4.1) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_POLICY_USER:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- free(policy_user);
- policy_user = name;
- name = NULL;
- policy_category = POLICY_CATEGORY_USER;
- state = STATE_POLICY;
- } else {
- log_error("Unexpected token (5) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_POLICY_GROUP:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- free(policy_group);
- policy_group = name;
- name = NULL;
- policy_category = POLICY_CATEGORY_GROUP;
- state = STATE_POLICY;
- } else {
- log_error("Unexpected token (6) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_POLICY_OTHER_ATTRIBUTE:
-
- if (t == XML_ATTRIBUTE_VALUE)
- state = STATE_POLICY;
- else {
- log_error("Unexpected token (7) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY:
-
- assert(i);
-
- if (t == XML_ATTRIBUTE_NAME) {
- PolicyItemClass ic;
-
- if (startswith(name, "send_"))
- ic = POLICY_ITEM_SEND;
- else if (startswith(name, "receive_"))
- ic = POLICY_ITEM_RECV;
- else if (streq(name, "own"))
- ic = POLICY_ITEM_OWN;
- else if (streq(name, "own_prefix"))
- ic = POLICY_ITEM_OWN_PREFIX;
- else if (streq(name, "user"))
- ic = POLICY_ITEM_USER;
- else if (streq(name, "group"))
- ic = POLICY_ITEM_GROUP;
- else if (STR_IN_SET(name, "eavesdrop", "log")) {
- log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
- state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
- break;
- } else {
- log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
- state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
- break;
- }
-
- if (i->class != _POLICY_ITEM_CLASS_UNSET && ic != i->class) {
- log_error("send_, receive_/eavesdrop fields mixed on same tag at %s:%u.", path, line);
- return -EINVAL;
- }
-
- i->class = ic;
-
- if (ic == POLICY_ITEM_SEND || ic == POLICY_ITEM_RECV) {
- const char *u;
-
- u = strchr(name, '_');
- assert(u);
-
- u++;
-
- if (streq(u, "interface"))
- state = STATE_ALLOW_DENY_INTERFACE;
- else if (streq(u, "member"))
- state = STATE_ALLOW_DENY_MEMBER;
- else if (streq(u, "error"))
- state = STATE_ALLOW_DENY_ERROR;
- else if (streq(u, "path"))
- state = STATE_ALLOW_DENY_PATH;
- else if (streq(u, "type"))
- state = STATE_ALLOW_DENY_MESSAGE_TYPE;
- else if ((streq(u, "destination") && ic == POLICY_ITEM_SEND) ||
- (streq(u, "sender") && ic == POLICY_ITEM_RECV))
- state = STATE_ALLOW_DENY_NAME;
- else {
- if (streq(u, "requested_reply"))
- log_debug("Unsupported attribute %s= at %s:%u, ignoring.", name, path, line);
- else
- log_error("Unknown attribute %s= at %s:%u, ignoring.", name, path, line);
- state = STATE_ALLOW_DENY_OTHER_ATTRIBUTE;
- break;
- }
- } else
- state = STATE_ALLOW_DENY_NAME;
-
- } else if (t == XML_TAG_CLOSE_EMPTY ||
- (t == XML_TAG_CLOSE && streq(name, i->type == POLICY_ITEM_ALLOW ? "allow" : "deny"))) {
-
- /* If the tag is fully empty so far, we consider it a recv */
- if (i->class == _POLICY_ITEM_CLASS_UNSET)
- i->class = POLICY_ITEM_RECV;
-
- if (policy_category == POLICY_CATEGORY_DEFAULT)
- item_append(i, &p->default_items);
- else if (policy_category == POLICY_CATEGORY_MANDATORY)
- item_append(i, &p->mandatory_items);
- else if (policy_category == POLICY_CATEGORY_ON_CONSOLE)
- item_append(i, &p->on_console_items);
- else if (policy_category == POLICY_CATEGORY_NO_CONSOLE)
- item_append(i, &p->no_console_items);
- else if (policy_category == POLICY_CATEGORY_USER) {
- const char *u = policy_user;
-
- assert_cc(sizeof(uid_t) == sizeof(uint32_t));
-
- r = hashmap_ensure_allocated(&p->user_items, NULL);
- if (r < 0)
- return log_oom();
-
- if (!u) {
- log_error("User policy without name");
- return -EINVAL;
- }
-
- r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to resolve user %s, ignoring policy: %m", u);
- free(i);
- } else {
- PolicyItem *first;
-
- first = hashmap_get(p->user_items, UID_TO_PTR(i->uid));
- item_append(i, &first);
- i->uid_valid = true;
-
- r = hashmap_replace(p->user_items, UID_TO_PTR(i->uid), first);
- if (r < 0) {
- LIST_REMOVE(items, first, i);
- return log_oom();
- }
- }
-
- } else if (policy_category == POLICY_CATEGORY_GROUP) {
- const char *g = policy_group;
-
- assert_cc(sizeof(gid_t) == sizeof(uint32_t));
-
- r = hashmap_ensure_allocated(&p->group_items, NULL);
- if (r < 0)
- return log_oom();
-
- if (!g) {
- log_error("Group policy without name");
- return -EINVAL;
- }
-
- r = get_group_creds(&g, &i->gid);
- if (r < 0) {
- log_error_errno(r, "Failed to resolve group %s, ignoring policy: %m", g);
- free(i);
- } else {
- PolicyItem *first;
-
- first = hashmap_get(p->group_items, GID_TO_PTR(i->gid));
- item_append(i, &first);
- i->gid_valid = true;
-
- r = hashmap_replace(p->group_items, GID_TO_PTR(i->gid), first);
- if (r < 0) {
- LIST_REMOVE(items, first, i);
- return log_oom();
- }
- }
- }
-
- state = STATE_POLICY;
- i = NULL;
-
- } else if (t != XML_TEXT || !in_charset(name, WHITESPACE)) {
- log_error("Unexpected token (8) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY_INTERFACE:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- assert(i);
- if (i->interface) {
- log_error("Duplicate interface at %s:%u.", path, line);
- return -EINVAL;
- }
-
- if (!streq(name, "*")) {
- i->interface = name;
- name = NULL;
- }
- state = STATE_ALLOW_DENY;
- } else {
- log_error("Unexpected token (9) at %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY_MEMBER:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- assert(i);
- if (i->member) {
- log_error("Duplicate member in %s:%u.", path, line);
- return -EINVAL;
- }
-
- if (!streq(name, "*")) {
- i->member = name;
- name = NULL;
- }
- state = STATE_ALLOW_DENY;
- } else {
- log_error("Unexpected token (10) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY_ERROR:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- assert(i);
- if (i->error) {
- log_error("Duplicate error in %s:%u.", path, line);
- return -EINVAL;
- }
-
- if (!streq(name, "*")) {
- i->error = name;
- name = NULL;
- }
- state = STATE_ALLOW_DENY;
- } else {
- log_error("Unexpected token (11) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY_PATH:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- assert(i);
- if (i->path) {
- log_error("Duplicate path in %s:%u.", path, line);
- return -EINVAL;
- }
-
- if (!streq(name, "*")) {
- i->path = name;
- name = NULL;
- }
- state = STATE_ALLOW_DENY;
- } else {
- log_error("Unexpected token (12) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY_MESSAGE_TYPE:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- assert(i);
-
- if (i->message_type != 0) {
- log_error("Duplicate message type in %s:%u.", path, line);
- return -EINVAL;
- }
-
- if (!streq(name, "*")) {
- r = bus_message_type_from_string(name, &i->message_type);
- if (r < 0) {
- log_error("Invalid message type in %s:%u.", path, line);
- return -EINVAL;
- }
- }
-
- state = STATE_ALLOW_DENY;
- } else {
- log_error("Unexpected token (13) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY_NAME:
-
- if (t == XML_ATTRIBUTE_VALUE) {
- assert(i);
- if (i->name) {
- log_error("Duplicate name in %s:%u.", path, line);
- return -EINVAL;
- }
-
- switch (i->class) {
- case POLICY_ITEM_USER:
- if (!streq(name, "*")) {
- const char *u = name;
-
- r = get_user_creds(&u, &i->uid, NULL, NULL, NULL);
- if (r < 0)
- log_error_errno(r, "Failed to resolve user %s: %m", name);
- else
- i->uid_valid = true;
- }
- break;
- case POLICY_ITEM_GROUP:
- if (!streq(name, "*")) {
- const char *g = name;
-
- r = get_group_creds(&g, &i->gid);
- if (r < 0)
- log_error_errno(r, "Failed to resolve group %s: %m", name);
- else
- i->gid_valid = true;
- }
- break;
-
- case POLICY_ITEM_SEND:
- case POLICY_ITEM_RECV:
-
- if (streq(name, "*"))
- name = mfree(name);
- break;
-
-
- default:
- break;
- }
-
- i->name = name;
- name = NULL;
-
- state = STATE_ALLOW_DENY;
- } else {
- log_error("Unexpected token (14) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_ALLOW_DENY_OTHER_ATTRIBUTE:
-
- if (t == XML_ATTRIBUTE_VALUE)
- state = STATE_ALLOW_DENY;
- else {
- log_error("Unexpected token (15) in %s:%u.", path, line);
- return -EINVAL;
- }
-
- break;
-
- case STATE_OTHER:
-
- if (t == XML_TAG_OPEN)
- n_other++;
- else if (t == XML_TAG_CLOSE || t == XML_TAG_CLOSE_EMPTY) {
-
- if (n_other == 0)
- state = STATE_BUSCONFIG;
- else
- n_other--;
- }
-
- break;
- }
- }
-}
-
-enum {
- DENY,
- ALLOW,
- DUNNO,
-};
-
-static const char *verdict_to_string(int v) {
- switch (v) {
-
- case DENY:
- return "DENY";
- case ALLOW:
- return "ALLOW";
- case DUNNO:
- return "DUNNO";
- }
-
- return NULL;
-}
-
-struct policy_check_filter {
- PolicyItemClass class;
- uid_t uid;
- gid_t gid;
- int message_type;
- const char *name;
- const char *interface;
- const char *path;
- const char *member;
-};
-
-static int is_permissive(PolicyItem *i) {
-
- assert(i);
-
- return (i->type == POLICY_ITEM_ALLOW) ? ALLOW : DENY;
-}
-
-static int check_policy_item(PolicyItem *i, const struct policy_check_filter *filter) {
-
- assert(i);
- assert(filter);
-
- switch (i->class) {
- case POLICY_ITEM_SEND:
- case POLICY_ITEM_RECV:
-
- if (i->name && !streq_ptr(i->name, filter->name))
- break;
-
- if ((i->message_type != 0) && (i->message_type != filter->message_type))
- break;
-
- if (i->path && !streq_ptr(i->path, filter->path))
- break;
-
- if (i->member && !streq_ptr(i->member, filter->member))
- break;
-
- if (i->interface && !streq_ptr(i->interface, filter->interface))
- break;
-
- return is_permissive(i);
-
- case POLICY_ITEM_OWN:
- assert(filter->name);
-
- if (streq(i->name, "*") || streq(i->name, filter->name))
- return is_permissive(i);
- break;
-
- case POLICY_ITEM_OWN_PREFIX:
- assert(filter->name);
-
- if (streq(i->name, "*") || service_name_startswith(filter->name, i->name))
- return is_permissive(i);
- break;
-
- case POLICY_ITEM_USER:
- if (filter->uid != UID_INVALID)
- if ((streq_ptr(i->name, "*") || (i->uid_valid && i->uid == filter->uid)))
- return is_permissive(i);
- break;
-
- case POLICY_ITEM_GROUP:
- if (filter->gid != GID_INVALID)
- if ((streq_ptr(i->name, "*") || (i->gid_valid && i->gid == filter->gid)))
- return is_permissive(i);
- break;
-
- case POLICY_ITEM_IGNORE:
- default:
- break;
- }
-
- return DUNNO;
-}
-
-static int check_policy_items(PolicyItem *items, const struct policy_check_filter *filter) {
-
- PolicyItem *i;
- int verdict = DUNNO;
-
- assert(filter);
-
- /* Check all policies in a set - a broader one might be followed by a more specific one,
- * and the order of rules in policy definitions matters */
- LIST_FOREACH(items, i, items) {
- int v;
-
- if (i->class != filter->class &&
- !(i->class == POLICY_ITEM_OWN_PREFIX && filter->class == POLICY_ITEM_OWN))
- continue;
-
- v = check_policy_item(i, filter);
- if (v != DUNNO)
- verdict = v;
- }
-
- return verdict;
-}
-
-static int policy_check(Policy *p, const struct policy_check_filter *filter) {
-
- PolicyItem *items;
- int verdict, v;
-
- assert(p);
- assert(filter);
-
- assert(IN_SET(filter->class, POLICY_ITEM_SEND, POLICY_ITEM_RECV, POLICY_ITEM_OWN, POLICY_ITEM_USER, POLICY_ITEM_GROUP));
-
- /*
- * The policy check is implemented by the following logic:
- *
- * 1. Check default items
- * 2. Check group items
- * 3. Check user items
- * 4. Check on/no_console items
- * 5. Check mandatory items
- *
- * Later rules override earlier rules.
- */
-
- verdict = check_policy_items(p->default_items, filter);
-
- if (filter->gid != GID_INVALID) {
- items = hashmap_get(p->group_items, GID_TO_PTR(filter->gid));
- if (items) {
- v = check_policy_items(items, filter);
- if (v != DUNNO)
- verdict = v;
- }
- }
-
- if (filter->uid != UID_INVALID) {
- items = hashmap_get(p->user_items, UID_TO_PTR(filter->uid));
- if (items) {
- v = check_policy_items(items, filter);
- if (v != DUNNO)
- verdict = v;
- }
- }
-
- if (filter->uid != UID_INVALID && sd_uid_get_seats(filter->uid, -1, NULL) > 0)
- v = check_policy_items(p->on_console_items, filter);
- else
- v = check_policy_items(p->no_console_items, filter);
- if (v != DUNNO)
- verdict = v;
-
- v = check_policy_items(p->mandatory_items, filter);
- if (v != DUNNO)
- verdict = v;
-
- return verdict;
-}
-
-bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name) {
-
- struct policy_check_filter filter = {
- .class = POLICY_ITEM_OWN,
- .uid = uid,
- .gid = gid,
- .name = name,
- };
-
- int verdict;
-
- assert(p);
- assert(name);
-
- verdict = policy_check(p, &filter);
-
- log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
- "Ownership permission check for uid=" UID_FMT " gid=" GID_FMT" name=%s: %s",
- uid, gid, strna(name), strna(verdict_to_string(verdict)));
-
- return verdict == ALLOW;
-}
-
-bool policy_check_hello(Policy *p, uid_t uid, gid_t gid) {
-
- struct policy_check_filter filter = {
- .uid = uid,
- .gid = gid,
- };
- int verdict;
-
- assert(p);
-
- filter.class = POLICY_ITEM_USER;
- verdict = policy_check(p, &filter);
-
- if (verdict != DENY) {
- int v;
-
- filter.class = POLICY_ITEM_GROUP;
- v = policy_check(p, &filter);
- if (v != DUNNO)
- verdict = v;
- }
-
- log_full(LOG_AUTH | (verdict != ALLOW ? LOG_WARNING : LOG_DEBUG),
- "Hello permission check for uid=" UID_FMT " gid=" GID_FMT": %s",
- uid, gid, strna(verdict_to_string(verdict)));
-
- return verdict == ALLOW;
-}
-
-bool policy_check_one_recv(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- const char *name,
- const char *path,
- const char *interface,
- const char *member) {
-
- struct policy_check_filter filter = {
- .class = POLICY_ITEM_RECV,
- .uid = uid,
- .gid = gid,
- .message_type = message_type,
- .name = name,
- .interface = interface,
- .path = path,
- .member = member,
- };
-
- assert(p);
-
- return policy_check(p, &filter) == ALLOW;
-}
-
-bool policy_check_recv(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- Set *names,
- char **namesv,
- const char *path,
- const char *interface,
- const char *member,
- bool dbus_to_kernel) {
-
- char *n, **nv, *last = NULL;
- bool allow = false;
- Iterator i;
-
- assert(p);
-
- if (set_isempty(names) && strv_isempty(namesv)) {
- allow = policy_check_one_recv(p, uid, gid, message_type, NULL, path, interface, member);
- } else {
- SET_FOREACH(n, names, i) {
- last = n;
- allow = policy_check_one_recv(p, uid, gid, message_type, n, path, interface, member);
- if (allow)
- break;
- }
- if (!allow) {
- STRV_FOREACH(nv, namesv) {
- last = *nv;
- allow = policy_check_one_recv(p, uid, gid, message_type, *nv, path, interface, member);
- if (allow)
- break;
- }
- }
- }
-
- log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
- "Receive permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
- dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
- strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
-
- return allow;
-}
-
-bool policy_check_one_send(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- const char *name,
- const char *path,
- const char *interface,
- const char *member) {
-
- struct policy_check_filter filter = {
- .class = POLICY_ITEM_SEND,
- .uid = uid,
- .gid = gid,
- .message_type = message_type,
- .name = name,
- .interface = interface,
- .path = path,
- .member = member,
- };
-
- assert(p);
-
- return policy_check(p, &filter) == ALLOW;
-}
-
-bool policy_check_send(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- Set *names,
- char **namesv,
- const char *path,
- const char *interface,
- const char *member,
- bool dbus_to_kernel,
- char **out_used_name) {
-
- char *n, **nv, *last = NULL;
- bool allow = false;
- Iterator i;
-
- assert(p);
-
- if (set_isempty(names) && strv_isempty(namesv)) {
- allow = policy_check_one_send(p, uid, gid, message_type, NULL, path, interface, member);
- } else {
- SET_FOREACH(n, names, i) {
- last = n;
- allow = policy_check_one_send(p, uid, gid, message_type, n, path, interface, member);
- if (allow)
- break;
- }
- if (!allow) {
- STRV_FOREACH(nv, namesv) {
- last = *nv;
- allow = policy_check_one_send(p, uid, gid, message_type, *nv, path, interface, member);
- if (allow)
- break;
- }
- }
- }
-
- if (out_used_name)
- *out_used_name = last;
-
- log_full(LOG_AUTH | (!allow ? LOG_WARNING : LOG_DEBUG),
- "Send permission check %s for uid=" UID_FMT " gid=" GID_FMT" message=%s name=%s path=%s interface=%s member=%s: %s",
- dbus_to_kernel ? "dbus-1 to kernel" : "kernel to dbus-1", uid, gid, bus_message_type_to_string(message_type), strna(last),
- strna(path), strna(interface), strna(member), allow ? "ALLOW" : "DENY");
-
- return allow;
-}
-
-int policy_load(Policy *p, char **files) {
- char **i;
- int r;
-
- assert(p);
-
- STRV_FOREACH(i, files) {
-
- r = file_load(p, *i);
- if (r == -EISDIR) {
- _cleanup_strv_free_ char **l = NULL;
- char **j;
-
- r = conf_files_list(&l, ".conf", NULL, *i, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to get configuration file list: %m");
-
- STRV_FOREACH(j, l)
- file_load(p, *j);
- }
-
- /* We ignore all errors but EISDIR, and just proceed. */
- }
-
- return 0;
-}
-
-void policy_free(Policy *p) {
- PolicyItem *i, *first;
-
- if (!p)
- return;
-
- while ((i = p->default_items)) {
- LIST_REMOVE(items, p->default_items, i);
- policy_item_free(i);
- }
-
- while ((i = p->mandatory_items)) {
- LIST_REMOVE(items, p->mandatory_items, i);
- policy_item_free(i);
- }
-
- while ((i = p->on_console_items)) {
- LIST_REMOVE(items, p->on_console_items, i);
- policy_item_free(i);
- }
-
- while ((i = p->no_console_items)) {
- LIST_REMOVE(items, p->no_console_items, i);
- policy_item_free(i);
- }
-
- while ((first = hashmap_steal_first(p->user_items))) {
-
- while ((i = first)) {
- LIST_REMOVE(items, first, i);
- policy_item_free(i);
- }
- }
-
- while ((first = hashmap_steal_first(p->group_items))) {
-
- while ((i = first)) {
- LIST_REMOVE(items, first, i);
- policy_item_free(i);
- }
- }
-
- hashmap_free(p->user_items);
- hashmap_free(p->group_items);
-
- p->user_items = p->group_items = NULL;
-}
-
-static void dump_items(PolicyItem *items, const char *prefix) {
-
- PolicyItem *i;
-
- if (!items)
- return;
-
- if (!prefix)
- prefix = "";
-
- LIST_FOREACH(items, i, items) {
-
- printf("%sType: %s\n"
- "%sClass: %s\n",
- prefix, policy_item_type_to_string(i->type),
- prefix, policy_item_class_to_string(i->class));
-
- if (i->interface)
- printf("%sInterface: %s\n",
- prefix, i->interface);
-
- if (i->member)
- printf("%sMember: %s\n",
- prefix, i->member);
-
- if (i->error)
- printf("%sError: %s\n",
- prefix, i->error);
-
- if (i->path)
- printf("%sPath: %s\n",
- prefix, i->path);
-
- if (i->name)
- printf("%sName: %s\n",
- prefix, i->name);
-
- if (i->message_type != 0)
- printf("%sMessage Type: %s\n",
- prefix, bus_message_type_to_string(i->message_type));
-
- if (i->uid_valid) {
- _cleanup_free_ char *user;
-
- user = uid_to_name(i->uid);
-
- printf("%sUser: %s ("UID_FMT")\n",
- prefix, strna(user), i->uid);
- }
-
- if (i->gid_valid) {
- _cleanup_free_ char *group;
-
- group = gid_to_name(i->gid);
-
- printf("%sGroup: %s ("GID_FMT")\n",
- prefix, strna(group), i->gid);
- }
- printf("%s-\n", prefix);
- }
-}
-
-static void dump_hashmap_items(Hashmap *h) {
- PolicyItem *i;
- Iterator j;
- void *k;
-
- HASHMAP_FOREACH_KEY(i, k, h, j) {
- printf("\t%s Item for " UID_FMT ":\n", draw_special_char(DRAW_ARROW), PTR_TO_UID(k));
- dump_items(i, "\t\t");
- }
-}
-
-void policy_dump(Policy *p) {
-
- printf("%s Default Items:\n", draw_special_char(DRAW_ARROW));
- dump_items(p->default_items, "\t");
-
- printf("%s Group Items:\n", draw_special_char(DRAW_ARROW));
- dump_hashmap_items(p->group_items);
-
- printf("%s User Items:\n", draw_special_char(DRAW_ARROW));
- dump_hashmap_items(p->user_items);
-
- printf("%s On-Console Items:\n", draw_special_char(DRAW_ARROW));
- dump_items(p->on_console_items, "\t");
-
- printf("%s No-Console Items:\n", draw_special_char(DRAW_ARROW));
- dump_items(p->no_console_items, "\t");
-
- printf("%s Mandatory Items:\n", draw_special_char(DRAW_ARROW));
- dump_items(p->mandatory_items, "\t");
-
- fflush(stdout);
-}
-
-int shared_policy_new(SharedPolicy **out) {
- SharedPolicy *sp;
- int r;
-
- sp = new0(SharedPolicy, 1);
- if (!sp)
- return log_oom();
-
- r = pthread_mutex_init(&sp->lock, NULL);
- 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) {
- r = log_error_errno(r, "Cannot initialize shared policy rwlock: %m");
- goto exit_mutex;
- }
-
- *out = sp;
- sp = NULL;
- return 0;
-
- /* pthread lock destruction is not fail-safe... meh! */
-exit_mutex:
- pthread_mutex_destroy(&sp->lock);
-exit_free:
- free(sp);
- return r;
-}
-
-SharedPolicy *shared_policy_free(SharedPolicy *sp) {
- if (!sp)
- return NULL;
-
- policy_free(sp->policy);
- pthread_rwlock_destroy(&sp->rwlock);
- pthread_mutex_destroy(&sp->lock);
- strv_free(sp->configuration);
- free(sp);
-
- return NULL;
-}
-
-static int shared_policy_reload_unlocked(SharedPolicy *sp, char **configuration) {
- Policy old, buffer = {};
- bool free_old;
- int r;
-
- assert(sp);
-
- r = policy_load(&buffer, configuration);
- if (r < 0)
- return log_error_errno(r, "Failed to load policy: %m");
-
- log_debug("Reloading configuration");
- /* policy_dump(&buffer); */
-
- pthread_rwlock_wrlock(&sp->rwlock);
- memcpy(&old, &sp->buffer, sizeof(old));
- memcpy(&sp->buffer, &buffer, sizeof(buffer));
- free_old = !!sp->policy;
- sp->policy = &sp->buffer;
- pthread_rwlock_unlock(&sp->rwlock);
-
- if (free_old)
- policy_free(&old);
-
- return 0;
-}
-
-int shared_policy_reload(SharedPolicy *sp) {
- int r;
-
- assert(sp);
-
- pthread_mutex_lock(&sp->lock);
- r = shared_policy_reload_unlocked(sp, sp->configuration);
- pthread_mutex_unlock(&sp->lock);
-
- return r;
-}
-
-int shared_policy_preload(SharedPolicy *sp, char **configuration) {
- _cleanup_strv_free_ char **conf = NULL;
- int r = 0;
-
- assert(sp);
-
- conf = strv_copy(configuration);
- if (!conf)
- return log_oom();
-
- pthread_mutex_lock(&sp->lock);
- if (!sp->policy) {
- r = shared_policy_reload_unlocked(sp, conf);
- if (r >= 0) {
- sp->configuration = conf;
- conf = NULL;
- }
- }
- pthread_mutex_unlock(&sp->lock);
-
- return r;
-}
-
-Policy *shared_policy_acquire(SharedPolicy *sp) {
- assert(sp);
-
- pthread_rwlock_rdlock(&sp->rwlock);
- if (sp->policy)
- return sp->policy;
- pthread_rwlock_unlock(&sp->rwlock);
-
- return NULL;
-}
-
-void shared_policy_release(SharedPolicy *sp, Policy *p) {
- assert(sp);
- assert(!p || sp->policy == p);
-
- if (p)
- pthread_rwlock_unlock(&sp->rwlock);
-}
-
-static const char* const policy_item_type_table[_POLICY_ITEM_TYPE_MAX] = {
- [_POLICY_ITEM_TYPE_UNSET] = "unset",
- [POLICY_ITEM_ALLOW] = "allow",
- [POLICY_ITEM_DENY] = "deny",
-};
-DEFINE_STRING_TABLE_LOOKUP(policy_item_type, PolicyItemType);
-
-static const char* const policy_item_class_table[_POLICY_ITEM_CLASS_MAX] = {
- [_POLICY_ITEM_CLASS_UNSET] = "unset",
- [POLICY_ITEM_SEND] = "send",
- [POLICY_ITEM_RECV] = "recv",
- [POLICY_ITEM_OWN] = "own",
- [POLICY_ITEM_OWN_PREFIX] = "own-prefix",
- [POLICY_ITEM_USER] = "user",
- [POLICY_ITEM_GROUP] = "group",
- [POLICY_ITEM_IGNORE] = "ignore",
-};
-DEFINE_STRING_TABLE_LOOKUP(policy_item_class, PolicyItemClass);
diff --git a/src/libbus-proxy-core/bus-xml-policy.h b/src/libbus-proxy-core/bus-xml-policy.h
deleted file mode 100644
index 3dcddaa048..0000000000
--- a/src/libbus-proxy-core/bus-xml-policy.h
+++ /dev/null
@@ -1,147 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2013 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 <pthread.h>
-
-#include "hashmap.h"
-#include "list.h"
-
-typedef enum PolicyItemType {
- _POLICY_ITEM_TYPE_UNSET = 0,
- POLICY_ITEM_ALLOW,
- POLICY_ITEM_DENY,
- _POLICY_ITEM_TYPE_MAX,
- _POLICY_ITEM_TYPE_INVALID = -1,
-} PolicyItemType;
-
-typedef enum PolicyItemClass {
- _POLICY_ITEM_CLASS_UNSET = 0,
- POLICY_ITEM_SEND,
- POLICY_ITEM_RECV,
- POLICY_ITEM_OWN,
- POLICY_ITEM_OWN_PREFIX,
- POLICY_ITEM_USER,
- POLICY_ITEM_GROUP,
- POLICY_ITEM_IGNORE,
- _POLICY_ITEM_CLASS_MAX,
- _POLICY_ITEM_CLASS_INVALID = -1,
-} PolicyItemClass;
-
-typedef struct PolicyItem PolicyItem;
-
-struct PolicyItem {
- PolicyItemType type;
- PolicyItemClass class;
- char *interface;
- char *member;
- char *error;
- char *path;
- char *name;
- uint8_t message_type;
- uid_t uid;
- gid_t gid;
-
- bool uid_valid, gid_valid;
-
- LIST_FIELDS(PolicyItem, items);
-};
-
-typedef struct Policy {
- LIST_HEAD(PolicyItem, default_items);
- LIST_HEAD(PolicyItem, mandatory_items);
- LIST_HEAD(PolicyItem, on_console_items);
- LIST_HEAD(PolicyItem, no_console_items);
- Hashmap *user_items;
- Hashmap *group_items;
-} Policy;
-
-typedef struct SharedPolicy {
- char **configuration;
- pthread_mutex_t lock;
- pthread_rwlock_t rwlock;
- Policy buffer;
- Policy *policy;
-} SharedPolicy;
-
-/* policy */
-
-int policy_load(Policy *p, char **files);
-void policy_free(Policy *p);
-
-bool policy_check_own(Policy *p, uid_t uid, gid_t gid, const char *name);
-bool policy_check_hello(Policy *p, uid_t uid, gid_t gid);
-bool policy_check_one_recv(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- const char *name,
- const char *path,
- const char *interface,
- const char *member);
-bool policy_check_recv(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- Set *names,
- char **namesv,
- const char *path,
- const char *interface,
- const char *member,
- bool dbus_to_kernel);
-bool policy_check_one_send(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- const char *name,
- const char *path,
- const char *interface,
- const char *member);
-bool policy_check_send(Policy *p,
- uid_t uid,
- gid_t gid,
- int message_type,
- Set *names,
- char **namesv,
- const char *path,
- const char *interface,
- const char *member,
- bool dbus_to_kernel,
- char **out_used_name);
-
-void policy_dump(Policy *p);
-
-const char* policy_item_type_to_string(PolicyItemType t) _const_;
-PolicyItemType policy_item_type_from_string(const char *s) _pure_;
-
-const char* policy_item_class_to_string(PolicyItemClass t) _const_;
-PolicyItemClass policy_item_class_from_string(const char *s) _pure_;
-
-/* shared policy */
-
-int shared_policy_new(SharedPolicy **out);
-SharedPolicy *shared_policy_free(SharedPolicy *sp);
-
-int shared_policy_reload(SharedPolicy *sp);
-int shared_policy_preload(SharedPolicy *sp, char **configuration);
-Policy *shared_policy_acquire(SharedPolicy *sp);
-void shared_policy_release(SharedPolicy *sp, Policy *p);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(SharedPolicy*, shared_policy_free);
diff --git a/src/libbus-proxy-core/driver.c b/src/libbus-proxy-core/driver.c
deleted file mode 100644
index 133b2e0f39..0000000000
--- a/src/libbus-proxy-core/driver.c
+++ /dev/null
@@ -1,745 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2013 Daniel Mack
- Copyright 2014 Kay Sievers
-
- 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 <stddef.h>
-#include <string.h>
-
-#include <systemd/sd-bus.h>
-
-#include "alloc-util.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "driver.h"
-#include "env-util.h"
-#include "proxy.h"
-#include "set.h"
-#include "strv.h"
-#include "synthesize.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_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
- int r;
-
- assert(bus);
- assert(name);
- assert(_creds);
-
- r = sd_bus_get_name_creds(bus, name, mask, &c);
- if (r == -ESRCH || r == -ENXIO)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", name);
- if (r < 0)
- return r;
-
- *_creds = c;
- c = NULL;
-
- return 0;
-}
-
-static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) {
- const char *name;
- int r;
-
- assert(bus);
- assert(m);
- assert(_creds);
-
- r = sd_bus_message_read(m, "s", &name);
- if (r < 0)
- return r;
-
- return get_creds_by_name(bus, name, mask, _creds, error);
-}
-
-static int driver_activation(sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- ProxyActivation *activation = userdata;
-
- /*
- * The org.freedesktop.DBus.Peer.Ping() call returned. We don't care
- * whether this succeeded, failed, was not implemented or timed out. We
- * cannot assume that the target reacts to this properly. Hence, just
- * send the reply to the activation request and be done.
- */
-
- m = activation->request; /* claim reference */
-
- --activation->proxy->n_activations;
- LIST_REMOVE(activations_by_proxy, activation->proxy->activations, activation);
- sd_bus_slot_unref(activation->slot);
- free(activation);
-
- return synthetic_reply_method_return(m, "u", BUS_START_REPLY_SUCCESS);
-}
-
-int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names) {
- int r;
-
- assert(a);
- assert(b);
- assert(m);
-
- if (!a->is_kernel)
- return 0;
-
- if (!streq_ptr(sd_bus_message_get_destination(m), "org.freedesktop.DBus"))
- return 0;
-
- /* The "Hello()" call is is handled in process_hello() */
-
- if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus.Introspectable", "Introspect")) {
-
- if (!sd_bus_message_has_signature(m, ""))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- return synthetic_reply_method_return(m, "s",
- "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
- "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
- "<node>\n"
- " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
- " <method name=\"Introspect\">\n"
- " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
- " </method>\n"
- " </interface>\n"
- " <interface name=\"org.freedesktop.DBus\">\n"
- " <method name=\"AddMatch\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " </method>\n"
- " <method name=\"RemoveMatch\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " </method>\n"
- " <method name=\"GetConnectionCredentials\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"a{sv}\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"ay\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"GetConnectionUnixProcessID\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"u\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"GetConnectionUnixUser\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"u\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"GetId\">\n"
- " <arg type=\"s\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"GetNameOwner\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"s\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"Hello\">\n"
- " <arg type=\"s\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"ListActivatableNames\">\n"
- " <arg type=\"as\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"ListNames\">\n"
- " <arg type=\"as\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"ListQueuedOwners\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"as\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"NameHasOwner\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"b\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"ReleaseName\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"u\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"ReloadConfig\">\n"
- " </method>\n"
- " <method name=\"RequestName\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"u\" direction=\"in\"/>\n"
- " <arg type=\"u\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"StartServiceByName\">\n"
- " <arg type=\"s\" direction=\"in\"/>\n"
- " <arg type=\"u\" direction=\"in\"/>\n"
- " <arg type=\"u\" direction=\"out\"/>\n"
- " </method>\n"
- " <method name=\"UpdateActivationEnvironment\">\n"
- " <arg type=\"a{ss}\" direction=\"in\"/>\n"
- " </method>\n"
- " <signal name=\"NameAcquired\">\n"
- " <arg type=\"s\"/>\n"
- " </signal>\n"
- " <signal name=\"NameLost\">\n"
- " <arg type=\"s\"/>\n"
- " </signal>\n"
- " <signal name=\"NameOwnerChanged\">\n"
- " <arg type=\"s\"/>\n"
- " <arg type=\"s\"/>\n"
- " <arg type=\"s\"/>\n"
- " </signal>\n"
- " </interface>\n"
- "</node>\n");
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "AddMatch")) {
- const char *match;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "s", &match);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_add_match(a, NULL, match, proxy_match, p);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_reply_method_return(m, NULL);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RemoveMatch")) {
- const char *match;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "s", &match);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = bus_remove_match_by_string(a, match, NULL, NULL);
- if (r == 0)
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule not found"));
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_reply_method_return(m, NULL);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionCredentials")) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = get_creds_by_message(a, m, SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, &error);
-
- r = sd_bus_message_new_method_return(m, &reply);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_open_container(reply, 'a', "{sv}");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- /* Due to i.e. namespace translations some data might be missing */
-
- if (creds->mask & SD_BUS_CREDS_PID) {
- r = sd_bus_message_append(reply, "{sv}", "ProcessID", "u", (uint32_t) creds->pid);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- if (creds->mask & SD_BUS_CREDS_EUID) {
- r = sd_bus_message_append(reply, "{sv}", "UnixUserID", "u", (uint32_t) creds->euid);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- if (creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT) {
- r = sd_bus_message_open_container(reply, 'e', "sv");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_append(reply, "s", "LinuxSecurityLabel");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_open_container(reply, 'v', "ay");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_driver_send(m->bus, reply);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = get_creds_by_message(a, m, SD_BUS_CREDS_SELINUX_CONTEXT, &creds, &error);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, &error);
-
- if (!(creds->mask & SD_BUS_CREDS_SELINUX_CONTEXT))
- return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
-
- r = sd_bus_message_new_method_return(m, &reply);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_append_array(reply, 'y', creds->label, strlen(creds->label));
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_driver_send(m->bus, reply);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = get_creds_by_message(a, m, SD_BUS_CREDS_PID, &creds, &error);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, &error);
-
- if (!(creds->mask & SD_BUS_CREDS_PID))
- return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
-
- return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = get_creds_by_message(a, m, SD_BUS_CREDS_EUID, &creds, &error);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, &error);
-
- if (!(creds->mask & SD_BUS_CREDS_EUID))
- return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
-
- return synthetic_reply_method_return(m, "u", (uint32_t) creds->euid);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetId")) {
- sd_id128_t server_id;
- char buf[SD_ID128_STRING_MAX];
-
- if (!sd_bus_message_has_signature(m, ""))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_get_bus_id(a, &server_id);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_reply_method_return(m, "s", sd_id128_to_string(server_id, buf));
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) {
- const char *name;
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "s", &name);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- if (streq(name, "org.freedesktop.DBus"))
- return synthetic_reply_method_return(m, "s", "org.freedesktop.DBus");
-
- r = get_creds_by_name(a, name, SD_BUS_CREDS_UNIQUE_NAME, &creds, &error);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, &error);
-
- if (!(creds->mask & SD_BUS_CREDS_UNIQUE_NAME))
- return synthetic_reply_method_errno(m, -EOPNOTSUPP, NULL);
-
- return synthetic_reply_method_return(m, "s", creds->unique_name);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListActivatableNames")) {
- _cleanup_strv_free_ char **names = NULL;
-
- if (!sd_bus_message_has_signature(m, ""))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_list_names(a, NULL, &names);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- /* Let's sort the names list to make it stable */
- strv_sort(names);
-
- return synthetic_reply_method_return_strv(m, names);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListNames")) {
- _cleanup_strv_free_ char **names = NULL;
-
- if (!sd_bus_message_has_signature(m, ""))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_list_names(a, &names, NULL);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = strv_extend(&names, "org.freedesktop.DBus");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- /* Let's sort the names list to make it stable */
- strv_sort(names);
-
- return synthetic_reply_method_return_strv(m, names);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ListQueuedOwners")) {
- struct kdbus_cmd_list cmd = {
- .flags = KDBUS_LIST_QUEUED,
- .size = sizeof(cmd),
- };
- struct kdbus_info *name_list, *name;
- _cleanup_strv_free_ char **owners = NULL;
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- char *arg0;
- int err = 0;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "s", &arg0);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_get_name_creds(a, arg0, 0, NULL);
- if (r == -ESRCH || r == -ENXIO) {
- sd_bus_error_setf(&error, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owners of name '%s': no such name.", arg0);
- return synthetic_reply_method_errno(m, r, &error);
- }
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = ioctl(a->input_fd, KDBUS_CMD_LIST, &cmd);
- if (r < 0)
- return synthetic_reply_method_errno(m, -errno, NULL);
-
- name_list = (struct kdbus_info *) ((uint8_t *) a->kdbus_buffer + cmd.offset);
-
- KDBUS_FOREACH(name, name_list, cmd.list_size) {
- struct kdbus_item *item;
- char *n;
-
- KDBUS_ITEM_FOREACH(item, name, items) {
- if (item->type == KDBUS_ITEM_OWNED_NAME) {
- if (!streq_ptr(item->name.name, arg0))
- continue;
-
- if (asprintf(&n, ":1.%llu", (unsigned long long) name->id) < 0) {
- err = -ENOMEM;
- break;
- }
-
- r = strv_consume(&owners, n);
- if (r < 0) {
- err = r;
- break;
- }
- }
- }
-
- if (err < 0)
- break;
- }
-
- r = bus_kernel_cmd_free(a, cmd.offset);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- if (err < 0)
- return synthetic_reply_method_errno(m, err, NULL);
-
- return synthetic_reply_method_return_strv(m, owners);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "NameHasOwner")) {
- const char *name;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "s", &name);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- if (streq(name, "org.freedesktop.DBus"))
- return synthetic_reply_method_return(m, "b", true);
-
- r = sd_bus_get_name_creds(a, name, 0, NULL);
- if (r < 0 && r != -ESRCH && r != -ENXIO)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_reply_method_return(m, "b", r >= 0);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReleaseName")) {
- const char *name;
-
- if (!sd_bus_message_has_signature(m, "s"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "s", &name);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_release_name(a, name);
- if (r < 0) {
- if (r == -ESRCH)
- return synthetic_reply_method_return(m, "u", BUS_NAME_NON_EXISTENT);
- if (r == -EADDRINUSE)
- return synthetic_reply_method_return(m, "u", BUS_NAME_NOT_OWNER);
-
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- set_remove(owned_names, (char*) name);
-
- return synthetic_reply_method_return(m, "u", BUS_NAME_RELEASED);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "ReloadConfig")) {
- if (!sd_bus_message_has_signature(m, ""))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = shared_policy_reload(sp);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_reply_method_return(m, NULL);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "RequestName")) {
- const char *name;
- uint32_t flags, param;
- bool in_queue;
-
- if (!sd_bus_message_has_signature(m, "su"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "su", &name, &flags);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- if (sp) {
- Policy *policy;
- bool denied;
-
- policy = shared_policy_acquire(sp);
- denied = !policy_check_own(policy, ucred->uid, ucred->gid, name);
- shared_policy_release(sp, policy);
- if (denied)
- return synthetic_reply_method_errno(m, -EPERM, NULL);
- }
-
- if ((flags & ~(BUS_NAME_ALLOW_REPLACEMENT|BUS_NAME_REPLACE_EXISTING|BUS_NAME_DO_NOT_QUEUE)) != 0)
- return synthetic_reply_method_errno(m, -EINVAL, NULL);
-
- param = 0;
- if (flags & BUS_NAME_ALLOW_REPLACEMENT)
- param |= SD_BUS_NAME_ALLOW_REPLACEMENT;
- if (flags & BUS_NAME_REPLACE_EXISTING)
- param |= SD_BUS_NAME_REPLACE_EXISTING;
- if (!(flags & BUS_NAME_DO_NOT_QUEUE))
- param |= SD_BUS_NAME_QUEUE;
-
- r = set_put_strdup(owned_names, name);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_request_name(a, name, param);
- if (r < 0) {
- if (r == -EALREADY)
- return synthetic_reply_method_return(m, "u", BUS_NAME_ALREADY_OWNER);
-
- set_remove(owned_names, (char*) name);
-
- if (r == -EEXIST)
- return synthetic_reply_method_return(m, "u", BUS_NAME_EXISTS);
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- in_queue = (r == 0);
-
- if (in_queue)
- return synthetic_reply_method_return(m, "u", BUS_NAME_IN_QUEUE);
-
- return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER);
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL;
- ProxyActivation *activation;
- const char *name;
- uint64_t cookie;
- uint32_t flags;
-
- if (!sd_bus_message_has_signature(m, "su"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_read(m, "su", &name, &flags);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- if (flags != 0)
- return synthetic_reply_method_errno(m, -EINVAL, NULL);
-
- r = sd_bus_get_name_creds(a, name, 0, NULL);
- if (r >= 0 || streq(name, "org.freedesktop.DBus"))
- return synthetic_reply_method_return(m, "u", BUS_START_REPLY_ALREADY_RUNNING);
- if (r != -ESRCH)
- return synthetic_reply_method_errno(m, r, NULL);
-
- if (p->n_activations >= PROXY_ACTIVATIONS_MAX)
- return synthetic_reply_method_errno(m, -EMFILE, NULL);
-
- r = sd_bus_message_get_cookie(m, &cookie);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_new_method_call(a,
- &msg,
- name,
- "/",
- "org.freedesktop.DBus.Peer",
- "Ping");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = bus_message_seal(msg, cookie, BUS_DEFAULT_TIMEOUT);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- activation = new0(ProxyActivation, 1);
- if (!activation)
- return synthetic_reply_method_errno(m, -ENOMEM, NULL);
-
- r = sd_bus_call_async(a,
- &activation->slot,
- msg,
- driver_activation,
- activation,
- 0);
- if (r < 0) {
- free(activation);
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- activation->proxy = p;
- activation->request = sd_bus_message_ref(m);
- LIST_PREPEND(activations_by_proxy, p->activations, activation);
- ++p->n_activations;
- return 1;
-
- } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL;
- _cleanup_strv_free_ char **args = NULL;
-
- if (!sd_bus_message_has_signature(m, "a{ss}"))
- return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters"));
-
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{ss}");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- while ((r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "ss")) > 0) {
- _cleanup_free_ char *s = NULL;
- const char *key;
- const char *value;
-
- r = sd_bus_message_read(m, "ss", &key, &value);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- s = strjoin(key, "=", value, NULL);
- if (!s)
- return synthetic_reply_method_errno(m, -ENOMEM, NULL);
-
- if (!env_assignment_is_valid(s)) {
- log_warning("UpdateActivationEnvironment() called with invalid assignment, discarding: %s", s);
- } else {
- r = strv_extend(&args, s);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
- }
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- if (strv_isempty(args)) /* nothing to do? */
- return synthetic_reply_method_return(m, NULL);
-
- r = sd_bus_message_new_method_call(
- a,
- &msg,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "SetEnvironment");
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_message_append_strv(msg, args);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- r = sd_bus_call(a, msg, 0, NULL, NULL);
- if (r < 0)
- return synthetic_reply_method_errno(m, r, NULL);
-
- return synthetic_reply_method_return(m, NULL);
-
- } else {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member);
-
- return synthetic_reply_method_errno(m, r, &error);
- }
-}
diff --git a/src/libbus-proxy-core/proxy.c b/src/libbus-proxy-core/proxy.c
deleted file mode 100644
index bcfbab0dad..0000000000
--- a/src/libbus-proxy-core/proxy.c
+++ /dev/null
@@ -1,953 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2013 Daniel Mack
- Copyright 2014 Kay Sievers
- Copyright 2014 David Herrmann
-
- 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 <poll.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <systemd/sd-bus.h>
-#include <systemd/sd-daemon.h>
-
-#include "alloc-util.h"
-#include "bus-control.h"
-#include "bus-internal.h"
-#include "bus-message.h"
-#include "bus-util.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 "user-util.h"
-#include "util.h"
-
-static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *b = NULL;
- int r;
-
- r = sd_bus_new(&b);
- if (r < 0)
- return log_error_errno(r, "Failed to allocate bus: %m");
-
- r = sd_bus_set_description(b, "sd-proxy");
- if (r < 0)
- return log_error_errno(r, "Failed to set bus name: %m");
-
- r = sd_bus_set_address(b, destination);
- if (r < 0)
- return log_error_errno(r, "Failed to set address to connect to: %m");
-
- r = sd_bus_negotiate_fds(b, negotiate_fds);
- if (r < 0)
- return log_error_errno(r, "Failed to set FD negotiation: %m");
-
- r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
- if (r < 0)
- return log_error_errno(r, "Failed to set credential negotiation: %m");
-
- if (p->local_creds.pid > 0) {
- b->fake_pids.pid = p->local_creds.pid;
- b->fake_pids_valid = true;
-
- b->fake_creds.uid = UID_INVALID;
- b->fake_creds.euid = p->local_creds.uid;
- b->fake_creds.suid = UID_INVALID;
- b->fake_creds.fsuid = UID_INVALID;
- b->fake_creds.gid = GID_INVALID;
- b->fake_creds.egid = p->local_creds.gid;
- b->fake_creds.sgid = GID_INVALID;
- b->fake_creds.fsgid = GID_INVALID;
- b->fake_creds_valid = true;
- }
-
- if (local_sec) {
- b->fake_label = strdup(local_sec);
- if (!b->fake_label)
- return log_oom();
- }
-
- b->manual_peer_interface = true;
-
- r = sd_bus_start(b);
- if (r < 0)
- return log_error_errno(r, "Failed to start bus client: %m");
-
- p->destination_bus = b;
- b = NULL;
- return 0;
-}
-
-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, 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)
- return log_error_errno(r, "Failed to get server ID: %m");
-
- r = sd_bus_set_server(b, 1, server_id);
- if (r < 0)
- return log_error_errno(r, "Failed to set server mode: %m");
-
- r = sd_bus_negotiate_fds(b, negotiate_fds);
- if (r < 0)
- return log_error_errno(r, "Failed to set FD negotiation: %m");
-
- r = sd_bus_negotiate_creds(b, true, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SELINUX_CONTEXT);
- if (r < 0)
- return log_error_errno(r, "Failed to set credential negotiation: %m");
-
- r = sd_bus_set_anonymous(b, true);
- if (r < 0)
- return log_error_errno(r, "Failed to set anonymous authentication: %m");
-
- b->manual_peer_interface = true;
-
- r = sd_bus_start(b);
- if (r < 0)
- return log_error_errno(r, "Failed to start bus client: %m");
-
- return 0;
-}
-
-static int proxy_match_synthetic(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- Proxy *p = userdata;
-
- p->synthetic_matched = true;
- return 0; /* make sure to continue processing it in further handlers */
-}
-
-/*
- * We always need NameOwnerChanged so we can synthesize NameLost and
- * NameAcquired. Furthermore, dbus-1 always passes unicast-signals through, so
- * subscribe unconditionally.
- */
-static int proxy_prepare_matches(Proxy *p) {
- _cleanup_free_ char *match = NULL;
- const char *unique;
- int r;
-
- if (!p->destination_bus->is_kernel)
- return 0;
-
- r = sd_bus_get_unique_name(p->destination_bus, &unique);
- if (r < 0)
- return log_error_errno(r, "Failed to get unique name: %m");
-
- match = strjoin("type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged',"
- "arg1='",
- unique,
- "'",
- NULL);
- if (!match)
- return log_oom();
-
- r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
- if (r < 0)
- return log_error_errno(r, "Failed to add match for NameLost: %m");
-
- free(match);
- match = strjoin("type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged',"
- "arg2='",
- unique,
- "'",
- NULL);
- if (!match)
- return log_oom();
-
- r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
- if (r < 0)
- return log_error_errno(r, "Failed to add match for NameAcquired: %m");
-
- free(match);
- match = strjoin("type='signal',"
- "destination='",
- unique,
- "'",
- NULL);
- if (!match)
- return log_oom();
-
- r = sd_bus_add_match(p->destination_bus, NULL, match, proxy_match_synthetic, p);
- if (r < 0)
- log_error_errno(r, "Failed to add match for directed signals: %m");
- /* FIXME: temporarily ignore error to support older kdbus versions */
-
- return 0;
-}
-
-int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) {
- _cleanup_(proxy_freep) Proxy *p = NULL;
- _cleanup_free_ char *local_sec = NULL;
- 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) {
- safe_close(in_fd);
- safe_close(out_fd);
- return log_oom();
- }
-
- p->local_in = in_fd;
- p->local_out = out_fd;
-
- p->owned_names = set_new(&string_hash_ops);
- if (!p->owned_names)
- return log_oom();
-
- is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
- sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
-
- if (is_unix) {
- (void) getpeercred(in_fd, &p->local_creds);
- (void) getpeersec(in_fd, &local_sec);
- }
-
- r = proxy_create_destination(p, destination, local_sec, is_unix);
- if (r < 0)
- return r;
-
- r = proxy_create_local(p, is_unix);
- if (r < 0)
- return r;
-
- r = proxy_prepare_matches(p);
- if (r < 0)
- return r;
-
- *out = p;
- p = NULL;
-
- return 0;
-}
-
-Proxy *proxy_free(Proxy *p) {
- ProxyActivation *activation;
-
- if (!p)
- return NULL;
-
- while ((activation = p->activations)) {
- LIST_REMOVE(activations_by_proxy, p->activations, activation);
- sd_bus_message_unref(activation->request);
- sd_bus_slot_unref(activation->slot);
- free(activation);
- }
-
- 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);
-
- return NULL;
-}
-
-int proxy_set_policy(Proxy *p, SharedPolicy *sp, char **configuration) {
- _cleanup_strv_free_ char **strv = NULL;
- Policy *policy;
- int r;
-
- assert(p);
- assert(sp);
-
- /* no need to load legacy policy if destination is not kdbus */
- if (!p->destination_bus->is_kernel)
- return 0;
-
- p->policy = sp;
-
- policy = shared_policy_acquire(sp);
- if (policy) {
- /* policy already pre-loaded */
- shared_policy_release(sp, policy);
- return 0;
- }
-
- if (!configuration) {
- const char *scope;
-
- r = sd_bus_get_scope(p->destination_bus, &scope);
- if (r < 0)
- return log_error_errno(r, "Couldn't determine bus scope: %m");
-
- if (streq(scope, "system"))
- strv = strv_new("/usr/share/dbus-1/system.conf",
- "/etc/dbus-1/system.conf",
- "/usr/share/dbus-1/system.d/",
- "/etc/dbus-1/system.d/",
- "/etc/dbus-1/system-local.conf",
- NULL);
- else if (streq(scope, "user"))
- strv = strv_new("/usr/share/dbus-1/session.conf",
- "/etc/dbus-1/session.conf",
- "/usr/share/dbus-1/session.d/",
- "/etc/dbus-1/session.d/",
- "/etc/dbus-1/session-local.conf",
- NULL);
- else
- return log_error("Unknown scope %s, don't know which policy to load. Refusing.", scope);
-
- if (!strv)
- return log_oom();
-
- configuration = strv;
- }
-
- return shared_policy_preload(sp, configuration);
-}
-
-int proxy_hello_policy(Proxy *p, uid_t original_uid) {
- Policy *policy;
- int r = 0;
-
- assert(p);
-
- if (!p->policy)
- return 0;
-
- policy = shared_policy_acquire(p->policy);
-
- if (p->local_creds.uid == original_uid)
- log_debug("Permitting access, since bus owner matches bus client.");
- else if (policy_check_hello(policy, p->local_creds.uid, p->local_creds.gid))
- log_debug("Permitting access due to XML policy.");
- else
- r = log_error_errno(EPERM, "Policy denied connection.");
-
- shared_policy_release(p->policy, policy);
-
- return r;
-}
-
-static int proxy_wait(Proxy *p) {
- uint64_t timeout_destination, timeout_local, t;
- int events_destination, events_local, fd;
- struct timespec _ts, *ts;
- struct pollfd *pollfd;
- int r;
-
- assert(p);
-
- fd = sd_bus_get_fd(p->destination_bus);
- if (fd < 0)
- return log_error_errno(fd, "Failed to get fd: %m");
-
- events_destination = sd_bus_get_events(p->destination_bus);
- if (events_destination < 0)
- return log_error_errno(events_destination, "Failed to get events mask: %m");
-
- r = sd_bus_get_timeout(p->destination_bus, &timeout_destination);
- if (r < 0)
- return log_error_errno(r, "Failed to get timeout: %m");
-
- events_local = sd_bus_get_events(p->local_bus);
- if (events_local < 0)
- return log_error_errno(events_local, "Failed to get events mask: %m");
-
- r = sd_bus_get_timeout(p->local_bus, &timeout_local);
- if (r < 0)
- return log_error_errno(r, "Failed to get timeout: %m");
-
- t = timeout_destination;
- if (t == (uint64_t) -1 || (timeout_local != (uint64_t) -1 && timeout_local < timeout_destination))
- t = timeout_local;
-
- if (t == (uint64_t) -1)
- ts = NULL;
- else {
- usec_t nw;
-
- nw = now(CLOCK_MONOTONIC);
- if (t > nw)
- t -= nw;
- else
- t = 0;
-
- ts = timespec_store(&_ts, t);
- }
-
- pollfd = (struct pollfd[3]) {
- { .fd = fd, .events = events_destination, },
- { .fd = p->local_in, .events = events_local & POLLIN, },
- { .fd = p->local_out, .events = events_local & POLLOUT, },
- };
-
- r = ppoll(pollfd, 3, ts, NULL);
- if (r < 0)
- return log_error_errno(errno, "ppoll() failed: %m");
-
- return 0;
-}
-
-static int handle_policy_error(sd_bus_message *m, int r) {
- if (r == -ESRCH || r == -ENXIO)
- return synthetic_reply_method_errorf(m, SD_BUS_ERROR_NAME_HAS_NO_OWNER, "Name %s is currently not owned by anyone.", m->destination);
-
- return r;
-}
-
-static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, Policy *policy, const struct ucred *our_ucred, Set *owned_names) {
- int r;
-
- assert(from);
- assert(to);
- assert(m);
-
- if (!policy)
- return 0;
-
- /*
- * dbus-1 distinguishes expected and non-expected replies by tracking
- * method-calls and timeouts. By default, DENY rules are *NEVER* applied
- * on expected replies, unless explicitly specified. But we dont track
- * method-calls, thus, we cannot know whether a reply is expected.
- * Fortunately, the kdbus forbids non-expected replies, so we can safely
- * ignore any policy on those and let the kernel deal with it.
- *
- * TODO: To be correct, we should only ignore policy-tags that are
- * applied on non-expected replies. However, so far we don't parse those
- * tags so we let everything pass. I haven't seen a DENY policy tag on
- * expected-replies, ever, so don't bother..
- */
- if (m->reply_cookie > 0)
- return 0;
-
- if (from->is_kernel) {
- uid_t sender_uid = UID_INVALID;
- gid_t sender_gid = GID_INVALID;
- char **sender_names = NULL;
-
- /* Driver messages are always OK */
- if (streq_ptr(m->sender, "org.freedesktop.DBus"))
- return 0;
-
- /* The message came from the kernel, and is sent to our legacy client. */
- (void) sd_bus_creds_get_well_known_names(&m->creds, &sender_names);
-
- (void) sd_bus_creds_get_euid(&m->creds, &sender_uid);
- (void) sd_bus_creds_get_egid(&m->creds, &sender_gid);
-
- if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *sender_creds = NULL;
-
- /* If the message came from another legacy
- * client, then the message creds will be
- * missing, simply because on legacy clients
- * per-message creds were unknown. In this
- * case, query the creds of the peer
- * instead. */
-
- r = bus_get_name_creds_kdbus(from, m->sender, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID, true, &sender_creds);
- if (r < 0)
- return handle_policy_error(m, r);
-
- (void) sd_bus_creds_get_euid(sender_creds, &sender_uid);
- (void) sd_bus_creds_get_egid(sender_creds, &sender_gid);
- }
-
- /* First check whether the sender can send the message to our name */
- if (policy_check_send(policy, sender_uid, sender_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, false, NULL) &&
- policy_check_recv(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, sender_names, m->path, m->interface, m->member, false))
- return 0;
-
- /* Return an error back to the caller */
- if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
- return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML receiver policy.");
-
- /* Return 1, indicating that the message shall not be processed any further */
- return 1;
- }
-
- if (to->is_kernel) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *destination_creds = NULL;
- uid_t destination_uid = UID_INVALID;
- gid_t destination_gid = GID_INVALID;
- const char *destination_unique = NULL;
- char **destination_names = NULL;
- char *n;
-
- /* Driver messages are always OK */
- if (streq_ptr(m->destination, "org.freedesktop.DBus"))
- return 0;
-
- /* The message came from the legacy client, and is sent to kdbus. */
- if (m->destination) {
- r = bus_get_name_creds_kdbus(to, m->destination,
- SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME|
- SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID,
- true, &destination_creds);
- if (r < 0)
- return handle_policy_error(m, r);
-
- r = sd_bus_creds_get_unique_name(destination_creds, &destination_unique);
- if (r < 0)
- return handle_policy_error(m, r);
-
- (void) sd_bus_creds_get_well_known_names(destination_creds, &destination_names);
-
- (void) sd_bus_creds_get_euid(destination_creds, &destination_uid);
- (void) sd_bus_creds_get_egid(destination_creds, &destination_gid);
- }
-
- /* First check if we (the sender) can send to this name */
- if (sd_bus_message_is_signal(m, NULL, NULL)) {
- /* If we forward a signal from dbus-1 to kdbus, we have
- * no idea who the recipient is. Therefore, we cannot
- * apply any dbus-1 policies that match on receiver
- * credentials. We know sd-bus always sets
- * KDBUS_MSG_SIGNAL, so the kernel applies policies to
- * the message. Therefore, skip policy checks in this
- * case. */
- return 0;
- } else if (policy_check_send(policy, our_ucred->uid, our_ucred->gid, m->header->type, NULL, destination_names, m->path, m->interface, m->member, true, &n)) {
- if (n) {
- /* If we made a receiver decision, then remember which
- * name's policy we used, and to which unique ID it
- * mapped when we made the decision. Then, let's pass
- * this to the kernel when sending the message, so that
- * it refuses the operation should the name and unique
- * ID not map to each other anymore. */
-
- r = free_and_strdup(&m->destination_ptr, n);
- if (r < 0)
- return r;
-
- r = bus_kernel_parse_unique_name(destination_unique, &m->verify_destination_id);
- if (r < 0)
- return r;
- }
-
- if (policy_check_recv(policy, destination_uid, destination_gid, m->header->type, owned_names, NULL, m->path, m->interface, m->member, true))
- return 0;
- }
-
- /* Return an error back to the caller */
- if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
- return synthetic_reply_method_errorf(m, SD_BUS_ERROR_ACCESS_DENIED, "Access prohibited by XML sender policy.");
-
- /* Return 1, indicating that the message shall not be processed any further */
- return 1;
- }
-
- return 0;
-}
-
-static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPolicy *sp, const struct ucred *our_ucred, Set *owned_names) {
- Policy *policy;
- int r;
-
- assert(sp);
-
- policy = shared_policy_acquire(sp);
- r = process_policy_unlocked(from, to, m, policy, our_ucred, owned_names);
- shared_policy_release(sp, policy);
-
- return r;
-}
-
-static int process_hello(Proxy *p, sd_bus_message *m) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
- bool is_hello;
- int r;
-
- assert(p);
- assert(m);
-
- /* As reaction to hello we need to respond with two messages:
- * the callback reply and the NameAcquired for the unique
- * name, since hello is otherwise obsolete on kdbus. */
-
- is_hello =
- sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "Hello") &&
- streq_ptr(m->destination, "org.freedesktop.DBus");
-
- if (!is_hello) {
- if (p->got_hello)
- return 0;
-
- return log_error_errno(EIO, "First packet isn't hello (it's %s.%s), aborting.", m->interface, m->member);
- }
-
- if (p->got_hello)
- return log_error_errno(EIO, "Got duplicate hello, aborting.");
-
- p->got_hello = true;
-
- if (!p->destination_bus->is_kernel)
- return 0;
-
- r = sd_bus_message_new_method_return(m, &n);
- if (r < 0)
- return log_error_errno(r, "Failed to generate HELLO reply: %m");
-
- r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
- if (r < 0)
- return log_error_errno(r, "Failed to append unique name to HELLO reply: %m");
-
- r = bus_message_append_sender(n, "org.freedesktop.DBus");
- if (r < 0)
- return log_error_errno(r, "Failed to append sender to HELLO reply: %m");
-
- r = bus_seal_synthetic_message(p->local_bus, n);
- if (r < 0)
- return log_error_errno(r, "Failed to seal HELLO reply: %m");
-
- r = sd_bus_send(p->local_bus, n, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to send HELLO reply: %m");
-
- n = sd_bus_message_unref(n);
- r = sd_bus_message_new_signal(
- p->local_bus,
- &n,
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "NameAcquired");
- if (r < 0)
- return log_error_errno(r, "Failed to allocate initial NameAcquired message: %m");
-
- r = sd_bus_message_append(n, "s", p->destination_bus->unique_name);
- if (r < 0)
- return log_error_errno(r, "Failed to append unique name to NameAcquired message: %m");
-
- r = bus_message_append_sender(n, "org.freedesktop.DBus");
- if (r < 0)
- return log_error_errno(r, "Failed to append sender to NameAcquired message: %m");
-
- r = sd_bus_message_set_destination(n, p->destination_bus->unique_name);
- if (r < 0)
- return log_error_errno(r, "Failed to set destination for NameAcquired message: %m");
-
- r = bus_seal_synthetic_message(p->local_bus, n);
- if (r < 0)
- return log_error_errno(r, "Failed to seal NameAcquired message: %m");
-
- r = sd_bus_send(p->local_bus, n, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to send NameAcquired message: %m");
-
- return 1;
-}
-
-static int patch_sender(sd_bus *a, sd_bus_message *m) {
- char **well_known = NULL;
- sd_bus_creds *c;
- int r;
-
- assert(a);
- assert(m);
-
- if (!a->is_kernel)
- return 0;
-
- /* We will change the sender of messages from the bus driver
- * so that they originate from the bus driver. This is a
- * speciality originating from dbus1, where the bus driver did
- * not have a unique id, but only the well-known name. */
-
- c = sd_bus_message_get_creds(m);
- if (!c)
- return 0;
-
- r = sd_bus_creds_get_well_known_names(c, &well_known);
- if (r < 0)
- return r;
-
- if (strv_contains(well_known, "org.freedesktop.DBus"))
- m->sender = "org.freedesktop.DBus";
-
- return 0;
-}
-
-static int proxy_process_destination_to_local(Proxy *p) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- bool matched, matched_synthetic;
- int r;
-
- assert(p);
-
- /*
- * Usually, we would just take any message that the bus passes to us
- * and forward it to the local connection. However, there are actually
- * applications that fail if they receive broadcasts that they didn't
- * subscribe to. Therefore, we actually emulate a real broadcast
- * matching here, and discard any broadcasts that weren't matched. Our
- * match-handlers remembers whether a message was matched by any rule,
- * by marking it in @p->message_matched.
- */
-
- r = sd_bus_process(p->destination_bus, &m);
-
- matched = p->message_matched;
- matched_synthetic = p->synthetic_matched;
- p->message_matched = false;
- p->synthetic_matched = false;
-
- if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
- return r;
- if (r < 0) {
- log_error_errno(r, "Failed to process destination bus: %m");
- return r;
- }
- if (r == 0)
- return 0;
- if (!m)
- return 1;
-
- /* We officially got EOF, let's quit */
- if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
- return -ECONNRESET;
-
- r = synthesize_name_acquired(p, p->destination_bus, p->local_bus, m);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return r;
- if (r < 0)
- return log_error_errno(r, "Failed to synthesize message: %m");
-
- /* discard broadcasts that were not matched by any MATCH rule */
- if (!matched && !sd_bus_message_get_destination(m)) {
- if (!matched_synthetic)
- log_debug("Dropped unmatched broadcast: uid=" UID_FMT " gid=" GID_FMT " pid=" PID_FMT " message=%s path=%s interface=%s member=%s sender=%s destination=%s",
- p->local_creds.uid, p->local_creds.gid, p->local_creds.pid, bus_message_type_to_string(m->header->type),
- strna(m->path), strna(m->interface), strna(m->member), strna(m->sender), strna(m->destination));
- return 1;
- }
-
- patch_sender(p->destination_bus, m);
-
- if (p->policy) {
- r = process_policy(p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return r;
- if (r < 0)
- return log_error_errno(r, "Failed to process policy: %m");
- if (r > 0)
- return 1;
- }
-
- r = sd_bus_send(p->local_bus, m, NULL);
- if (r < 0) {
- if (r == -ECONNRESET || r == -ENOTCONN)
- return r;
-
- /* If the peer tries to send a reply and it is
- * rejected with EBADSLT by the kernel, we ignore the
- * error. This catches cases where the original
- * method-call didn't had EXPECT_REPLY set, but the
- * proxy-peer still sends a reply. This is allowed in
- * dbus1, but not in kdbus. We don't want to track
- * reply-windows in the proxy, so we simply ignore
- * EBADSLT for all replies. The only downside is, that
- * callers are no longer notified if their replies are
- * dropped. However, this is equivalent to the
- * caller's timeout to expire, so this should be
- * acceptable. Nobody sane sends replies without a
- * matching method-call, so nobody should care. */
-
- /* FIXME: remove -EPERM when kdbus is updated */
- if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
- return 1;
-
- /* Return the error to the client, if we can */
- synthetic_reply_method_errnof(m, r, "Failed to forward message we got from destination: %m");
- if (r == -ENOBUFS) {
- /* if local dbus1 peer does not dispatch its queue, warn only once */
- if (!p->queue_overflow)
- log_error("Dropped messages due to queue overflow of local peer (pid: "PID_FMT" uid: "UID_FMT")", p->local_creds.pid, p->local_creds.uid);
- p->queue_overflow = true;
- } else
- log_error_errno(r,
- "Failed to forward message we got from destination: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
- p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
- strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
-
- return 1;
- }
-
- p->queue_overflow = false;
- return 1;
-}
-
-static int proxy_process_local_to_destination(Proxy *p) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- int r;
-
- assert(p);
-
- r = sd_bus_process(p->local_bus, &m);
- if (r == -ECONNRESET || r == -ENOTCONN) /* Treat 'connection reset by peer' as clean exit condition */
- return r;
- if (r < 0) {
- log_error_errno(r, "Failed to process local bus: %m");
- return r;
- }
- if (r == 0)
- return 0;
- if (!m)
- return 1;
-
- /* We officially got EOF, let's quit */
- if (sd_bus_message_is_signal(m, "org.freedesktop.DBus.Local", "Disconnected"))
- return -ECONNRESET;
-
- r = process_hello(p, m);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return r;
- if (r < 0)
- return log_error_errno(r, "Failed to process HELLO: %m");
- if (r > 0)
- return 1;
-
- r = bus_proxy_process_driver(p, p->destination_bus, p->local_bus, m, p->policy, &p->local_creds, p->owned_names);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return r;
- if (r < 0)
- return log_error_errno(r, "Failed to process driver calls: %m");
- if (r > 0)
- return 1;
-
- for (;;) {
- if (p->policy) {
- r = process_policy(p->local_bus, p->destination_bus, m, p->policy, &p->local_creds, p->owned_names);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return r;
- if (r < 0)
- return log_error_errno(r, "Failed to process policy: %m");
- if (r > 0)
- return 1;
- }
-
- r = sd_bus_send(p->destination_bus, m, NULL);
- if (r < 0) {
- if (r == -ECONNRESET || r == -ENOTCONN)
- return r;
-
- /* The name database changed since the policy check, hence let's check again */
- if (r == -EREMCHG)
- continue;
-
- /* see above why EBADSLT is ignored for replies */
- if ((r == -EPERM || r == -EBADSLT) && m->reply_cookie > 0)
- return 1;
-
- synthetic_reply_method_errnof(m, r, "Failed to forward message we got from local: %m");
- log_error_errno(r,
- "Failed to forward message we got from local: uid=" UID_FMT " gid=" GID_FMT" message=%s destination=%s path=%s interface=%s member=%s: %m",
- p->local_creds.uid, p->local_creds.gid, bus_message_type_to_string(m->header->type),
- strna(m->destination), strna(m->path), strna(m->interface), strna(m->member));
- return 1;
- }
-
- break;
- }
-
- return 1;
-}
-
-int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- Proxy *p = userdata;
-
- p->message_matched = true;
- return 0; /* make sure to continue processing it in further handlers */
-}
-
-int proxy_run(Proxy *p) {
- int r;
-
- assert(p);
-
- for (;;) {
- bool busy = false;
-
- if (p->got_hello) {
- /* Read messages from bus, to pass them on to our client */
- r = proxy_process_destination_to_local(p);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return 0;
- if (r < 0)
- return r;
- if (r > 0)
- busy = true;
- }
-
- /* Read messages from our client, to pass them on to the bus */
- r = proxy_process_local_to_destination(p);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return 0;
- if (r < 0)
- return r;
- if (r > 0)
- busy = true;
-
- if (!busy) {
- r = proxy_wait(p);
- if (r == -ECONNRESET || r == -ENOTCONN)
- return 0;
- if (r < 0)
- return r;
- }
- }
-
- return 0;
-}
diff --git a/src/libbus-proxy-core/proxy.h b/src/libbus-proxy-core/proxy.h
deleted file mode 100644
index 0e3ed8a87a..0000000000
--- a/src/libbus-proxy-core/proxy.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 David Herrmann
-
- 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 <systemd/sd-bus.h>
-
-#include "bus-xml-policy.h"
-
-typedef struct Proxy Proxy;
-typedef struct ProxyActivation ProxyActivation;
-
-#define PROXY_ACTIVATIONS_MAX (16) /* max parallel activation requests */
-
-struct Proxy {
- sd_bus *local_bus;
- struct ucred local_creds;
- int local_in;
- int local_out;
-
- sd_bus *destination_bus;
-
- Set *owned_names;
- SharedPolicy *policy;
-
- LIST_HEAD(ProxyActivation, activations);
- size_t n_activations;
-
- bool got_hello : 1;
- bool queue_overflow : 1;
- bool message_matched : 1;
- bool synthetic_matched : 1;
-};
-
-struct ProxyActivation {
- LIST_FIELDS(ProxyActivation, activations_by_proxy);
- Proxy *proxy;
- sd_bus_message *request;
- sd_bus_slot *slot;
-};
-
-int proxy_new(Proxy **out, int in_fd, int out_fd, const char *dest);
-Proxy *proxy_free(Proxy *p);
-
-int proxy_set_policy(Proxy *p, SharedPolicy *policy, char **configuration);
-int proxy_hello_policy(Proxy *p, uid_t original_uid);
-int proxy_match(sd_bus_message *m, void *userdata, sd_bus_error *error);
-int proxy_run(Proxy *p);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(Proxy*, proxy_free);
diff --git a/src/libbus-proxy-core/synthesize.c b/src/libbus-proxy-core/synthesize.c
deleted file mode 100644
index 7562f29ecb..0000000000
--- a/src/libbus-proxy-core/synthesize.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2013 Daniel Mack
- Copyright 2014 Kay Sievers
-
- 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 <systemd/sd-bus.h>
-
-#include "bus-internal.h"
-#include "bus-match.h"
-#include "bus-message.h"
-#include "bus-util.h"
-#include "synthesize.h"
-#include "util.h"
-
-int synthetic_driver_send(sd_bus *b, sd_bus_message *m) {
- int r;
-
- assert(b);
- assert(m);
-
- r = bus_message_append_sender(m, "org.freedesktop.DBus");
- if (r < 0)
- return r;
-
- r = bus_seal_synthetic_message(b, m);
- if (r < 0)
- return r;
-
- return sd_bus_send(b, m, NULL);
-}
-
-int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- int r;
-
- assert(call);
-
- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
- return 0;
-
- r = sd_bus_message_new_method_error(call, &m, e);
- if (r < 0)
- return r;
-
- return synthetic_driver_send(call->bus, m);
-}
-
-int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- va_list ap;
-
- va_start(ap, format);
- bus_error_setfv(&error, name, format, ap);
- va_end(ap);
-
- return synthetic_reply_method_error(call, &error);
-}
-
-int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) {
- _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
-
- assert(call);
-
- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
- return 0;
-
- if (sd_bus_error_is_set(p))
- return synthetic_reply_method_error(call, p);
-
- sd_bus_error_set_errno(&berror, error);
-
- return synthetic_reply_method_error(call, &berror);
-}
-
-int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) {
- _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
- va_list ap;
-
- assert(call);
-
- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
- return 0;
-
- va_start(ap, format);
- sd_bus_error_set_errnofv(&berror, error, format, ap);
- va_end(ap);
-
- return synthetic_reply_method_error(call, &berror);
-}
-
-int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- int r;
-
- assert(call);
-
- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
- return 0;
-
- r = sd_bus_message_new_method_return(call, &m);
- if (r < 0)
- return r;
-
- if (!isempty(types)) {
- va_list ap;
-
- va_start(ap, types);
- r = bus_message_append_ap(m, types, ap);
- va_end(ap);
- if (r < 0)
- return r;
- }
-
- return synthetic_driver_send(call->bus, m);
-}
-
-int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
- int r;
-
- assert(call);
-
- if (call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)
- return 0;
-
- r = sd_bus_message_new_method_return(call, &m);
- if (r < 0)
- return synthetic_reply_method_errno(call, r, NULL);
-
- r = sd_bus_message_append_strv(m, l);
- if (r < 0)
- return synthetic_reply_method_errno(call, r, NULL);
-
- return synthetic_driver_send(call->bus, m);
-}
-
-int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
- const char *name, *old_owner, *new_owner;
- int r;
-
- assert(p);
- assert(a);
- assert(b);
- assert(m);
-
- /* If we get NameOwnerChanged for our own name, we need to
- * synthesize NameLost/NameAcquired, since socket clients need
- * that, even though it is obsoleted on kdbus */
-
- if (!a->is_kernel)
- return 0;
-
- if (!sd_bus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged") ||
- !streq_ptr(m->path, "/org/freedesktop/DBus") ||
- !streq_ptr(m->sender, "org.freedesktop.DBus"))
- return 0;
-
- r = sd_bus_message_read(m, "sss", &name, &old_owner, &new_owner);
- if (r < 0)
- return r;
-
- r = sd_bus_message_rewind(m, true);
- if (r < 0)
- return r;
-
- if (streq(old_owner, a->unique_name)) {
-
- r = sd_bus_message_new_signal(
- b,
- &n,
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "NameLost");
-
- } else if (streq(new_owner, a->unique_name)) {
-
- r = sd_bus_message_new_signal(
- b,
- &n,
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "NameAcquired");
- } else
- return 0;
-
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(n, "s", name);
- if (r < 0)
- return r;
-
- r = bus_message_append_sender(n, "org.freedesktop.DBus");
- if (r < 0)
- return r;
-
- r = sd_bus_message_set_destination(n, a->unique_name);
- if (r < 0)
- return r;
-
- r = bus_seal_synthetic_message(b, n);
- if (r < 0)
- return r;
-
- return sd_bus_send(b, n, NULL);
-}
diff --git a/src/libbus-proxy-core/synthesize.h b/src/libbus-proxy-core/synthesize.h
deleted file mode 100644
index cb8c21cdb7..0000000000
--- a/src/libbus-proxy-core/synthesize.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <systemd/sd-bus.h>
-
-#include "proxy.h"
-
-int synthetic_driver_send(sd_bus *b, sd_bus_message *m);
-
-int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...);
-int synthetic_reply_method_return_strv(sd_bus_message *call, char **l);
-
-int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e);
-int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) _sd_printf_(3, 4);
-int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p);
-int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) _sd_printf_(3, 4);
-
-int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m);
diff --git a/src/libbus-proxy-core/test-bus-xml-policy.c b/src/libbus-proxy-core/test-bus-xml-policy.c
deleted file mode 100644
index 6f32c09789..0000000000
--- a/src/libbus-proxy-core/test-bus-xml-policy.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 Daniel Mack
-
- 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 <stddef.h>
-#include <unistd.h>
-
-#include <systemd/sd-bus.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;
- int r = 0;
-
- path = strjoin(TEST_DIR, "/bus-policy/", name, NULL);
- assert_se(path);
-
- if (access(path, R_OK) == 0)
- r = policy_load(p, STRV_MAKE(path));
- else
- r = -ENOENT;
-
- return r;
-}
-
-static int show_policy(const char *fn) {
- Policy p = {};
- int r;
-
- r = policy_load(&p, STRV_MAKE(fn));
- if (r < 0) {
- log_error_errno(r, "Failed to load policy %s: %m", fn);
- return r;
- }
-
- policy_dump(&p);
- policy_free(&p);
-
- return 0;
-}
-
-int main(int argc, char *argv[]) {
-
- Policy p = {};
-
- printf("Showing session policy BEGIN\n");
- show_policy("/etc/dbus-1/session.conf");
- printf("Showing session policy END\n");
-
- printf("Showing system policy BEGIN\n");
- show_policy("/etc/dbus-1/system.conf");
- printf("Showing system policy END\n");
-
- /* Ownership tests */
- assert_se(test_policy_load(&p, "ownerships.conf") == 0);
-
- assert_se(policy_check_own(&p, 0, 0, "org.test.test1") == true);
- assert_se(policy_check_own(&p, 1, 0, "org.test.test1") == true);
-
- assert_se(policy_check_own(&p, 0, 0, "org.test.test2") == true);
- assert_se(policy_check_own(&p, 1, 0, "org.test.test2") == false);
-
- assert_se(policy_check_own(&p, 0, 0, "org.test.test3") == false);
- assert_se(policy_check_own(&p, 1, 0, "org.test.test3") == false);
-
- assert_se(policy_check_own(&p, 0, 0, "org.test.test4") == false);
- assert_se(policy_check_own(&p, 1, 0, "org.test.test4") == true);
-
- policy_free(&p);
-
- /* Signaltest */
- assert_se(test_policy_load(&p, "signals.conf") == 0);
-
- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == true);
- assert_se(policy_check_one_send(&p, 1, 0, SD_BUS_MESSAGE_SIGNAL, "bli.bla.blubb", NULL, "/an/object/path", NULL) == false);
-
- policy_free(&p);
-
- /* Method calls */
- assert_se(test_policy_load(&p, "methods.conf") == 0);
- policy_dump(&p);
-
- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "bli.bla.blubb", "Member") == false);
- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int1", "Member") == true);
- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == true);
-
- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test3", "/an/object/path", "org.test.int3", "Member111") == true);
-
- policy_free(&p);
-
- /* User and groups */
- assert_se(test_policy_load(&p, "hello.conf") == 0);
- policy_dump(&p);
-
- assert_se(policy_check_hello(&p, 0, 0) == true);
- assert_se(policy_check_hello(&p, 1, 0) == false);
- assert_se(policy_check_hello(&p, 0, 1) == false);
-
- policy_free(&p);
-
- /* dbus1 test file: ownership */
-
- assert_se(test_policy_load(&p, "check-own-rules.conf") >= 0);
- policy_dump(&p);
-
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop") == false);
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystem") == false);
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems") == true);
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo") == true);
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems.foo.bar") == true);
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2") == false);
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo") == false);
- assert_se(policy_check_own(&p, 0, 0, "org.freedesktop.ManySystems2.foo.bar") == false);
-
- policy_free(&p);
-
- /* dbus1 test file: many rules */
-
- assert_se(test_policy_load(&p, "many-rules.conf") >= 0);
- policy_dump(&p);
- policy_free(&p);
-
- /* dbus1 test file: generic test */
-
- assert_se(test_policy_load(&p, "test.conf") >= 0);
- policy_dump(&p);
-
- assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService") == true);
- assert_se(policy_check_own(&p, 0, 0, "org.foo.FooService2") == false);
- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
- assert_se(policy_check_one_send(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
- assert_se(policy_check_one_recv(&p, 0, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
-
- assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService") == false);
- assert_se(policy_check_own(&p, 100, 0, "org.foo.FooService2") == false);
- assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.test.int2", "Member") == false);
- assert_se(policy_check_one_send(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.test.test1", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
- assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == true);
- assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService", "/an/object/path", "org.foo.FooBroadcastInterface2", "Member") == false);
- assert_se(policy_check_one_recv(&p, 100, 0, SD_BUS_MESSAGE_METHOD_CALL, "org.foo.FooService2", "/an/object/path", "org.foo.FooBroadcastInterface", "Member") == false);
-
- policy_free(&p);
-
- return EXIT_SUCCESS;
-}
diff --git a/src/libcore/Makefile b/src/libcore/Makefile
index 5eef67be3d..f40a115042 100644
--- a/src/libcore/Makefile
+++ b/src/libcore/Makefile
@@ -45,8 +45,6 @@ libcore_la_SOURCES = \
src/core/socket.h \
src/core/busname.c \
src/core/busname.h \
- src/core/bus-endpoint.c \
- src/core/bus-endpoint.h \
src/core/bus-policy.c \
src/core/bus-policy.h \
src/core/target.c \
diff --git a/src/libcore/automount.c b/src/libcore/automount.c
index 5dc6fd98e7..f06d837e30 100644
--- a/src/libcore/automount.c
+++ b/src/libcore/automount.c
@@ -75,6 +75,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
static int open_dev_autofs(Manager *m);
static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
+static int automount_start_expire(Automount *a);
+static void automount_stop_expire(Automount *a);
+static int automount_send_ready(Automount *a, Set *tokens, int status);
static void automount_init(Unit *u) {
Automount *a = AUTOMOUNT(u);
@@ -87,8 +90,6 @@ static void automount_init(Unit *u) {
UNIT(a)->ignore_on_isolate = true;
}
-static int automount_send_ready(Automount *a, Set *tokens, int status);
-
static void unmount_autofs(Automount *a) {
int r;
@@ -149,7 +150,7 @@ static int automount_add_default_dependencies(Automount *a) {
if (!UNIT(a)->default_dependencies)
return 0;
- if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
@@ -235,6 +236,9 @@ static void automount_set_state(Automount *a, AutomountState state) {
old_state = a->state;
a->state = state;
+ if (state != AUTOMOUNT_RUNNING)
+ automount_stop_expire(a);
+
if (state != AUTOMOUNT_WAITING &&
state != AUTOMOUNT_RUNNING)
unmount_autofs(a);
@@ -408,7 +412,7 @@ static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, in
init_autofs_dev_ioctl(&param);
param.ioctlfd = ioctl_fd;
- if (status) {
+ if (status != 0) {
param.fail.token = token;
param.fail.status = status;
} else
@@ -435,7 +439,7 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
if (ioctl_fd < 0)
return ioctl_fd;
- if (status)
+ if (status != 0)
log_unit_debug_errno(UNIT(a), status, "Sending failure: %m");
else
log_unit_debug(UNIT(a), "Sending success.");
@@ -462,59 +466,54 @@ static int automount_send_ready(Automount *a, Set *tokens, int status) {
return r;
}
-static int automount_start_expire(Automount *a);
-
-int automount_update_mount(Automount *a, MountState old_state, MountState state) {
+static void automount_trigger_notify(Unit *u, Unit *other) {
+ Automount *a = AUTOMOUNT(u);
int r;
assert(a);
+ assert(other);
+
+ /* Filter out invocations with bogus state */
+ if (other->load_state != UNIT_LOADED || other->type != UNIT_MOUNT)
+ return;
+
+ /* Don't propagate state changes from the mount if we are already down */
+ if (!IN_SET(a->state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING))
+ return;
+
+ /* Propagate start limit hit state */
+ if (other->start_limit_hit) {
+ automount_enter_dead(a, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT);
+ return;
+ }
+
+ /* Don't propagate anything if there's still a job queued */
+ if (other->job)
+ return;
+
+ /* The mount is successfully established */
+ if (IN_SET(MOUNT(other)->state, MOUNT_MOUNTED, MOUNT_REMOUNTING)) {
+ (void) automount_send_ready(a, a->tokens, 0);
- switch (state) {
- case MOUNT_MOUNTED:
- case MOUNT_REMOUNTING:
- automount_send_ready(a, a->tokens, 0);
r = automount_start_expire(a);
if (r < 0)
log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
- break;
- case MOUNT_DEAD:
- case MOUNT_UNMOUNTING:
- case MOUNT_MOUNTING_SIGTERM:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_FAILED:
- if (old_state != state)
- automount_send_ready(a, a->tokens, -ENODEV);
- (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
- break;
- default:
- break;
- }
- switch (state) {
- case MOUNT_DEAD:
- automount_send_ready(a, a->expire_tokens, 0);
- break;
- case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
- case MOUNT_MOUNTING_SIGTERM:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_FAILED:
- if (old_state != state)
- automount_send_ready(a, a->expire_tokens, -ENODEV);
- break;
- default:
- break;
+ automount_set_state(a, AUTOMOUNT_RUNNING);
}
- return 0;
+ /* The mount is in some unhappy state now, let's unfreeze any waiting clients */
+ if (IN_SET(MOUNT(other)->state,
+ MOUNT_DEAD, MOUNT_UNMOUNTING,
+ MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_FAILED)) {
+
+ (void) automount_send_ready(a, a->tokens, -ENODEV);
+
+ automount_set_state(a, AUTOMOUNT_WAITING);
+ }
}
static void automount_enter_waiting(Automount *a) {
@@ -699,6 +698,15 @@ static int automount_start_expire(Automount *a) {
return 0;
}
+static void automount_stop_expire(Automount *a) {
+ assert(a);
+
+ if (!a->expire_event_source)
+ return;
+
+ (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
+}
+
static void automount_enter_runnning(Automount *a) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
struct stat st;
@@ -751,6 +759,7 @@ fail:
static int automount_start(Unit *u) {
Automount *a = AUTOMOUNT(u);
Unit *trigger;
+ int r;
assert(a);
assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
@@ -766,6 +775,12 @@ static int automount_start(Unit *u) {
return -ENOENT;
}
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
a->result = AUTOMOUNT_SUCCESS;
automount_enter_waiting(a);
return 1;
@@ -958,7 +973,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
case autofs_ptype_expire_direct:
log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);
- (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
+ automount_stop_expire(a);
r = set_ensure_allocated(&a->expire_tokens, NULL);
if (r < 0) {
@@ -1037,7 +1052,9 @@ static bool automount_supported(void) {
static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
[AUTOMOUNT_SUCCESS] = "success",
- [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
+ [AUTOMOUNT_FAILURE_RESOURCES] = "resources",
+ [AUTOMOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT] = "mount-start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
@@ -1050,9 +1067,6 @@ const UnitVTable automount_vtable = {
"Automount\0"
"Install\0",
- .no_alias = true,
- .no_instances = true,
-
.init = automount_init,
.load = automount_load,
.done = automount_done,
@@ -1072,6 +1086,8 @@ const UnitVTable automount_vtable = {
.check_gc = automount_check_gc,
+ .trigger_notify = automount_trigger_notify,
+
.reset_failed = automount_reset_failed,
.bus_vtable = bus_automount_vtable,
diff --git a/src/libcore/automount.h b/src/libcore/automount.h
index cf5b1cf994..76a201178e 100644
--- a/src/libcore/automount.h
+++ b/src/libcore/automount.h
@@ -26,6 +26,8 @@ typedef struct Automount Automount;
typedef enum AutomountResult {
AUTOMOUNT_SUCCESS,
AUTOMOUNT_FAILURE_RESOURCES,
+ AUTOMOUNT_FAILURE_START_LIMIT_HIT,
+ AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT,
_AUTOMOUNT_RESULT_MAX,
_AUTOMOUNT_RESULT_INVALID = -1
} AutomountResult;
@@ -53,7 +55,5 @@ struct Automount {
extern const UnitVTable automount_vtable;
-int automount_update_mount(Automount *a, MountState old_state, MountState state);
-
const char* automount_result_to_string(AutomountResult i) _const_;
AutomountResult automount_result_from_string(const char *s) _pure_;
diff --git a/src/libcore/bus-endpoint.c b/src/libcore/bus-endpoint.c
deleted file mode 100644
index d22a80c91f..0000000000
--- a/src/libcore/bus-endpoint.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 Daniel Mack
-
- 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 "alloc-util.h"
-#include "bus-endpoint.h"
-#include "bus-kernel.h"
-#include "bus-policy.h"
-#include "kdbus.h"
-
-int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) {
-
- struct kdbus_cmd *update;
- struct kdbus_item *n;
- BusEndpointPolicy *po;
- Iterator i;
- size_t size;
- int r;
-
- size = ALIGN8(offsetof(struct kdbus_cmd, items));
-
- HASHMAP_FOREACH(po, ep->policy_hash, i) {
- size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(po->name) + 1);
- size += ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
- }
-
- update = alloca0_align(size, 8);
- update->size = size;
-
- n = update->items;
-
- HASHMAP_FOREACH(po, ep->policy_hash, i) {
- n->type = KDBUS_ITEM_NAME;
- n->size = offsetof(struct kdbus_item, str) + strlen(po->name) + 1;
- strcpy(n->str, po->name);
- n = KDBUS_ITEM_NEXT(n);
-
- n->type = KDBUS_ITEM_POLICY_ACCESS;
- n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
-
- n->policy_access.type = KDBUS_POLICY_ACCESS_USER;
- n->policy_access.access = bus_kernel_translate_access(po->access);
- n->policy_access.id = uid;
-
- n = KDBUS_ITEM_NEXT(n);
- }
-
- r = ioctl(fd, KDBUS_CMD_ENDPOINT_UPDATE, update);
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int bus_endpoint_new(BusEndpoint **ep) {
- assert(ep);
-
- *ep = new0(BusEndpoint, 1);
- if (!*ep)
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access) {
- _cleanup_free_ BusEndpointPolicy *po = NULL;
- _cleanup_free_ char *key = NULL;
- int r;
-
- assert(ep);
- assert(name);
- assert(access > _BUS_POLICY_ACCESS_INVALID && access < _BUS_POLICY_ACCESS_MAX);
-
- /* check if we already have this name in the policy list. If we do, see if the new access level
- * is higher than the exising one, and upgrade the entry in that case. Otherwise, do nothing.
- */
-
- if (ep->policy_hash) {
- po = hashmap_get(ep->policy_hash, name);
- if (po) {
- if (po->access < access)
- po->access = access;
-
- return 0;
- }
- } else {
- ep->policy_hash = hashmap_new(&string_hash_ops);
- if (!ep->policy_hash)
- return -ENOMEM;
- }
-
- po = new0(BusEndpointPolicy, 1);
- if (!po)
- return -ENOMEM;
-
- key = strdup(name);
- if (!key)
- return -ENOMEM;
-
- po->name = key;
- po->access = access;
-
- r = hashmap_put(ep->policy_hash, key, po);
- if (r < 0)
- return r;
-
- po = NULL;
- key = NULL;
- return 0;
-}
-
-void bus_endpoint_free(BusEndpoint *endpoint) {
- if (!endpoint)
- return;
-
- hashmap_free_free_free(endpoint->policy_hash);
- free(endpoint);
-}
diff --git a/src/libcore/busname.c b/src/libcore/busname.c
index de2a21ccde..f03a95c24e 100644
--- a/src/libcore/busname.c
+++ b/src/libcore/busname.c
@@ -149,7 +149,7 @@ static int busname_add_default_default_dependencies(BusName *n) {
if (r < 0)
return r;
- if (UNIT(n)->manager->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(UNIT(n)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@@ -318,7 +318,7 @@ static int busname_open_fd(BusName *n) {
if (n->starter_fd >= 0)
return 0;
- mode = UNIT(n)->manager->running_as == MANAGER_SYSTEM ? "system" : "user";
+ mode = MANAGER_IS_SYSTEM(UNIT(n)->manager) ? "system" : "user";
n->starter_fd = bus_kernel_open_bus_fd(mode, &path);
if (n->starter_fd < 0)
return log_unit_warning_errno(UNIT(n), n->starter_fd, "Failed to open %s: %m", path ?: "kdbus");
@@ -607,6 +607,7 @@ fail:
static int busname_start(Unit *u) {
BusName *n = BUSNAME(u);
+ int r;
assert(n);
@@ -632,6 +633,12 @@ static int busname_start(Unit *u) {
assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ busname_enter_dead(n, BUSNAME_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
n->result = BUSNAME_SUCCESS;
busname_enter_making(n);
@@ -999,6 +1006,14 @@ static bool busname_supported(void) {
return supported;
}
+static int busname_control_pid(Unit *u) {
+ BusName *n = BUSNAME(u);
+
+ assert(n);
+
+ return n->control_pid;
+}
+
static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_SUCCESS] = "success",
[BUSNAME_FAILURE_RESOURCES] = "resources",
@@ -1006,6 +1021,7 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_FAILURE_EXIT_CODE] = "exit-code",
[BUSNAME_FAILURE_SIGNAL] = "signal",
[BUSNAME_FAILURE_CORE_DUMP] = "core-dump",
+ [BUSNAME_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
[BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit",
};
@@ -1020,9 +1036,6 @@ const UnitVTable busname_vtable = {
"Install\0",
.private_section = "BusName",
- .no_alias = true,
- .no_instances = true,
-
.init = busname_init,
.done = busname_done,
.load = busname_load,
@@ -1052,6 +1065,8 @@ const UnitVTable busname_vtable = {
.supported = busname_supported,
+ .control_pid = busname_control_pid,
+
.bus_vtable = bus_busname_vtable,
.status_message_formats = {
diff --git a/src/libcore/busname.h b/src/libcore/busname.h
index 6b6f6c62d4..a8562db458 100644
--- a/src/libcore/busname.h
+++ b/src/libcore/busname.h
@@ -23,6 +23,7 @@ typedef struct BusName BusName;
typedef struct BusNamePolicy BusNamePolicy;
#include "unit.h"
+#include "bus-policy.h"
typedef enum BusNameResult {
BUSNAME_SUCCESS,
@@ -31,6 +32,7 @@ typedef enum BusNameResult {
BUSNAME_FAILURE_EXIT_CODE,
BUSNAME_FAILURE_SIGNAL,
BUSNAME_FAILURE_CORE_DUMP,
+ BUSNAME_FAILURE_START_LIMIT_HIT,
BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT,
_BUSNAME_RESULT_MAX,
_BUSNAME_RESULT_INVALID = -1
diff --git a/src/libcore/cgroup.c b/src/libcore/cgroup.c
index 39235a95f6..0fb63b1bd1 100644
--- a/src/libcore/cgroup.c
+++ b/src/libcore/cgroup.c
@@ -32,6 +32,7 @@
#include "special.h"
#include "string-table.h"
#include "string-util.h"
+#include "stdio-util.h"
#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
@@ -47,6 +48,9 @@ void cgroup_context_init(CGroupContext *c) {
c->memory_limit = (uint64_t) -1;
+ c->io_weight = CGROUP_WEIGHT_INVALID;
+ c->startup_io_weight = CGROUP_WEIGHT_INVALID;
+
c->blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
@@ -62,6 +66,24 @@ void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
free(a);
}
+void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w) {
+ assert(c);
+ assert(w);
+
+ LIST_REMOVE(device_weights, c->io_device_weights, w);
+ free(w->path);
+ free(w);
+}
+
+void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l) {
+ assert(c);
+ assert(l);
+
+ LIST_REMOVE(device_limits, c->io_device_limits, l);
+ free(l->path);
+ free(l);
+}
+
void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
assert(c);
assert(w);
@@ -83,6 +105,12 @@ void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockI
void cgroup_context_done(CGroupContext *c) {
assert(c);
+ while (c->io_device_weights)
+ cgroup_context_free_io_device_weight(c, c->io_device_weights);
+
+ while (c->io_device_limits)
+ cgroup_context_free_io_device_limit(c, c->io_device_limits);
+
while (c->blockio_device_weights)
cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
@@ -94,6 +122,8 @@ void cgroup_context_done(CGroupContext *c) {
}
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+ CGroupIODeviceLimit *il;
+ CGroupIODeviceWeight *iw;
CGroupBlockIODeviceBandwidth *b;
CGroupBlockIODeviceWeight *w;
CGroupDeviceAllow *a;
@@ -106,12 +136,15 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
fprintf(f,
"%sCPUAccounting=%s\n"
+ "%sIOAccounting=%s\n"
"%sBlockIOAccounting=%s\n"
"%sMemoryAccounting=%s\n"
"%sTasksAccounting=%s\n"
"%sCPUShares=%" PRIu64 "\n"
"%sStartupCPUShares=%" PRIu64 "\n"
"%sCPUQuotaPerSecSec=%s\n"
+ "%sIOWeight=%" PRIu64 "\n"
+ "%sStartupIOWeight=%" PRIu64 "\n"
"%sBlockIOWeight=%" PRIu64 "\n"
"%sStartupBlockIOWeight=%" PRIu64 "\n"
"%sMemoryLimit=%" PRIu64 "\n"
@@ -119,12 +152,15 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sDevicePolicy=%s\n"
"%sDelegate=%s\n",
prefix, yes_no(c->cpu_accounting),
+ prefix, yes_no(c->io_accounting),
prefix, yes_no(c->blockio_accounting),
prefix, yes_no(c->memory_accounting),
prefix, yes_no(c->tasks_accounting),
prefix, c->cpu_shares,
prefix, c->startup_cpu_shares,
prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
+ prefix, c->io_weight,
+ prefix, c->startup_io_weight,
prefix, c->blockio_weight,
prefix, c->startup_blockio_weight,
prefix, c->memory_limit,
@@ -139,6 +175,27 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
a->path,
a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
+ LIST_FOREACH(device_weights, iw, c->io_device_weights)
+ fprintf(f,
+ "%sIODeviceWeight=%s %" PRIu64,
+ prefix,
+ iw->path,
+ iw->weight);
+
+ LIST_FOREACH(device_limits, il, c->io_device_limits) {
+ char buf[FORMAT_BYTES_MAX];
+ CGroupIOLimitType type;
+
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ if (il->limits[type] != cgroup_io_limit_defaults[type])
+ fprintf(f,
+ "%s%s=%s %s\n",
+ prefix,
+ cgroup_io_limit_type_to_string(type),
+ il->path,
+ format_bytes(buf, sizeof(buf), il->limits[type]));
+ }
+
LIST_FOREACH(device_weights, w, c->blockio_device_weights)
fprintf(f,
"%sBlockIODeviceWeight=%s %" PRIu64,
@@ -149,16 +206,22 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
char buf[FORMAT_BYTES_MAX];
- fprintf(f,
- "%s%s=%s %s\n",
- prefix,
- b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
- b->path,
- format_bytes(buf, sizeof(buf), b->bandwidth));
+ if (b->rbps != CGROUP_LIMIT_MAX)
+ fprintf(f,
+ "%sBlockIOReadBandwidth=%s %s\n",
+ prefix,
+ b->path,
+ format_bytes(buf, sizeof(buf), b->rbps));
+ if (b->wbps != CGROUP_LIMIT_MAX)
+ fprintf(f,
+ "%sBlockIOWriteBandwidth=%s %s\n",
+ prefix,
+ b->path,
+ format_bytes(buf, sizeof(buf), b->wbps));
}
}
-static int lookup_blkio_device(const char *p, dev_t *dev) {
+static int lookup_block_device(const char *p, dev_t *dev) {
struct stat st;
int r;
@@ -295,6 +358,144 @@ fail:
return -errno;
}
+static bool cgroup_context_has_io_config(CGroupContext *c) {
+ return c->io_accounting ||
+ c->io_weight != CGROUP_WEIGHT_INVALID ||
+ c->startup_io_weight != CGROUP_WEIGHT_INVALID ||
+ c->io_device_weights ||
+ c->io_device_limits;
+}
+
+static bool cgroup_context_has_blockio_config(CGroupContext *c) {
+ return c->blockio_accounting ||
+ c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
+ c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
+ c->blockio_device_weights ||
+ c->blockio_device_bandwidths;
+}
+
+static uint64_t cgroup_context_io_weight(CGroupContext *c, ManagerState state) {
+ if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) &&
+ c->startup_io_weight != CGROUP_WEIGHT_INVALID)
+ return c->startup_io_weight;
+ else if (c->io_weight != CGROUP_WEIGHT_INVALID)
+ return c->io_weight;
+ else
+ return CGROUP_WEIGHT_DEFAULT;
+}
+
+static uint64_t cgroup_context_blkio_weight(CGroupContext *c, ManagerState state) {
+ if (IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) &&
+ c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID)
+ return c->startup_blockio_weight;
+ else if (c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID)
+ return c->blockio_weight;
+ else
+ return CGROUP_BLKIO_WEIGHT_DEFAULT;
+}
+
+static uint64_t cgroup_weight_blkio_to_io(uint64_t blkio_weight) {
+ return CLAMP(blkio_weight * CGROUP_WEIGHT_DEFAULT / CGROUP_BLKIO_WEIGHT_DEFAULT,
+ CGROUP_WEIGHT_MIN, CGROUP_WEIGHT_MAX);
+}
+
+static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) {
+ return CLAMP(io_weight * CGROUP_BLKIO_WEIGHT_DEFAULT / CGROUP_WEIGHT_DEFAULT,
+ CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX);
+}
+
+static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) {
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
+ dev_t dev;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return;
+
+ xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), io_weight);
+ r = cg_set_attribute("io", path, "io.weight", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.weight on %s: %m", path);
+}
+
+static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_path, uint64_t blkio_weight) {
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
+ dev_t dev;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return;
+
+ xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), blkio_weight);
+ r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.weight_device on %s: %m", path);
+}
+
+static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_path, uint64_t *limits) {
+ char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)];
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4];
+ CGroupIOLimitType type;
+ dev_t dev;
+ unsigned n = 0;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return 0;
+
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) {
+ if (limits[type] != cgroup_io_limit_defaults[type]) {
+ xsprintf(limit_bufs[type], "%" PRIu64, limits[type]);
+ n++;
+ } else {
+ xsprintf(limit_bufs[type], "%s", limits[type] == CGROUP_LIMIT_MAX ? "max" : "0");
+ }
+ }
+
+ xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev),
+ limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],
+ limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]);
+ r = cg_set_attribute("io", path, "io.max", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.max on %s: %m", path);
+ return n;
+}
+
+static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *dev_path, uint64_t rbps, uint64_t wbps) {
+ char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
+ dev_t dev;
+ unsigned n = 0;
+ int r;
+
+ r = lookup_block_device(dev_path, &dev);
+ if (r < 0)
+ return 0;
+
+ if (rbps != CGROUP_LIMIT_MAX)
+ n++;
+ sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), rbps);
+ r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.throttle.read_bps_device on %s: %m", path);
+
+ if (wbps != CGROUP_LIMIT_MAX)
+ n++;
+ sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), wbps);
+ r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf);
+ if (r < 0)
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.throttle.write_bps_device on %s: %m", path);
+
+ return n;
+}
+
void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) {
bool is_root;
int r;
@@ -343,53 +544,120 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
"Failed to set cpu.cfs_quota_us on %s: %m", path);
}
- if (mask & CGROUP_MASK_BLKIO) {
- char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
- CGroupBlockIODeviceWeight *w;
- CGroupBlockIODeviceBandwidth *b;
+ if (mask & CGROUP_MASK_IO) {
+ bool has_io = cgroup_context_has_io_config(c);
+ bool has_blockio = cgroup_context_has_blockio_config(c);
if (!is_root) {
- sprintf(buf, "%" PRIu64 "\n",
- IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->startup_blockio_weight :
- c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT);
- r = cg_set_attribute("blkio", path, "blkio.weight", buf);
+ char buf[8+DECIMAL_STR_MAX(uint64_t)+1];
+ uint64_t weight;
+
+ if (has_io)
+ weight = cgroup_context_io_weight(c, state);
+ else if (has_blockio)
+ weight = cgroup_weight_blkio_to_io(cgroup_context_blkio_weight(c, state));
+ else
+ weight = CGROUP_WEIGHT_DEFAULT;
+
+ xsprintf(buf, "default %" PRIu64 "\n", weight);
+ r = cg_set_attribute("io", path, "io.weight", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight on %s: %m", path);
+ "Failed to set io.weight on %s: %m", path);
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
- dev_t dev;
+ if (has_io) {
+ CGroupIODeviceWeight *w;
- r = lookup_blkio_device(w->path, &dev);
- if (r < 0)
- continue;
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->io_device_weights)
+ cgroup_apply_io_device_weight(path, w->path, w->weight);
+ } else if (has_blockio) {
+ CGroupBlockIODeviceWeight *w;
- sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight);
- r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight_device on %s: %m", path);
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights)
+ cgroup_apply_io_device_weight(path, w->path, cgroup_weight_blkio_to_io(w->weight));
}
}
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- const char *a;
- dev_t dev;
+ /* Apply limits and free ones without config. */
+ if (has_io) {
+ CGroupIODeviceLimit *l, *next;
- r = lookup_blkio_device(b->path, &dev);
- if (r < 0)
- continue;
+ LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
+ if (!cgroup_apply_io_device_limit(path, l->path, l->limits))
+ cgroup_context_free_io_device_limit(c, l);
+ }
+ } else if (has_blockio) {
+ CGroupBlockIODeviceBandwidth *b, *next;
- a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
+ LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
+ uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
+ CGroupIOLimitType type;
- sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
- r = cg_set_attribute("blkio", path, a, buf);
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ limits[type] = cgroup_io_limit_defaults[type];
+
+ limits[CGROUP_IO_RBPS_MAX] = b->rbps;
+ limits[CGROUP_IO_WBPS_MAX] = b->wbps;
+
+ if (!cgroup_apply_io_device_limit(path, b->path, limits))
+ cgroup_context_free_blockio_device_bandwidth(c, b);
+ }
+ }
+ }
+
+ if (mask & CGROUP_MASK_BLKIO) {
+ bool has_io = cgroup_context_has_io_config(c);
+ bool has_blockio = cgroup_context_has_blockio_config(c);
+
+ if (!is_root) {
+ char buf[DECIMAL_STR_MAX(uint64_t)+1];
+ uint64_t weight;
+
+ if (has_blockio)
+ weight = cgroup_context_blkio_weight(c, state);
+ else if (has_io)
+ weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state));
+ else
+ weight = CGROUP_BLKIO_WEIGHT_DEFAULT;
+
+ xsprintf(buf, "%" PRIu64 "\n", weight);
+ r = cg_set_attribute("blkio", path, "blkio.weight", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set %s on %s: %m", a, path);
+ "Failed to set blkio.weight on %s: %m", path);
+
+ if (has_blockio) {
+ CGroupBlockIODeviceWeight *w;
+
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights)
+ cgroup_apply_blkio_device_weight(path, w->path, w->weight);
+ } else if (has_io) {
+ CGroupIODeviceWeight *w;
+
+ /* FIXME: no way to reset this list */
+ LIST_FOREACH(device_weights, w, c->io_device_weights)
+ cgroup_apply_blkio_device_weight(path, w->path, cgroup_weight_io_to_blkio(w->weight));
+ }
+ }
+
+ /* Apply limits and free ones without config. */
+ if (has_blockio) {
+ CGroupBlockIODeviceBandwidth *b, *next;
+
+ LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
+ if (!cgroup_apply_blkio_device_limit(path, b->path, b->rbps, b->wbps))
+ cgroup_context_free_blockio_device_bandwidth(c, b);
+ }
+ } else if (has_io) {
+ CGroupIODeviceLimit *l, *next;
+
+ LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
+ if (!cgroup_apply_blkio_device_limit(path, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]))
+ cgroup_context_free_io_device_limit(c, l);
+ }
}
}
@@ -506,12 +774,8 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
c->cpu_quota_per_sec_usec != USEC_INFINITY)
mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
- if (c->blockio_accounting ||
- c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
- c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
- c->blockio_device_weights ||
- c->blockio_device_bandwidths)
- mask |= CGROUP_MASK_BLKIO;
+ if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c))
+ mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
if (c->memory_accounting ||
c->memory_limit != (uint64_t) -1)
@@ -765,7 +1029,7 @@ int unit_set_cgroup_path(Unit *u, const char *path) {
}
int unit_watch_cgroup(Unit *u) {
- _cleanup_free_ char *populated = NULL;
+ _cleanup_free_ char *events = NULL;
int r;
assert(u);
@@ -791,11 +1055,11 @@ int unit_watch_cgroup(Unit *u) {
if (r < 0)
return log_oom();
- r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated);
+ r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.events", &events);
if (r < 0)
return log_oom();
- u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY);
+ u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, events, IN_MODIFY);
if (u->cgroup_inotify_wd < 0) {
if (errno == ENOENT) /* If the directory is already
@@ -857,6 +1121,7 @@ static int unit_create_cgroup(
/* Keep track that this is now realized */
u->cgroup_realized = true;
u->cgroup_realized_mask = target_mask;
+ u->cgroup_enabled_mask = enable_mask;
if (u->type != UNIT_SLICE && !c->delegate) {
@@ -886,10 +1151,10 @@ int unit_attach_pids_to_cgroup(Unit *u) {
return 0;
}
-static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) {
+static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask, CGroupMask enable_mask) {
assert(u);
- return u->cgroup_realized && u->cgroup_realized_mask == target_mask;
+ return u->cgroup_realized && u->cgroup_realized_mask == target_mask && u->cgroup_enabled_mask == enable_mask;
}
/* Check if necessary controllers and attributes for a unit are in place.
@@ -910,7 +1175,9 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
}
target_mask = unit_get_target_mask(u);
- if (unit_has_mask_realized(u, target_mask))
+ enable_mask = unit_get_enable_mask(u);
+
+ if (unit_has_mask_realized(u, target_mask, enable_mask))
return 0;
/* First, realize parents */
@@ -921,7 +1188,6 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
}
/* And then do the real work */
- enable_mask = unit_get_enable_mask(u);
r = unit_create_cgroup(u, target_mask, enable_mask);
if (r < 0)
return r;
@@ -990,7 +1256,7 @@ static void unit_queue_siblings(Unit *u) {
/* If the unit doesn't need any new controllers
* and has current ones realized, it doesn't need
* any changes. */
- if (unit_has_mask_realized(m, unit_get_target_mask(m)))
+ if (unit_has_mask_realized(m, unit_get_target_mask(m), unit_get_enable_mask(m)))
continue;
unit_add_to_cgroup_queue(m);
@@ -1069,6 +1335,7 @@ void unit_prune_cgroup(Unit *u) {
u->cgroup_realized = false;
u->cgroup_realized_mask = 0;
+ u->cgroup_enabled_mask = 0;
}
int unit_search_main_pid(Unit *u, pid_t *ret) {
@@ -1265,7 +1532,7 @@ int manager_setup_cgroup(Manager *m) {
* it. This is to support live upgrades from older systemd
* versions where PID 1 was moved there. Also see
* cg_get_root_path(). */
- if (!e && m->running_as == MANAGER_SYSTEM) {
+ if (!e && MANAGER_IS_SYSTEM(m)) {
e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
if (!e)
e = endswith(m->cgroup_root, "/system"); /* even more legacy */
@@ -1312,13 +1579,15 @@ int manager_setup_cgroup(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to watch control group inotify object: %m");
- r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
+ /* Process cgroup empty notifications early, but after service notifications and SIGCHLD. Also
+ * see handling of cgroup agent notifications, for the classic cgroup hierarchy support. */
+ r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_NORMAL-5);
if (r < 0)
return log_error_errno(r, "Failed to set priority of inotify event source: %m");
(void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
- } else if (m->running_as == MANAGER_SYSTEM) {
+ } else if (MANAGER_IS_SYSTEM(m)) {
/* On the legacy hierarchy we only get
* notifications via cgroup agents. (Which
@@ -1458,6 +1727,8 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
assert(m);
assert(cgroup);
+ log_debug("Got cgroup empty notification for: %s", cgroup);
+
u = manager_get_unit_by_cgroup(m, cgroup);
if (!u)
return 0;
@@ -1594,6 +1865,10 @@ void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
if (m == 0)
return;
+ /* always invalidate compat pairs together */
+ if (m & (CGROUP_MASK_IO | CGROUP_MASK_BLKIO))
+ m |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
+
if ((u->cgroup_realized_mask & m) == 0)
return;
@@ -1608,7 +1883,7 @@ void manager_invalidate_startup_units(Manager *m) {
assert(m);
SET_FOREACH(u, m->startup_units, i)
- unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_BLKIO);
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_IO|CGROUP_MASK_BLKIO);
}
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
diff --git a/src/libcore/cgroup.h b/src/libcore/cgroup.h
index 360bbca30f..2b1edbafc4 100644
--- a/src/libcore/cgroup.h
+++ b/src/libcore/cgroup.h
@@ -23,9 +23,12 @@
#include "list.h"
#include "time-util.h"
+#include "cgroup-util.h"
typedef struct CGroupContext CGroupContext;
typedef struct CGroupDeviceAllow CGroupDeviceAllow;
+typedef struct CGroupIODeviceWeight CGroupIODeviceWeight;
+typedef struct CGroupIODeviceLimit CGroupIODeviceLimit;
typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight;
typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth;
@@ -53,6 +56,18 @@ struct CGroupDeviceAllow {
bool m:1;
};
+struct CGroupIODeviceWeight {
+ LIST_FIELDS(CGroupIODeviceWeight, device_weights);
+ char *path;
+ uint64_t weight;
+};
+
+struct CGroupIODeviceLimit {
+ LIST_FIELDS(CGroupIODeviceLimit, device_limits);
+ char *path;
+ uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
+};
+
struct CGroupBlockIODeviceWeight {
LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights);
char *path;
@@ -62,16 +77,24 @@ struct CGroupBlockIODeviceWeight {
struct CGroupBlockIODeviceBandwidth {
LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths);
char *path;
- uint64_t bandwidth;
- bool read;
+ uint64_t rbps;
+ uint64_t wbps;
};
struct CGroupContext {
bool cpu_accounting;
+ bool io_accounting;
bool blockio_accounting;
bool memory_accounting;
bool tasks_accounting;
+ /* For unified hierarchy */
+ uint64_t io_weight;
+ uint64_t startup_io_weight;
+ LIST_HEAD(CGroupIODeviceWeight, io_device_weights);
+ LIST_HEAD(CGroupIODeviceLimit, io_device_limits);
+
+ /* For legacy hierarchies */
uint64_t cpu_shares;
uint64_t startup_cpu_shares;
usec_t cpu_quota_per_sec_usec;
@@ -86,6 +109,7 @@ struct CGroupContext {
CGroupDevicePolicy device_policy;
LIST_HEAD(CGroupDeviceAllow, device_allow);
+ /* Common */
uint64_t tasks_max;
bool delegate;
@@ -102,6 +126,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
CGroupMask cgroup_context_get_mask(CGroupContext *c);
void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
+void cgroup_context_free_io_device_weight(CGroupContext *c, CGroupIODeviceWeight *w);
+void cgroup_context_free_io_device_limit(CGroupContext *c, CGroupIODeviceLimit *l);
void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
diff --git a/src/libcore/dbus-cgroup.c b/src/libcore/dbus-cgroup.c
index 859d155ec1..eef1c47c14 100644
--- a/src/libcore/dbus-cgroup.c
+++ b/src/libcore/dbus-cgroup.c
@@ -28,6 +28,72 @@
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
+static int property_get_io_device_weight(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ CGroupContext *c = userdata;
+ CGroupIODeviceWeight *w;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ r = sd_bus_message_open_container(reply, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(device_weights, w, c->io_device_weights) {
+ r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
+static int property_get_io_device_limits(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ CGroupContext *c = userdata;
+ CGroupIODeviceLimit *l;
+ int r;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ r = sd_bus_message_open_container(reply, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ LIST_FOREACH(device_limits, l, c->io_device_limits) {
+ CGroupIOLimitType type;
+
+ type = cgroup_io_limit_type_from_string(property);
+ if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
+ continue;
+
+ r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
+ if (r < 0)
+ return r;
+ }
+
+ return sd_bus_message_close_container(reply);
+}
+
static int property_get_blockio_device_weight(
sd_bus *bus,
const char *path,
@@ -80,11 +146,17 @@ static int property_get_blockio_device_bandwidths(
return r;
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+ uint64_t v;
- if (streq(property, "BlockIOReadBandwidth") != b->read)
+ if (streq(property, "BlockIOReadBandwidth"))
+ v = b->rbps;
+ else
+ v = b->wbps;
+
+ if (v == CGROUP_LIMIT_MAX)
continue;
- r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
+ r = sd_bus_message_append(reply, "(st)", b->path, v);
if (r < 0)
return r;
}
@@ -141,6 +213,14 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
+ SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
+ SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
+ SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
+ SD_BUS_PROPERTY("IODeviceWeight", "a(st)", property_get_io_device_weight, 0, 0),
+ SD_BUS_PROPERTY("IOReadBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
+ SD_BUS_PROPERTY("IOWriteBandwidthMax", "a(st)", property_get_io_device_limits, 0, 0),
+ SD_BUS_PROPERTY("IOReadIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
+ SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
SD_BUS_PROPERTY("BlockIOWeight", "t", NULL, offsetof(CGroupContext, blockio_weight), 0),
SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, offsetof(CGroupContext, startup_blockio_weight), 0),
@@ -197,6 +277,7 @@ int bus_cgroup_set_property(
UnitSetPropertiesMode mode,
sd_bus_error *error) {
+ CGroupIOLimitType iol_type;
int r;
assert(u);
@@ -281,6 +362,223 @@ int bus_cgroup_set_property(
return 1;
+ } else if (streq(name, "IOAccounting")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->io_accounting = b;
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+ unit_write_drop_in_private(u, mode, name, b ? "IOAccounting=yes" : "IOAccounting=no");
+ }
+
+ return 1;
+
+ } else if (streq(name, "IOWeight")) {
+ uint64_t weight;
+
+ r = sd_bus_message_read(message, "t", &weight);
+ if (r < 0)
+ return r;
+
+ if (!CGROUP_WEIGHT_IS_OK(weight))
+ return sd_bus_error_set_errnof(error, EINVAL, "IOWeight value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->io_weight = weight;
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ if (weight == CGROUP_WEIGHT_INVALID)
+ unit_write_drop_in_private(u, mode, name, "IOWeight=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "IOWeight=%" PRIu64, weight);
+ }
+
+ return 1;
+
+ } else if (streq(name, "StartupIOWeight")) {
+ uint64_t weight;
+
+ r = sd_bus_message_read(message, "t", &weight);
+ if (r < 0)
+ return r;
+
+ if (CGROUP_WEIGHT_IS_OK(weight))
+ return sd_bus_error_set_errnof(error, EINVAL, "StartupIOWeight value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->startup_io_weight = weight;
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ if (weight == CGROUP_WEIGHT_INVALID)
+ unit_write_drop_in_private(u, mode, name, "StartupIOWeight=");
+ else
+ unit_write_drop_in_private_format(u, mode, name, "StartupIOWeight=%" PRIu64, weight);
+ }
+
+ return 1;
+
+ } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
+ const char *path;
+ unsigned n = 0;
+ uint64_t u64;
+
+ r = sd_bus_message_enter_container(message, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
+
+ if (mode != UNIT_CHECK) {
+ CGroupIODeviceLimit *a = NULL, *b;
+
+ LIST_FOREACH(device_limits, b, c->io_device_limits) {
+ if (path_equal(path, b->path)) {
+ a = b;
+ break;
+ }
+ }
+
+ if (!a) {
+ CGroupIOLimitType type;
+
+ a = new0(CGroupIODeviceLimit, 1);
+ if (!a)
+ return -ENOMEM;
+
+ a->path = strdup(path);
+ if (!a->path) {
+ free(a);
+ return -ENOMEM;
+ }
+
+ for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
+ a->limits[type] = cgroup_io_limit_defaults[type];
+
+ LIST_PREPEND(device_limits, c->io_device_limits, a);
+ }
+
+ a->limits[iol_type] = u64;
+ }
+
+ n++;
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ CGroupIODeviceLimit *a;
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ size_t size = 0;
+
+ if (n == 0) {
+ LIST_FOREACH(device_limits, a, c->io_device_limits)
+ a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
+ }
+
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ f = open_memstream(&buf, &size);
+ if (!f)
+ return -ENOMEM;
+
+ fprintf(f, "%s=\n", name);
+ LIST_FOREACH(device_limits, a, c->io_device_limits)
+ if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
+ fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private(u, mode, name, buf);
+ }
+
+ return 1;
+
+ } else if (streq(name, "IODeviceWeight")) {
+ const char *path;
+ uint64_t weight;
+ unsigned n = 0;
+
+ r = sd_bus_message_enter_container(message, 'a', "(st)");
+ if (r < 0)
+ return r;
+
+ while ((r = sd_bus_message_read(message, "(st)", &path, &weight)) > 0) {
+
+ if (!CGROUP_WEIGHT_IS_OK(weight) || weight == CGROUP_WEIGHT_INVALID)
+ return sd_bus_error_set_errnof(error, EINVAL, "IODeviceWeight out of range");
+
+ if (mode != UNIT_CHECK) {
+ CGroupIODeviceWeight *a = NULL, *b;
+
+ LIST_FOREACH(device_weights, b, c->io_device_weights) {
+ if (path_equal(b->path, path)) {
+ a = b;
+ break;
+ }
+ }
+
+ if (!a) {
+ a = new0(CGroupIODeviceWeight, 1);
+ if (!a)
+ return -ENOMEM;
+
+ a->path = strdup(path);
+ if (!a->path) {
+ free(a);
+ return -ENOMEM;
+ }
+ LIST_PREPEND(device_weights,c->io_device_weights, a);
+ }
+
+ a->weight = weight;
+ }
+
+ n++;
+ }
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *buf = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ CGroupIODeviceWeight *a;
+ size_t size = 0;
+
+ if (n == 0) {
+ while (c->io_device_weights)
+ cgroup_context_free_io_device_weight(c, c->io_device_weights);
+ }
+
+ unit_invalidate_cgroup(u, CGROUP_MASK_IO);
+
+ f = open_memstream(&buf, &size);
+ if (!f)
+ return -ENOMEM;
+
+ fputs("IODeviceWeight=\n", f);
+ LIST_FOREACH(device_weights, a, c->io_device_weights)
+ fprintf(f, "IODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+ unit_write_drop_in_private(u, mode, name, buf);
+ }
+
+ return 1;
+
} else if (streq(name, "BlockIOAccounting")) {
int b;
@@ -359,7 +657,7 @@ int bus_cgroup_set_property(
CGroupBlockIODeviceBandwidth *a = NULL, *b;
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- if (path_equal(path, b->path) && read == b->read) {
+ if (path_equal(path, b->path)) {
a = b;
break;
}
@@ -370,7 +668,8 @@ int bus_cgroup_set_property(
if (!a)
return -ENOMEM;
- a->read = read;
+ a->rbps = CGROUP_LIMIT_MAX;
+ a->wbps = CGROUP_LIMIT_MAX;
a->path = strdup(path);
if (!a->path) {
free(a);
@@ -380,7 +679,10 @@ int bus_cgroup_set_property(
LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
}
- a->bandwidth = u64;
+ if (read)
+ a->rbps = u64;
+ else
+ a->wbps = u64;
}
n++;
@@ -393,15 +695,18 @@ int bus_cgroup_set_property(
return r;
if (mode != UNIT_CHECK) {
- CGroupBlockIODeviceBandwidth *a, *next;
+ CGroupBlockIODeviceBandwidth *a;
_cleanup_free_ char *buf = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t size = 0;
if (n == 0) {
- LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
- if (a->read == read)
- cgroup_context_free_blockio_device_bandwidth(c, a);
+ LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
+ if (read)
+ a->rbps = CGROUP_LIMIT_MAX;
+ else
+ a->wbps = CGROUP_LIMIT_MAX;
+ }
}
unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
@@ -413,13 +718,13 @@ int bus_cgroup_set_property(
if (read) {
fputs("BlockIOReadBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
- if (a->read)
- fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
+ if (a->rbps != CGROUP_LIMIT_MAX)
+ fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
} else {
fputs("BlockIOWriteBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
- if (!a->read)
- fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
+ if (a->wbps != CGROUP_LIMIT_MAX)
+ fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
}
r = fflush_and_check(f);
diff --git a/src/libcore/dbus-execute.c b/src/libcore/dbus-execute.c
index f2fc301f8e..06943c6365 100644
--- a/src/libcore/dbus-execute.c
+++ b/src/libcore/dbus-execute.c
@@ -312,7 +312,7 @@ static int property_get_ambient_capabilities(
return sd_bus_message_append(reply, "t", c->capability_ambient_set);
}
-static int property_get_capabilities(
+static int property_get_empty_string(
sd_bus *bus,
const char *path,
const char *interface,
@@ -321,23 +321,10 @@ static int property_get_capabilities(
void *userdata,
sd_bus_error *error) {
- ExecContext *c = userdata;
- _cleanup_cap_free_charp_ char *t = NULL;
- const char *s;
-
assert(bus);
assert(reply);
- assert(c);
-
- if (c->capabilities)
- s = t = cap_to_text(c->capabilities, NULL);
- else
- s = "";
- if (!s)
- return -ENOMEM;
-
- return sd_bus_message_append(reply, "s", s);
+ return sd_bus_message_append(reply, "s", "");
}
static int property_get_syscall_filter(
@@ -700,7 +687,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
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("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
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),
SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -850,18 +837,10 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
- if (isempty(uu)) {
+ if (isempty(uu))
c->user = mfree(c->user);
- } else {
- char *t;
-
- t = strdup(uu);
- if (!t)
- return -ENOMEM;
-
- free(c->user);
- c->user = t;
- }
+ else if (free_and_strdup(&c->user, uu) < 0)
+ return -ENOMEM;
unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
}
@@ -877,18 +856,10 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
- if (isempty(gg)) {
+ if (isempty(gg))
c->group = mfree(c->group);
- } else {
- char *t;
-
- t = strdup(gg);
- if (!t)
- return -ENOMEM;
-
- free(c->group);
- c->group = t;
- }
+ else if (free_and_strdup(&c->group, gg) < 0)
+ return -ENOMEM;
unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
}
@@ -903,18 +874,10 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
- if (isempty(id)) {
+ 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;
- }
+ else if (free_and_strdup(&c->syslog_identifier, id) < 0)
+ return -ENOMEM;
unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
}
@@ -1491,6 +1454,24 @@ int bus_exec_context_set_transient_property(
return 1;
+ } else if (streq(name, "SELinuxContext")) {
+ const char *s;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ if (isempty(s))
+ c->selinux_context = mfree(c->selinux_context);
+ else if (free_and_strdup(&c->selinux_context, s) < 0)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, strempty(s));
+ }
+
+ return 1;
+
}
ri = rlimit_from_string(name);
diff --git a/src/libcore/dbus-job.c b/src/libcore/dbus-job.c
index 337cef8a4f..1d739787bb 100644
--- a/src/libcore/dbus-job.c
+++ b/src/libcore/dbus-job.c
@@ -75,7 +75,7 @@ int bus_job_method_cancel(sd_bus_message *message, void *userdata, sd_bus_error
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
}
- job_finish_and_invalidate(j, JOB_CANCELED, true);
+ job_finish_and_invalidate(j, JOB_CANCELED, true, false);
return sd_bus_reply_method_return(message, NULL);
}
diff --git a/src/libcore/dbus-kill.c b/src/libcore/dbus-kill.c
index fc50fafaad..0f54c6b84b 100644
--- a/src/libcore/dbus-kill.c
+++ b/src/libcore/dbus-kill.c
@@ -58,7 +58,7 @@ int bus_kill_context_set_transient_property(
k = kill_mode_from_string(m);
if (k < 0)
- return -EINVAL;
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Kill mode '%s' not known.", m);
if (mode != UNIT_CHECK) {
c->kill_mode = k;
@@ -75,7 +75,7 @@ int bus_kill_context_set_transient_property(
if (r < 0)
return r;
- if (sig <= 0 || sig >= _NSIG)
+ if (!SIGNAL_VALID(sig))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal %i out of range", sig);
if (mode != UNIT_CHECK) {
diff --git a/src/libcore/dbus-manager.c b/src/libcore/dbus-manager.c
index f939196397..86722e1162 100644
--- a/src/libcore/dbus-manager.c
+++ b/src/libcore/dbus-manager.c
@@ -139,7 +139,7 @@ static int property_get_tainted(
if (access("/proc/cgroups", F_OK) < 0)
e = stpcpy(e, "cgroups-missing:");
- if (clock_is_localtime() > 0)
+ if (clock_is_localtime(NULL) > 0)
e = stpcpy(e, "local-hwclock:");
/* remove the last ':' */
@@ -642,6 +642,104 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
return bus_unit_method_set_properties(message, u, error);
}
+static int reply_unit_info(sd_bus_message *reply, Unit *u) {
+ _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
+ Unit *following;
+
+ following = unit_following(u);
+
+ unit_path = unit_dbus_path(u);
+ if (!unit_path)
+ return -ENOMEM;
+
+ if (u->job) {
+ job_path = job_dbus_path(u->job);
+ if (!job_path)
+ return -ENOMEM;
+ }
+
+ return sd_bus_message_append(
+ reply, "(ssssssouso)",
+ u->id,
+ unit_description(u),
+ unit_load_state_to_string(u->load_state),
+ unit_active_state_to_string(unit_active_state(u)),
+ unit_sub_state_to_string(u),
+ following ? following->id : "",
+ unit_path,
+ u->job ? u->job->id : 0,
+ u->job ? job_type_to_string(u->job->type) : "",
+ job_path ? job_path : "/");
+}
+
+static int method_list_units_by_names(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ Manager *m = userdata;
+ int r;
+ char **unit;
+ _cleanup_strv_free_ char **units = NULL;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read_strv(message, &units);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)");
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(unit, units) {
+ Unit *u;
+
+ if (!unit_name_is_valid(*unit, UNIT_NAME_ANY))
+ continue;
+
+ r = manager_load_unit(m, *unit, NULL, error, &u);
+ if (r < 0)
+ return r;
+
+ r = reply_unit_info(reply, u);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
+static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ Manager *m = userdata;
+ const char *name;
+ Unit *u;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read(message, "s", &name);
+ if (r < 0)
+ return r;
+
+ r = manager_load_unit(m, name, NULL, error, &u);
+ if (r < 0)
+ return r;
+
+ r = bus_unit_check_load_state(u, error);
+ if (r < 0)
+ return r;
+
+ return bus_unit_method_get_processes(message, u, error);
+}
+
static int transient_unit_from_message(
Manager *m,
sd_bus_message *message,
@@ -865,7 +963,7 @@ static int method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_e
return sd_bus_reply_method_return(message, NULL);
}
-static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states) {
+static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = userdata;
const char *k;
@@ -891,42 +989,20 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e
return r;
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
- Unit *following;
-
if (k != u->id)
continue;
- following = unit_following(u);
-
if (!strv_isempty(states) &&
!strv_contains(states, unit_load_state_to_string(u->load_state)) &&
!strv_contains(states, unit_active_state_to_string(unit_active_state(u))) &&
!strv_contains(states, unit_sub_state_to_string(u)))
continue;
- unit_path = unit_dbus_path(u);
- if (!unit_path)
- return -ENOMEM;
-
- if (u->job) {
- job_path = job_dbus_path(u->job);
- if (!job_path)
- return -ENOMEM;
- }
+ if (!strv_isempty(patterns) &&
+ !strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
+ continue;
- r = sd_bus_message_append(
- reply, "(ssssssouso)",
- u->id,
- unit_description(u),
- unit_load_state_to_string(u->load_state),
- unit_active_state_to_string(unit_active_state(u)),
- unit_sub_state_to_string(u),
- following ? following->id : "",
- unit_path,
- u->job ? u->job->id : 0,
- u->job ? job_type_to_string(u->job->type) : "",
- job_path ? job_path : "/");
+ r = reply_unit_info(reply, u);
if (r < 0)
return r;
}
@@ -939,7 +1015,7 @@ static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_e
}
static int method_list_units(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return list_units_filtered(message, userdata, error, NULL);
+ return list_units_filtered(message, userdata, error, NULL, NULL);
}
static int method_list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -950,7 +1026,23 @@ static int method_list_units_filtered(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
- return list_units_filtered(message, userdata, error, states);
+ return list_units_filtered(message, userdata, error, states, NULL);
+}
+
+static int method_list_units_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_strv_free_ char **states = NULL;
+ _cleanup_strv_free_ char **patterns = NULL;
+ int r;
+
+ r = sd_bus_message_read_strv(message, &states);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read_strv(message, &patterns);
+ if (r < 0)
+ return r;
+
+ return list_units_filtered(message, userdata, error, states, patterns);
}
static int method_list_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1187,7 +1279,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *
if (r < 0)
return r;
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
m->exit_code = MANAGER_REBOOT;
@@ -1206,7 +1298,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
m->exit_code = MANAGER_POWEROFF;
@@ -1225,7 +1317,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er
if (r < 0)
return r;
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
m->exit_code = MANAGER_HALT;
@@ -1244,7 +1336,7 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e
if (r < 0)
return r;
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
m->exit_code = MANAGER_KEXEC;
@@ -1265,7 +1357,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
if (r < 0)
return r;
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
r = sd_bus_message_read(message, "ss", &root, &init);
@@ -1433,7 +1525,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_
if (r < 0)
return r;
- if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0)
+ if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
m->return_value = code;
@@ -1441,7 +1533,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_reply_method_return(message, NULL);
}
-static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
Manager *m = userdata;
UnitFileList *item;
@@ -1466,7 +1558,7 @@ static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bu
if (!h)
return -ENOMEM;
- r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
+ r = unit_file_get_list(m->unit_file_scope, NULL, h, states, patterns);
if (r < 0)
goto fail;
@@ -1494,11 +1586,30 @@ fail:
return r;
}
+static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return list_unit_files_by_patterns(message, userdata, error, NULL, NULL);
+}
+
+static int method_list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_strv_free_ char **states = NULL;
+ _cleanup_strv_free_ char **patterns = NULL;
+ int r;
+
+ r = sd_bus_message_read_strv(message, &states);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_read_strv(message, &patterns);
+ if (r < 0)
+ return r;
+
+ return list_unit_files_by_patterns(message, userdata, error, states, patterns);
+}
+
static int method_get_unit_file_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
UnitFileState state;
- UnitFileScope scope;
int r;
assert(message);
@@ -1514,9 +1625,7 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
if (r < 0)
return r;
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_get_state(scope, NULL, name, &state);
+ r = unit_file_get_state(m->unit_file_scope, NULL, name, &state);
if (r < 0)
return r;
@@ -1526,7 +1635,6 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
static int method_get_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *default_target = NULL;
Manager *m = userdata;
- UnitFileScope scope;
int r;
assert(message);
@@ -1538,9 +1646,7 @@ static int method_get_default_target(sd_bus_message *message, void *userdata, sd
if (r < 0)
return r;
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_get_default(scope, NULL, &default_target);
+ r = unit_file_get_default(m->unit_file_scope, NULL, &default_target);
if (r < 0)
return r;
@@ -1571,7 +1677,7 @@ static int reply_unit_file_changes_and_free(
unsigned i;
int r;
- if (n_changes > 0) {
+ if (unit_file_changes_have_modification(changes, n_changes)) {
r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
if (r < 0)
log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
@@ -1591,15 +1697,19 @@ static int reply_unit_file_changes_and_free(
if (r < 0)
goto fail;
- for (i = 0; i < n_changes; i++) {
- r = sd_bus_message_append(
- reply, "(sss)",
- unit_file_change_type_to_string(changes[i].type),
- changes[i].path,
- changes[i].source);
- if (r < 0)
- goto fail;
- }
+ for (i = 0; i < n_changes; i++)
+ if (changes[i].type >= 0) {
+ const char *change = unit_file_change_type_to_string(changes[i].type);
+ assert(change != NULL);
+
+ r = sd_bus_message_append(
+ reply, "(sss)",
+ change,
+ changes[i].path,
+ changes[i].source);
+ if (r < 0)
+ goto fail;
+ }
r = sd_bus_message_close_container(reply);
if (r < 0)
@@ -1613,10 +1723,61 @@ fail:
return r;
}
+/* Create an error reply, using the error information from changes[]
+ * if possible, and fall back to generating an error from error code c.
+ * The error message only describes the first error.
+ *
+ * Coordinate with unit_file_dump_changes() in install.c.
+ */
+static int install_error(
+ sd_bus_error *error,
+ int c,
+ UnitFileChange *changes,
+ unsigned n_changes) {
+ int r;
+ unsigned i;
+ assert(c < 0);
+
+ for (i = 0; i < n_changes; i++)
+ switch(changes[i].type) {
+ case 0 ... INT_MAX:
+ continue;
+ case -EEXIST:
+ if (changes[i].source)
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
+ "File %s already exists and is a symlink to %s.",
+ changes[i].path, changes[i].source);
+ else
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS,
+ "File %s already exists.",
+ changes[i].path);
+ goto found;
+ case -ERFKILL:
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED,
+ "Unit file %s is masked.", changes[i].path);
+ goto found;
+ case -EADDRNOTAVAIL:
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_GENERATED,
+ "Unit %s is transient or generated.", changes[i].path);
+ goto found;
+ case -ELOOP:
+ r = sd_bus_error_setf(error, BUS_ERROR_UNIT_LINKED,
+ "Refusing to operate on linked unit file %s", changes[i].path);
+ goto found;
+ default:
+ r = sd_bus_error_set_errnof(error, changes[i].type, "File %s: %m", changes[i].path);
+ goto found;
+ }
+
+ r = c;
+ found:
+ unit_file_changes_free(changes, n_changes);
+ return r;
+}
+
static int method_enable_unit_files_generic(
sd_bus_message *message,
Manager *m,
- const char *verb,
int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes),
bool carries_install_info,
sd_bus_error *error) {
@@ -1624,7 +1785,6 @@ static int method_enable_unit_files_generic(
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
- UnitFileScope scope;
int runtime, force, r;
assert(message);
@@ -1644,27 +1804,23 @@ static int method_enable_unit_files_generic(
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
- if (r == -ESHUTDOWN)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
+ r = call(m->unit_file_scope, runtime, NULL, l, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
}
static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "enable", unit_file_enable, true, error);
+ return method_enable_unit_files_generic(message, userdata, unit_file_enable, true, error);
}
static int method_reenable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "enable", unit_file_reenable, true, error);
+ return method_enable_unit_files_generic(message, userdata, unit_file_reenable, true, error);
}
static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "enable", unit_file_link, false, error);
+ return method_enable_unit_files_generic(message, userdata, unit_file_link, false, error);
}
static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) {
@@ -1672,11 +1828,11 @@ static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, cons
}
static int method_preset_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "enable", unit_file_preset_without_mode, true, error);
+ return method_enable_unit_files_generic(message, userdata, unit_file_preset_without_mode, true, error);
}
static int method_mask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "disable", unit_file_mask, false, error);
+ return method_enable_unit_files_generic(message, userdata, unit_file_mask, false, error);
}
static int method_preset_unit_files_with_mode(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1686,7 +1842,6 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
unsigned n_changes = 0;
Manager *m = userdata;
UnitFilePresetMode mm;
- UnitFileScope scope;
int runtime, force, r;
const char *mode;
@@ -1715,26 +1870,22 @@ static int method_preset_unit_files_with_mode(sd_bus_message *message, void *use
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes);
+ r = unit_file_preset(m->unit_file_scope, runtime, NULL, l, mm, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, r, changes, n_changes);
}
static int method_disable_unit_files_generic(
sd_bus_message *message,
- Manager *m, const
- char *verb,
+ Manager *m,
int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
sd_bus_error *error) {
_cleanup_strv_free_ char **l = NULL;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
- UnitFileScope scope;
int r, runtime;
assert(message);
@@ -1748,34 +1899,58 @@ static int method_disable_unit_files_generic(
if (r < 0)
return r;
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
r = bus_verify_manage_unit_files_async(m, message, error);
if (r < 0)
return r;
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- r = call(scope, runtime, NULL, l, &changes, &n_changes);
+ r = call(m->unit_file_scope, runtime, NULL, l, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(message, userdata, "disable", unit_file_disable, error);
+ return method_disable_unit_files_generic(message, userdata, unit_file_disable, error);
}
static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(message, userdata, "enable", unit_file_unmask, error);
+ return method_disable_unit_files_generic(message, userdata, unit_file_unmask, error);
+}
+
+static int method_revert_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_strv_free_ char **l = NULL;
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+ Manager *m = userdata;
+ int r;
+
+ assert(message);
+ assert(m);
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ r = bus_verify_manage_unit_files_async(m, message, error);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ r = unit_file_revert(m->unit_file_scope, NULL, l, &changes, &n_changes);
+ if (r < 0)
+ return install_error(error, r, changes, n_changes);
+
+ return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
static int method_set_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
Manager *m = userdata;
- UnitFileScope scope;
const char *name;
int force, r;
@@ -1796,11 +1971,9 @@ static int method_set_default_target(sd_bus_message *message, void *userdata, sd
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
+ r = unit_file_set_default(m->unit_file_scope, NULL, name, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@@ -1810,7 +1983,6 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
unsigned n_changes = 0;
Manager *m = userdata;
UnitFilePresetMode mm;
- UnitFileScope scope;
const char *mode;
int force, runtime, r;
@@ -1839,13 +2011,9 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata,
if (r == 0)
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
- if (r < 0) {
- unit_file_changes_free(changes, n_changes);
- return r;
- }
+ r = unit_file_preset_all(m->unit_file_scope, runtime, NULL, mm, force, &changes, &n_changes);
+ if (r < 0)
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@@ -1855,10 +2023,8 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
Manager *m = userdata;
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
- UnitFileScope scope;
int runtime, force, r;
- char *target;
- char *type;
+ char *target, *type;
UnitDependency dep;
assert(message);
@@ -1882,13 +2048,9 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
if (dep < 0)
return -EINVAL;
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
- if (r == -ESHUTDOWN)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
+ r = unit_file_add_dependency(m->unit_file_scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
if (r < 0)
- return r;
+ return install_error(error, r, changes, n_changes);
return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
}
@@ -1924,7 +2086,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(Manager, environment), 0),
SD_BUS_PROPERTY("ConfirmSpawn", "b", bus_property_get_bool, offsetof(Manager, confirm_spawn), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ShowStatus", "b", bus_property_get_bool, offsetof(Manager, show_status), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_path), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
@@ -1936,7 +2098,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */
SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1992,12 +2155,15 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnitsFiltered", "as", "a(ssssssouso)", method_list_units_filtered, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ListUnitsByPatterns", "asas", "a(ssssssouso)", method_list_units_by_patterns, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ListUnitsByNames", "as", "a(ssssssouso)", method_list_units_by_names, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2016,6 +2182,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("ListUnitFilesByPatterns", "asas", "a(ss)", method_list_unit_files_by_patterns, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -2025,6 +2192,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("PresetUnitFilesWithMode", "assbb", "ba(sss)", method_preset_unit_files_with_mode, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("RevertUnitFiles", "as", "a(sss)", method_revert_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/libcore/dbus-socket.c b/src/libcore/dbus-socket.c
index d33e494f6b..961340608d 100644
--- a/src/libcore/dbus-socket.c
+++ b/src/libcore/dbus-socket.c
@@ -149,6 +149,8 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TriggerLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/libcore/dbus-timer.c b/src/libcore/dbus-timer.c
index bc121b83a2..a0e61b023e 100644
--- a/src/libcore/dbus-timer.c
+++ b/src/libcore/dbus-timer.c
@@ -156,7 +156,7 @@ static int property_get_next_elapse_monotonic(
usec_t a, b;
a = now(CLOCK_MONOTONIC);
- b = now(CLOCK_BOOTTIME);
+ b = now(clock_boottime_or_monotonic());
if (t->next_elapse_monotonic_or_boottime + a > b)
x = t->next_elapse_monotonic_or_boottime + a - b;
diff --git a/src/libcore/dbus-unit.c b/src/libcore/dbus-unit.c
index 9a09f59fc2..dcd8db0898 100644
--- a/src/libcore/dbus-unit.c
+++ b/src/libcore/dbus-unit.c
@@ -24,9 +24,12 @@
#include "cgroup-util.h"
#include "dbus-unit.h"
#include "dbus.h"
+#include "fd-util.h"
#include "locale-util.h"
#include "log.h"
+#include "process-util.h"
#include "selinux-access.h"
+#include "signal-util.h"
#include "special.h"
#include "string-util.h"
#include "strv.h"
@@ -547,7 +550,7 @@ int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
}
- if (signo <= 0 || signo >= _NSIG)
+ if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
r = bus_verify_manage_units_async_full(
@@ -701,7 +704,8 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -840,6 +844,145 @@ static int property_get_cgroup(
return sd_bus_message_append(reply, "s", t);
}
+static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) {
+ _cleanup_free_ char *buf = NULL, *cmdline = NULL;
+ int r;
+
+ assert(reply);
+ assert(pid > 0);
+
+ r = set_put(pids, PID_TO_PTR(pid));
+ if (r == -EEXIST || r == 0)
+ return 0;
+ if (r < 0)
+ return r;
+
+ if (!p) {
+ r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf);
+ if (r == -ESRCH)
+ return 0;
+ if (r < 0)
+ return r;
+
+ p = buf;
+ }
+
+ (void) get_process_cmdline(pid, 0, true, &cmdline);
+
+ return sd_bus_message_append(reply,
+ "(sus)",
+ p,
+ (uint32_t) pid,
+ cmdline);
+}
+
+static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
+ _cleanup_closedir_ DIR *d = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
+
+ assert(reply);
+ assert(p);
+
+ r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f);
+ if (r == ENOENT)
+ return 0;
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ pid_t pid;
+
+ r = cg_read_pid(f, &pid);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (is_kernel_thread(pid) > 0)
+ continue;
+
+ r = append_process(reply, p, pid, pids);
+ if (r < 0)
+ return r;
+ }
+
+ r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ _cleanup_free_ char *g = NULL, *j = NULL;
+
+ r = cg_read_subgroup(d, &g);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ j = strjoin(p, "/", g, NULL);
+ if (!j)
+ return -ENOMEM;
+
+ r = append_cgroup(reply, j, pids);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(set_freep) Set *pids = NULL;
+ Unit *u = userdata;
+ pid_t pid;
+ int r;
+
+ assert(message);
+
+ pids = set_new(NULL);
+ if (!pids)
+ return -ENOMEM;
+
+ r = sd_bus_message_new_method_return(message, &reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(reply, 'a', "(sus)");
+ if (r < 0)
+ return r;
+
+ if (u->cgroup_path) {
+ r = append_cgroup(reply, u->cgroup_path, pids);
+ if (r < 0)
+ return r;
+ }
+
+ /* The main and control pids might live outside of the cgroup, hence fetch them separately */
+ pid = unit_main_pid(u);
+ if (pid > 0) {
+ r = append_process(reply, NULL, pid, pids);
+ if (r < 0)
+ return r;
+ }
+
+ pid = unit_control_pid(u);
+ if (pid > 0) {
+ r = append_process(reply, NULL, pid, pids);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(reply);
+ if (r < 0)
+ return r;
+
+ return sd_bus_send(NULL, reply, NULL);
+}
+
const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
@@ -847,6 +990,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
+ SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};
@@ -1002,7 +1146,6 @@ int bus_unit_queue_job(
type = JOB_TRY_RELOAD;
}
-
if (type == JOB_STOP &&
(u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
unit_active_state(u) == UNIT_INACTIVE)
@@ -1099,7 +1242,10 @@ static int bus_unit_set_transient_property(
if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
- r = manager_load_unit(u->manager, s, NULL, error, &slice);
+ /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be
+ * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare()
+ * instead of manager_load_unit() on purpose, here. */
+ r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice);
if (r < 0)
return r;
@@ -1259,6 +1405,7 @@ int bus_unit_set_properties(
}
int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
+ assert(u);
if (u->load_state == UNIT_LOADED)
return 0;
diff --git a/src/libcore/dbus-unit.h b/src/libcore/dbus-unit.h
index 1a0070fce6..758045a47c 100644
--- a/src/libcore/dbus-unit.h
+++ b/src/libcore/dbus-unit.h
@@ -36,5 +36,6 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_check_load_state(Unit *u, sd_bus_error *error);
diff --git a/src/libcore/dbus.c b/src/libcore/dbus.c
index dc939b023a..1b217da303 100644
--- a/src/libcore/dbus.c
+++ b/src/libcore/dbus.c
@@ -71,28 +71,42 @@ int bus_send_queued_message(Manager *m) {
return 0;
}
+int bus_forward_agent_released(Manager *m, const char *path) {
+ int r;
+
+ assert(m);
+ assert(path);
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return 0;
+
+ if (!m->system_bus)
+ return 0;
+
+ /* If we are running a system instance we forward the agent message on the system bus, so that the user
+ * instances get notified about this, too */
+
+ r = sd_bus_emit_signal(m->system_bus,
+ "/org/freedesktop/systemd1/agent",
+ "org.freedesktop.systemd1.Agent",
+ "Released",
+ "s", path);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to propagate agent release message: %m");
+
+ return 1;
+}
+
static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- const char *cgroup, *me;
Manager *m = userdata;
+ const char *cgroup;
uid_t sender_uid;
- sd_bus *bus;
int r;
assert(message);
assert(m);
- /* ignore recursive events sent by us on the system/user bus */
- bus = sd_bus_message_get_bus(message);
- if (!sd_bus_is_server(bus)) {
- r = sd_bus_get_unique_name(bus, &me);
- if (r < 0)
- return r;
-
- if (streq_ptr(sd_bus_message_get_sender(message), me))
- return 0;
- }
-
/* only accept org.freedesktop.systemd1.Agent from UID=0 */
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
@@ -110,16 +124,6 @@ static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus
}
manager_notify_cgroup_empty(m, cgroup);
-
- /* if running as system-instance, forward under our name */
- if (m->running_as == MANAGER_SYSTEM && m->system_bus) {
- r = sd_bus_message_rewind(message, 1);
- if (r >= 0)
- r = sd_bus_send(m->system_bus, message, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to forward Released message: %m");
- }
-
return 0;
}
@@ -690,25 +694,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
return 0;
}
- if (m->running_as == MANAGER_SYSTEM) {
- /* When we run as system instance we get the Released
- * signal via a direct connection */
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- signal_agent_released, m);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
- return 0;
- }
- }
-
r = bus_setup_disconnected_match(m, bus);
if (r < 0)
return 0;
@@ -864,10 +849,10 @@ static int bus_init_api(Manager *m) {
return 0;
/* The API and system bus is the same if we are running in system mode */
- if (m->running_as == MANAGER_SYSTEM && m->system_bus)
+ if (MANAGER_IS_SYSTEM(m) && m->system_bus)
bus = sd_bus_ref(m->system_bus);
else {
- if (m->running_as == MANAGER_SYSTEM)
+ if (MANAGER_IS_SYSTEM(m))
r = sd_bus_open_system(&bus);
else
r = sd_bus_open_user(&bus);
@@ -906,8 +891,8 @@ static int bus_setup_system(Manager *m, sd_bus *bus) {
assert(m);
assert(bus);
- /* On kdbus or if we are a user instance we get the Released message via the system bus */
- if (m->running_as == MANAGER_USER || m->kdbus_fd >= 0) {
+ /* if we are a user instance we get the Released message via the system bus */
+ if (MANAGER_IS_USER(m)) {
r = sd_bus_add_match(
bus,
NULL,
@@ -932,7 +917,7 @@ static int bus_init_system(Manager *m) {
return 0;
/* The API and system bus is the same if we are running in system mode */
- if (m->running_as == MANAGER_SYSTEM && m->api_bus) {
+ if (MANAGER_IS_SYSTEM(m) && m->api_bus) {
m->system_bus = sd_bus_ref(m->api_bus);
return 0;
}
@@ -983,14 +968,14 @@ static int bus_init_private(Manager *m) {
if (m->kdbus_fd >= 0)
return 0;
- if (m->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(m)) {
/* We want the private bus only when running as init */
if (getpid() != 1)
return 0;
strcpy(sa.un.sun_path, "/run/systemd/private");
- salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
+ salen = SOCKADDR_UN_LEN(sa.un);
} else {
size_t left = sizeof(sa.un.sun_path);
char *p = sa.un.sun_path;
@@ -1082,7 +1067,7 @@ static void destroy_bus(Manager *m, sd_bus **bus) {
/* Possibly flush unwritten data, but only if we are
* unprivileged, since we don't want to sync here */
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
sd_bus_flush(*bus);
/* And destroy the object */
diff --git a/src/libcore/dbus.h b/src/libcore/dbus.h
index e16a84fbb8..6baaffbd75 100644
--- a/src/libcore/dbus.h
+++ b/src/libcore/dbus.h
@@ -40,3 +40,5 @@ int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error
int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
+
+int bus_forward_agent_released(Manager *m, const char *path);
diff --git a/src/libcore/device.c b/src/libcore/device.c
index d201dc5e4b..16e56efcc3 100644
--- a/src/libcore/device.c
+++ b/src/libcore/device.c
@@ -265,7 +265,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
assert(u);
assert(dev);
- property = u->manager->running_as == MANAGER_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
+ property = MANAGER_IS_USER(u->manager) ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
wants = udev_device_get_property_value(dev, property);
if (!wants)
return 0;
@@ -318,11 +318,11 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa
* the GC to have garbaged it. That's desired since the device
* unit may have a dependency on the mount unit which was
* added during the loading of the later. */
- if (u && DEVICE(u)->state == DEVICE_PLUGGED) {
+ if (dev && u && DEVICE(u)->state == DEVICE_PLUGGED) {
/* This unit is in plugged state: we're sure it's
* attached to a device. */
if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
- log_unit_error(u, "Dev %s appeared twice with different sysfs paths %s and %s",
+ log_unit_debug(u, "Dev %s appeared twice with different sysfs paths %s and %s",
e, DEVICE(u)->sysfs, sysfs);
return -EEXIST;
}
@@ -841,8 +841,6 @@ const UnitVTable device_vtable = {
"Device\0"
"Install\0",
- .no_instances = true,
-
.init = device_init,
.done = device_done,
.load = unit_load_fragment_and_dropin_optional,
diff --git a/src/libcore/execute.c b/src/libcore/execute.c
index 6fd35c8350..b58fb80be2 100644
--- a/src/libcore/execute.c
+++ b/src/libcore/execute.c
@@ -24,6 +24,7 @@
#include <poll.h>
#include <signal.h>
#include <string.h>
+#include <sys/capability.h>
#include <sys/personality.h>
#include <sys/prctl.h>
#include <sys/socket.h>
@@ -57,7 +58,6 @@
#endif
#include "async.h"
#include "barrier.h"
-#include "bus-endpoint.h"
#include "cap-list.h"
#include "capability-util.h"
#include "def.h"
@@ -271,7 +271,7 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
}
}
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
r = -errno;
@@ -747,10 +747,10 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_
static int enforce_user(const ExecContext *context, uid_t uid) {
assert(context);
- /* Sets (but doesn't lookup) the uid and make sure we keep the
+ /* Sets (but doesn't look up) the uid and make sure we keep the
* capabilities while doing so. */
- if (context->capabilities || context->capability_ambient_set != 0) {
+ if (context->capability_ambient_set != 0) {
/* First step: If we need to keep capabilities but
* drop privileges we need to make sure we keep our
@@ -762,31 +762,9 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
if (prctl(PR_SET_SECUREBITS, sb) < 0)
return -errno;
}
-
- /* Second step: set the capabilities. This will reduce
- * the capabilities to the minimum we need. */
-
- if (context->capabilities) {
- _cleanup_cap_free_ cap_t d = NULL;
- static const cap_value_t bits[] = {
- CAP_SETUID, /* Necessary so that we can run setresuid() below */
- CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
- };
-
- d = cap_dup(context->capabilities);
- if (!d)
- return -errno;
-
- if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
- cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
- return -errno;
-
- if (cap_set_proc(d) < 0)
- return -errno;
- }
}
- /* Third step: actually set the uids */
+ /* Second step: actually set the uids */
if (setresuid(uid, uid, uid) < 0)
return -errno;
@@ -1387,9 +1365,6 @@ static bool exec_needs_mount_namespace(
if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
return true;
- if (params->bus_endpoint_path)
- return true;
-
if (context->private_devices ||
context->protect_system != PROTECT_SYSTEM_NO ||
context->protect_home != PROTECT_HOME_NO)
@@ -1423,9 +1398,6 @@ static int close_remaining_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];
@@ -1655,16 +1627,6 @@ static int exec_child(
}
}
- if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) {
- uid_t ep_uid = (uid == UID_INVALID) ? 0 : uid;
-
- r = bus_kernel_set_endpoint_policy(params->bus_endpoint_fd, ep_uid, context->bus_endpoint);
- if (r < 0) {
- *exit_status = EXIT_BUS_ENDPOINT;
- return r;
- }
- }
-
/* If delegation is enabled we'll pass ownership of the cgroup
* (but only in systemd's own controller hierarchy!) to the
* user of the new process. */
@@ -1787,7 +1749,6 @@ static int exec_child(
context->inaccessible_dirs,
tmp,
var,
- params->bus_endpoint_path,
context->private_devices,
context->protect_home,
context->protect_system,
@@ -1864,6 +1825,11 @@ static int exec_child(
if (params->apply_permissions) {
+ bool use_address_families = context->address_families_whitelist ||
+ !set_isempty(context->address_families);
+ bool use_syscall_filter = context->syscall_whitelist ||
+ !set_isempty(context->syscall_filter) ||
+ !set_isempty(context->syscall_archs);
int secure_bits = context->secure_bits;
for (i = 0; i < _RLIMIT_MAX; i++) {
@@ -1892,21 +1858,6 @@ static int exec_child(
*exit_status = EXIT_CAPABILITIES;
return r;
}
-
- if (context->capabilities) {
-
- /* The capabilities in ambient set need to be also in the inherited
- * set. If they aren't, trying to get them will fail. Add the ambient
- * set inherited capabilities to the capability set in the context.
- * This is needed because if capabilities are set (using "Capabilities="
- * keyword), they will override whatever we set now. */
-
- r = capability_update_inherited_set(context->capabilities, context->capability_ambient_set);
- if (r < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return r;
- }
- }
}
if (context->user) {
@@ -1931,7 +1882,7 @@ static int exec_child(
* also to the context secure_bits so that we don't try to
* drop the bit away next. */
- secure_bits |= 1<<SECURE_KEEP_CAPS;
+ secure_bits |= 1<<SECURE_KEEP_CAPS;
}
}
@@ -1945,21 +1896,15 @@ static int exec_child(
return -errno;
}
- if (context->capabilities)
- if (cap_set_proc(context->capabilities) < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return -errno;
- }
-
- if (context->no_new_privileges)
+ if (context->no_new_privileges ||
+ (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || use_syscall_filter)))
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
*exit_status = EXIT_NO_NEW_PRIVILEGES;
return -errno;
}
#ifdef HAVE_SECCOMP
- if (context->address_families_whitelist ||
- !set_isempty(context->address_families)) {
+ if (use_address_families) {
r = apply_address_families(context);
if (r < 0) {
*exit_status = EXIT_ADDRESS_FAMILIES;
@@ -1967,9 +1912,7 @@ static int exec_child(
}
}
- if (context->syscall_whitelist ||
- !set_isempty(context->syscall_filter) ||
- !set_isempty(context->syscall_archs)) {
+ if (use_syscall_filter) {
r = apply_seccomp(context);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
@@ -2193,11 +2136,6 @@ void exec_context_done(ExecContext *c) {
c->pam_name = mfree(c->pam_name);
- if (c->capabilities) {
- cap_free(c->capabilities);
- c->capabilities = NULL;
- }
-
c->read_only_dirs = strv_free(c->read_only_dirs);
c->read_write_dirs = strv_free(c->read_write_dirs);
c->inaccessible_dirs = strv_free(c->inaccessible_dirs);
@@ -2214,9 +2152,6 @@ void exec_context_done(ExecContext *c) {
c->address_families = set_free(c->address_families);
c->runtime_directory = strv_free(c->runtime_directory);
-
- bus_endpoint_free(c->bus_endpoint);
- c->bus_endpoint = NULL;
}
int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) {
@@ -2306,7 +2241,7 @@ int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) {
if (fn[0] == '-') {
ignore = true;
- fn ++;
+ fn++;
}
if (!path_is_absolute(fn)) {
@@ -2559,14 +2494,6 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
prefix, strna(lvl_str));
}
- if (c->capabilities) {
- _cleanup_cap_free_charp_ char *t;
-
- t = cap_to_text(c->capabilities, NULL);
- if (t)
- fprintf(f, "%sCapabilities: %s\n", prefix, t);
- }
-
if (c->secure_bits)
fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
prefix,
diff --git a/src/libcore/execute.h b/src/libcore/execute.h
index 578f85b6bc..41148bcea2 100644
--- a/src/libcore/execute.h
+++ b/src/libcore/execute.h
@@ -30,7 +30,6 @@ typedef struct ExecParameters ExecParameters;
#include <stdio.h>
#include <sys/capability.h>
-#include "bus-endpoint.h"
#include "fdset.h"
#include "list.h"
#include "missing.h"
@@ -156,10 +155,7 @@ struct ExecContext {
unsigned long mount_flags;
uint64_t capability_bounding_set;
-
uint64_t capability_ambient_set;
-
- cap_t capabilities;
int secure_bits;
int syslog_priority;
@@ -201,9 +197,6 @@ struct ExecContext {
bool ioprio_set:1;
bool cpu_sched_set:1;
bool no_new_privileges_set:1;
-
- /* custom dbus enpoint */
- BusEndpoint *bus_endpoint;
};
#include "cgroup-util.h"
@@ -234,9 +227,6 @@ struct ExecParameters {
int *idle_pipe;
- char *bus_endpoint_path;
- int bus_endpoint_fd;
-
int stdin_fd;
int stdout_fd;
int stderr_fd;
diff --git a/src/libcore/failure-action.c b/src/libcore/failure-action.c
index 39f5519ca1..ddae46190f 100644
--- a/src/libcore/failure-action.c
+++ b/src/libcore/failure-action.c
@@ -47,7 +47,7 @@ int failure_action(
if (action == FAILURE_ACTION_NONE)
return -ECANCELED;
- if (m->running_as == MANAGER_USER) {
+ if (!MANAGER_IS_SYSTEM(m)) {
/* Downgrade all options to simply exiting if we run
* in user mode */
@@ -61,16 +61,17 @@ int failure_action(
case FAILURE_ACTION_REBOOT:
log_and_status(m, "Rebooting as result of failure.");
- update_reboot_param_file(reboot_arg);
- (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL);
+ (void) update_reboot_parameter_and_warn(reboot_arg);
+ (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
break;
case FAILURE_ACTION_REBOOT_FORCE:
log_and_status(m, "Forcibly rebooting as result of failure.");
- update_reboot_param_file(reboot_arg);
+ (void) update_reboot_parameter_and_warn(reboot_arg);
m->exit_code = MANAGER_REBOOT;
+
break;
case FAILURE_ACTION_REBOOT_IMMEDIATE:
@@ -78,9 +79,10 @@ int failure_action(
sync();
- if (reboot_arg) {
+ if (!isempty(reboot_arg)) {
log_info("Rebooting with argument '%s'.", reboot_arg);
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reboot_arg);
+ log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
}
log_info("Rebooting.");
@@ -89,7 +91,7 @@ int failure_action(
case FAILURE_ACTION_POWEROFF:
log_and_status(m, "Powering off as result of failure.");
- (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL);
+ (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
break;
case FAILURE_ACTION_POWEROFF_FORCE:
diff --git a/src/libcore/ima-setup.c b/src/libcore/ima-setup.c
index ff7558d500..d1b0ce76ef 100644
--- a/src/libcore/ima-setup.c
+++ b/src/libcore/ima-setup.c
@@ -3,7 +3,7 @@
Copyright 2010 Lennart Poettering
Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
- TORSEC group -- http://security.polito.it
+ TORSEC group — http://security.polito.it
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
diff --git a/src/libcore/ima-setup.h b/src/libcore/ima-setup.h
index 3bad74b246..472b58cb00 100644
--- a/src/libcore/ima-setup.h
+++ b/src/libcore/ima-setup.h
@@ -5,7 +5,7 @@
Copyright 2010 Lennart Poettering
Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
- TORSEC group -- http://security.polito.it
+ TORSEC group — http://security.polito.it
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
diff --git a/src/libcore/job.c b/src/libcore/job.c
index 1e2f12bba0..42fdcb988a 100644
--- a/src/libcore/job.c
+++ b/src/libcore/job.c
@@ -137,7 +137,7 @@ void job_uninstall(Job *j) {
/* Detach from next 'bigger' objects */
/* daemon-reload should be transparent to job observers */
- if (j->manager->n_reloading <= 0)
+ if (!MANAGER_IS_RELOADING(j->manager))
bus_job_send_removed_signal(j);
*pj = NULL;
@@ -191,7 +191,7 @@ Job* job_install(Job *j) {
if (uj) {
if (job_type_is_conflicting(uj->type, j->type))
- job_finish_and_invalidate(uj, JOB_CANCELED, false);
+ job_finish_and_invalidate(uj, JOB_CANCELED, false, false);
else {
/* not conflicting, i.e. mergeable */
@@ -222,7 +222,7 @@ Job* job_install(Job *j) {
*pj = j;
j->installed = true;
- j->manager->n_installed_jobs ++;
+ j->manager->n_installed_jobs++;
log_unit_debug(j->unit,
"Installed new job %s/%s as %u",
j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
@@ -614,19 +614,19 @@ int job_run_and_invalidate(Job *j) {
if (j) {
if (r == -EALREADY)
- r = job_finish_and_invalidate(j, JOB_DONE, true);
+ r = job_finish_and_invalidate(j, JOB_DONE, true, true);
else if (r == -EBADR)
- r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
+ r = job_finish_and_invalidate(j, JOB_SKIPPED, true, false);
else if (r == -ENOEXEC)
- r = job_finish_and_invalidate(j, JOB_INVALID, true);
+ r = job_finish_and_invalidate(j, JOB_INVALID, true, false);
else if (r == -EPROTO)
- r = job_finish_and_invalidate(j, JOB_ASSERT, true);
+ r = job_finish_and_invalidate(j, JOB_ASSERT, true, false);
else if (r == -EOPNOTSUPP)
- r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true);
+ r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true, false);
else if (r == -EAGAIN)
job_set_state(j, JOB_WAITING);
else if (r < 0)
- r = job_finish_and_invalidate(j, JOB_FAILED, true);
+ r = job_finish_and_invalidate(j, JOB_FAILED, true, false);
}
return r;
@@ -645,7 +645,7 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Stopped %s.",
[JOB_FAILED] = "Stopped (with error) %s.",
- [JOB_TIMEOUT] = "Timed out stoppping %s.",
+ [JOB_TIMEOUT] = "Timed out stopping %s.",
};
static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Reloaded %s.",
@@ -690,17 +690,20 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
}
static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- static const char* const job_result_status_table[_JOB_RESULT_MAX] = {
- [JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL,
- [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL,
- [JOB_FAILED] = ANSI_HIGHLIGHT_RED "FAILED" ANSI_NORMAL,
- [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW "DEPEND" ANSI_NORMAL,
- [JOB_SKIPPED] = ANSI_HIGHLIGHT " INFO " ANSI_NORMAL,
- [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW "ASSERT" ANSI_NORMAL,
- [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL,
+ static struct {
+ const char *color, *word;
+ } const statuses[_JOB_RESULT_MAX] = {
+ [JOB_DONE] = {ANSI_GREEN, " OK "},
+ [JOB_TIMEOUT] = {ANSI_HIGHLIGHT_RED, " TIME "},
+ [JOB_FAILED] = {ANSI_HIGHLIGHT_RED, "FAILED"},
+ [JOB_DEPENDENCY] = {ANSI_HIGHLIGHT_YELLOW, "DEPEND"},
+ [JOB_SKIPPED] = {ANSI_HIGHLIGHT, " INFO "},
+ [JOB_ASSERT] = {ANSI_HIGHLIGHT_YELLOW, "ASSERT"},
+ [JOB_UNSUPPORTED] = {ANSI_HIGHLIGHT_YELLOW, "UNSUPP"},
};
const char *format;
+ const char *status;
assert(u);
assert(t >= 0);
@@ -714,11 +717,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
if (!format)
return;
+ if (log_get_show_color())
+ status = strjoina(statuses[result].color, statuses[result].word, ANSI_NORMAL);
+ else
+ status = statuses[result].word;
+
if (result != JOB_DONE)
manager_flip_auto_status(u->manager, true);
DISABLE_WARNING_FORMAT_NONLITERAL;
- unit_status_printf(u, job_result_status_table[result], format);
+ unit_status_printf(u, status, format);
REENABLE_WARNING;
if (t == JOB_START && result == JOB_FAILED) {
@@ -819,11 +827,11 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) {
if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE))
continue;
- job_finish_and_invalidate(j, JOB_DEPENDENCY, true);
+ job_finish_and_invalidate(j, JOB_DEPENDENCY, true, false);
}
}
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
Unit *u;
Unit *other;
JobType t;
@@ -840,7 +848,9 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
log_unit_debug(u, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
- job_emit_status_message(u, t, result);
+ /* If this job did nothing to respective unit we don't log the status message */
+ if (!already)
+ job_emit_status_message(u, t, result);
job_add_to_dbus_queue(j);
@@ -856,7 +866,7 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
}
if (result == JOB_FAILED || result == JOB_INVALID)
- j->manager->n_failed_jobs ++;
+ j->manager->n_failed_jobs++;
job_uninstall(j);
job_free(j);
@@ -915,7 +925,7 @@ static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *user
log_unit_warning(j->unit, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
u = j->unit;
- job_finish_and_invalidate(j, JOB_TIMEOUT, true);
+ job_finish_and_invalidate(j, JOB_TIMEOUT, true, false);
failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg);
@@ -1148,7 +1158,7 @@ void job_shutdown_magic(Job *j) {
if (j->type != JOB_START)
return;
- if (j->unit->manager->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(j->unit->manager))
return;
if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
diff --git a/src/libcore/job.h b/src/libcore/job.h
index de130303d2..68c2089b91 100644
--- a/src/libcore/job.h
+++ b/src/libcore/job.h
@@ -219,7 +219,7 @@ void job_add_to_dbus_queue(Job *j);
int job_start_timer(Job *j);
int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive);
+int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already);
char *job_dbus_path(Job *j);
diff --git a/src/libcore/load-dropin.c b/src/libcore/load-dropin.c
index 22b71b6f5e..f83fa09301 100644
--- a/src/libcore/load-dropin.c
+++ b/src/libcore/load-dropin.c
@@ -44,6 +44,7 @@ static int add_dependency_consumer(
}
int unit_load_dropin(Unit *u) {
+ _cleanup_strv_free_ char **l = NULL;
Iterator i;
char *t, **f;
int r;
@@ -55,7 +56,7 @@ int unit_load_dropin(Unit *u) {
SET_FOREACH(t, u->names, i) {
char **p;
- STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
+ STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".wants", UNIT_WANTS,
add_dependency_consumer, u, NULL);
unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".requires", UNIT_REQUIRES,
@@ -63,11 +64,19 @@ int unit_load_dropin(Unit *u) {
}
}
- u->dropin_paths = strv_free(u->dropin_paths);
- r = unit_find_dropin_paths(u, &u->dropin_paths);
+ r = unit_find_dropin_paths(u, &l);
if (r <= 0)
return 0;
+ if (!u->dropin_paths) {
+ u->dropin_paths = l;
+ l = NULL;
+ } else {
+ r = strv_extend_strv(&u->dropin_paths, l, true);
+ if (r < 0)
+ return log_oom();
+ }
+
STRV_FOREACH(f, u->dropin_paths) {
config_parse(u->id, *f, NULL,
UNIT_VTABLE(u)->sections,
diff --git a/src/libcore/load-dropin.h b/src/libcore/load-dropin.h
index d8a4aefbb3..942d26724e 100644
--- a/src/libcore/load-dropin.h
+++ b/src/libcore/load-dropin.h
@@ -25,7 +25,7 @@
/* Read service data supplementary drop-in directories */
static inline int unit_find_dropin_paths(Unit *u, char ***paths) {
- return unit_file_find_dropin_paths(u->manager->lookup_paths.unit_path,
+ return unit_file_find_dropin_paths(u->manager->lookup_paths.search_path,
u->manager->unit_path_cache,
u->names,
paths);
diff --git a/src/libcore/load-fragment-gperf.gperf.m4 b/src/libcore/load-fragment-gperf.gperf.m4
index 5024fd19a5..8193418980 100644
--- a/src/libcore/load-fragment-gperf.gperf.m4
+++ b/src/libcore/load-fragment-gperf.gperf.m4
@@ -45,7 +45,7 @@ $1.SyslogIdentifier, config_parse_unit_string_printf, 0,
$1.SyslogFacility, config_parse_log_facility, 0, offsetof($1, exec_context.syslog_priority)
$1.SyslogLevel, config_parse_log_level, 0, offsetof($1, exec_context.syslog_priority)
$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix)
-$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context)
+$1.Capabilities, config_parse_warn_compat, DISABLED_LEGACY, offsetof($1, exec_context)
$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context)
$1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set)
$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set)
@@ -120,6 +120,14 @@ $1.MemoryAccounting, config_parse_bool, 0,
$1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context)
$1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy)
+$1.IOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.io_accounting)
+$1.IOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.io_weight)
+$1.StartupIOWeight, config_parse_io_weight, 0, offsetof($1, cgroup_context.startup_io_weight)
+$1.IODeviceWeight, config_parse_io_device_weight, 0, offsetof($1, cgroup_context)
+$1.IOReadBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
+$1.IOWriteBandwidthMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
+$1.IOReadIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
+$1.IOWriteIOPSMax, config_parse_io_limit, 0, offsetof($1, cgroup_context)
$1.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting)
$1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.blockio_weight)
$1.StartupBlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.startup_blockio_weight)
@@ -164,6 +172,8 @@ Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LE
Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout)
Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
+Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
+m4_dnl The following is a legacy alias name for compatibility
Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
@@ -220,6 +230,7 @@ Service.TimeoutStartSec, config_parse_service_timeout, 0,
Service.TimeoutStopSec, config_parse_service_timeout, 0, 0
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
+m4_dnl The following three only exist for compatibility, they moved into Unit, see above
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
@@ -240,7 +251,7 @@ Service.BusName, config_parse_bus_name, 0,
Service.FileDescriptorStoreMax, config_parse_unsigned, 0, offsetof(Service, n_fd_store_max)
Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access)
Service.Sockets, config_parse_service_sockets, 0, 0
-Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context)
+Service.BusPolicy, config_parse_warn_compat, DISABLED_LEGACY, 0
Service.USBFunctionDescriptors, config_parse_path, 0, offsetof(Service, usb_function_descriptors)
Service.USBFunctionStrings, config_parse_path, 0, offsetof(Service, usb_function_strings)
EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
@@ -297,6 +308,8 @@ Socket.RemoveOnStop, config_parse_bool, 0,
Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
Socket.FileDescriptorName, config_parse_fdname, 0, 0
Socket.Service, config_parse_socket_service, 0, 0
+Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval)
+Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst)
m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in)
diff --git a/src/libcore/load-fragment.c b/src/libcore/load-fragment.c
index 8804b3ac41..86b4fb071b 100644
--- a/src/libcore/load-fragment.c
+++ b/src/libcore/load-fragment.c
@@ -119,7 +119,7 @@ int config_parse_unit_deps(
assert(rvalue);
p = rvalue;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
int r;
@@ -620,7 +620,7 @@ int config_parse_exec(
separate_argv0 = true;
else
break;
- f ++;
+ f++;
}
if (isempty(f)) {
@@ -668,7 +668,7 @@ int config_parse_exec(
/* Check explicitly for an unquoted semicolon as
* command separator token. */
if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
- p ++;
+ p++;
p += strspn(p, WHITESPACE);
semicolon = true;
break;
@@ -732,16 +732,17 @@ int config_parse_exec(
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
-int config_parse_socket_bindtodevice(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_socket_bindtodevice(
+ 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) {
Socket *s = data;
char *n;
@@ -752,6 +753,11 @@ int config_parse_socket_bindtodevice(const char* unit,
assert(data);
if (rvalue[0] && !streq(rvalue, "*")) {
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is invalid, ignoring: %s", rvalue);
+ return 0;
+ }
+
n = strdup(rvalue);
if (!n)
return log_oom();
@@ -942,38 +948,6 @@ int config_parse_exec_cpu_affinity(const char *unit,
return 0;
}
-int config_parse_exec_capabilities(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;
- cap_t cap;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- cap = cap_from_text(rvalue);
- if (!cap) {
- log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue);
- return 0;
- }
-
- if (c->capabilities)
- cap_free(c->capabilities);
- c->capabilities = cap;
-
- return 0;
-}
-
int config_parse_exec_secure_bits(const char *unit,
const char *filename,
unsigned line,
@@ -1631,7 +1605,7 @@ int config_parse_service_sockets(
assert(data);
p = rvalue;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *word = NULL, *k = NULL;
r = extract_first_word(&p, &word, NULL, 0);
@@ -1893,59 +1867,6 @@ int config_parse_bus_policy(
return 0;
}
-int config_parse_bus_endpoint_policy(
- 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 *name = NULL;
- BusPolicyAccess access;
- ExecContext *c = data;
- char *access_str;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- name = strdup(rvalue);
- if (!name)
- return log_oom();
-
- access_str = strpbrk(name, WHITESPACE);
- if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue);
- return 0;
- }
-
- *access_str = '\0';
- access_str++;
- access_str += strspn(access_str, WHITESPACE);
-
- 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, 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 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,
@@ -2580,7 +2501,7 @@ int config_parse_syscall_filter(
/* Turn on NNP, but only if it wasn't configured explicitly
* before, and only if we are in user mode. */
- if (!c->no_new_privileges_set && u->manager->running_as == MANAGER_USER)
+ if (!c->no_new_privileges_set && MANAGER_IS_USER(u->manager))
c->no_new_privileges = true;
return 0;
@@ -2932,11 +2853,12 @@ int config_parse_device_allow(
void *data,
void *userdata) {
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *path = NULL, *t = NULL;
CGroupContext *c = data;
CGroupDeviceAllow *a;
- const char *m;
+ const char *m = NULL;
size_t n;
+ int r;
if (isempty(rvalue)) {
while (c->device_allow)
@@ -2945,8 +2867,16 @@ int config_parse_device_allow(
return 0;
}
- n = strcspn(rvalue, WHITESPACE);
- path = strndup(rvalue, n);
+ r = unit_full_printf(userdata, rvalue, &t);
+ if(r < 0) {
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Failed to resolve specifiers in %s, ignoring: %m",
+ rvalue);
+ }
+
+ n = strcspn(t, WHITESPACE);
+
+ path = strndup(t, n);
if (!path)
return log_oom();
@@ -2957,7 +2887,7 @@ int config_parse_device_allow(
return 0;
}
- m = rvalue + n + strspn(rvalue + n, WHITESPACE);
+ m = t + n + strspn(t + n, WHITESPACE);
if (isempty(m))
m = "rwm";
@@ -2980,6 +2910,193 @@ int config_parse_device_allow(
return 0;
}
+int config_parse_io_weight(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ uint64_t *weight = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = cg_weight_parse(rvalue, weight);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
+
+int config_parse_io_device_weight(
+ 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 *path = NULL;
+ CGroupIODeviceWeight *w;
+ CGroupContext *c = data;
+ const char *weight;
+ uint64_t u;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue)) {
+ while (c->io_device_weights)
+ cgroup_context_free_io_device_weight(c, c->io_device_weights);
+
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ weight = rvalue + n;
+ weight += strspn(weight, WHITESPACE);
+
+ if (isempty(weight)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ r = cg_weight_parse(weight, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO weight '%s' invalid. Ignoring.", weight);
+ return 0;
+ }
+
+ assert(u != CGROUP_WEIGHT_INVALID);
+
+ w = new0(CGroupIODeviceWeight, 1);
+ if (!w)
+ return log_oom();
+
+ w->path = path;
+ path = NULL;
+
+ w->weight = u;
+
+ LIST_PREPEND(device_weights, c->io_device_weights, w);
+ return 0;
+}
+
+int config_parse_io_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) {
+
+ _cleanup_free_ char *path = NULL;
+ CGroupIODeviceLimit *l = NULL, *t;
+ CGroupContext *c = data;
+ CGroupIOLimitType type;
+ const char *limit;
+ uint64_t num;
+ size_t n;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ type = cgroup_io_limit_type_from_string(lvalue);
+ assert(type >= 0);
+
+ if (isempty(rvalue)) {
+ LIST_FOREACH(device_limits, l, c->io_device_limits)
+ l->limits[type] = cgroup_io_limit_defaults[type];
+ return 0;
+ }
+
+ n = strcspn(rvalue, WHITESPACE);
+ limit = rvalue + n;
+ limit += strspn(limit, WHITESPACE);
+
+ if (!*limit) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring.");
+ return 0;
+ }
+
+ path = strndup(rvalue, n);
+ if (!path)
+ return log_oom();
+
+ if (!path_startswith(path, "/dev")) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
+ return 0;
+ }
+
+ if (streq("max", limit)) {
+ num = CGROUP_LIMIT_MAX;
+ } else {
+ r = parse_size(limit, 1000, &num);
+ if (r < 0 || num <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "IO Limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+ }
+
+ LIST_FOREACH(device_limits, t, c->io_device_limits) {
+ if (path_equal(path, t->path)) {
+ l = t;
+ break;
+ }
+ }
+
+ if (!l) {
+ CGroupIOLimitType ttype;
+
+ l = new0(CGroupIODeviceLimit, 1);
+ if (!l)
+ return log_oom();
+
+ l->path = path;
+ path = NULL;
+ for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
+ l->limits[ttype] = cgroup_io_limit_defaults[ttype];
+
+ LIST_PREPEND(device_limits, c->io_device_limits, l);
+ }
+
+ l->limits[type] = num;
+
+ return 0;
+}
+
int config_parse_blockio_weight(
const char *unit,
const char *filename,
@@ -3091,7 +3208,7 @@ int config_parse_blockio_bandwidth(
void *userdata) {
_cleanup_free_ char *path = NULL;
- CGroupBlockIODeviceBandwidth *b;
+ CGroupBlockIODeviceBandwidth *b = NULL, *t;
CGroupContext *c = data;
const char *bandwidth;
uint64_t bytes;
@@ -3106,12 +3223,10 @@ int config_parse_blockio_bandwidth(
read = streq("BlockIOReadBandwidth", lvalue);
if (isempty(rvalue)) {
- CGroupBlockIODeviceBandwidth *next;
-
- LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
- if (b->read == read)
- cgroup_context_free_blockio_device_bandwidth(c, b);
-
+ LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
+ b->rbps = CGROUP_LIMIT_MAX;
+ b->wbps = CGROUP_LIMIT_MAX;
+ }
return 0;
}
@@ -3139,16 +3254,30 @@ int config_parse_blockio_bandwidth(
return 0;
}
- b = new0(CGroupBlockIODeviceBandwidth, 1);
- if (!b)
- return log_oom();
+ LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
+ if (path_equal(path, t->path)) {
+ b = t;
+ break;
+ }
+ }
- b->path = path;
- path = NULL;
- b->bandwidth = bytes;
- b->read = read;
+ if (!t) {
+ b = new0(CGroupBlockIODeviceBandwidth, 1);
+ if (!b)
+ return log_oom();
- LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+ b->path = path;
+ path = NULL;
+ b->rbps = CGROUP_LIMIT_MAX;
+ b->wbps = CGROUP_LIMIT_MAX;
+
+ LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
+ }
+
+ if (read)
+ b->rbps = bytes;
+ else
+ b->wbps = bytes;
return 0;
}
@@ -3446,7 +3575,7 @@ int config_parse_protect_home(
ProtectHome h;
h = protect_home_from_string(rvalue);
- if (h < 0){
+ if (h < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
return 0;
}
@@ -3489,7 +3618,7 @@ int config_parse_protect_system(
ProtectSystem s;
s = protect_system_from_string(rvalue);
- if (s < 0){
+ if (s < 0) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue);
return 0;
}
@@ -3503,10 +3632,10 @@ int config_parse_protect_system(
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
+ char *id = NULL;
unsigned c = 0;
int fd, r;
FILE *f;
- char *id = NULL;
assert(filename);
assert(*filename);
@@ -3528,7 +3657,6 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
* the names of this unit, but only if it is a valid
* unit name. */
name = basename(*filename);
-
if (unit_name_is_valid(name, UNIT_NAME_ANY)) {
id = set_get(names, name);
@@ -3568,6 +3696,7 @@ static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
*_f = f;
*_final = id;
+
return 0;
}
@@ -3592,7 +3721,19 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
* ours? Then let's try it the other way
* round */
- other = manager_get_unit((*u)->manager, k);
+ /* If the symlink name we are looking at is unit template, then
+ we must search for instance of this template */
+ if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE)) {
+ _cleanup_free_ char *instance = NULL;
+
+ r = unit_name_replace_instance(k, (*u)->instance, &instance);
+ if (r < 0)
+ return r;
+
+ other = manager_get_unit((*u)->manager, instance);
+ } else
+ other = manager_get_unit((*u)->manager, k);
+
free(k);
if (other) {
@@ -3616,13 +3757,13 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
}
static int load_from_path(Unit *u, const char *path) {
- int r;
_cleanup_set_free_free_ Set *symlink_names = NULL;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *filename = NULL;
char *id = NULL;
Unit *merged;
struct stat st;
+ int r;
assert(u);
assert(path);
@@ -3647,7 +3788,7 @@ static int load_from_path(Unit *u, const char *path) {
} else {
char **p;
- STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
+ STRV_FOREACH(p, u->manager->lookup_paths.search_path) {
/* Instead of opening the path right away, we manually
* follow all symlinks and add their name to our unit
@@ -3661,18 +3802,14 @@ static int load_from_path(Unit *u, const char *path) {
r = -ENOENT;
else
r = open_follow(&filename, &f, symlink_names, &id);
+ if (r >= 0)
+ break;
+ filename = mfree(filename);
+ if (r != -ENOENT)
+ return r;
- if (r < 0) {
- filename = mfree(filename);
- if (r != -ENOENT)
- return r;
-
- /* Empty the symlink names for the next run */
- set_clear_free(symlink_names);
- continue;
- }
-
- break;
+ /* Empty the symlink names for the next run */
+ set_clear_free(symlink_names);
}
}
@@ -3680,6 +3817,11 @@ static int load_from_path(Unit *u, const char *path) {
/* Hmm, no suitable file found? */
return 0;
+ if (!unit_type_may_alias(u->type) && set_size(symlink_names) > 1) {
+ log_unit_warning(u, "Unit type of %s does not support alias names, refusing loading via symlink.", u->id);
+ return -ELOOP;
+ }
+
merged = u;
r = merge_by_names(&merged, symlink_names, id);
if (r < 0)
@@ -3693,10 +3835,12 @@ static int load_from_path(Unit *u, const char *path) {
if (fstat(fileno(f), &st) < 0)
return -errno;
- if (null_or_empty(&st))
+ if (null_or_empty(&st)) {
u->load_state = UNIT_MASKED;
- else {
+ u->fragment_mtime = 0;
+ } else {
u->load_state = UNIT_LOADED;
+ u->fragment_mtime = timespec_load(&st.st_mtim);
/* Now, parse the file contents */
r = config_parse(u->id, filename, f,
@@ -3711,8 +3855,6 @@ static int load_from_path(Unit *u, const char *path) {
u->fragment_path = filename;
filename = NULL;
- u->fragment_mtime = timespec_load(&st.st_mtim);
-
if (u->source_path) {
if (stat(u->source_path, &st) >= 0)
u->source_mtime = timespec_load(&st.st_mtim);
@@ -3841,7 +3983,6 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_input, "INPUT" },
{ config_parse_log_facility, "FACILITY" },
{ config_parse_log_level, "LEVEL" },
- { config_parse_exec_capabilities, "CAPABILITIES" },
{ config_parse_exec_secure_bits, "SECUREBITS" },
{ config_parse_capability_set, "BOUNDINGSET" },
{ config_parse_limit, "LIMIT" },
@@ -3888,6 +4029,9 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },
{ config_parse_device_policy, "POLICY" },
+ { config_parse_io_limit, "LIMIT" },
+ { config_parse_io_weight, "WEIGHT" },
+ { config_parse_io_device_weight, "DEVICEWEIGHT" },
{ config_parse_blockio_bandwidth, "BANDWIDTH" },
{ config_parse_blockio_weight, "WEIGHT" },
{ config_parse_blockio_device_weight, "DEVICEWEIGHT" },
diff --git a/src/libcore/load-fragment.h b/src/libcore/load-fragment.h
index 5fb5910919..b36a2e3a02 100644
--- a/src/libcore/load-fragment.h
+++ b/src/libcore/load-fragment.h
@@ -52,7 +52,6 @@ int config_parse_exec_io_priority(const char *unit, const char *filename, unsign
int config_parse_exec_cpu_sched_policy(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_cpu_sched_prio(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_cpu_affinity(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_capabilities(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_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_capability_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);
@@ -67,7 +66,6 @@ int config_parse_service_sockets(const char *unit, const char *filename, unsigne
int config_parse_busname_service(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_policy(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_policy_world(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_endpoint_policy(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_env_file(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_ip_tos(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_condition_path(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -88,6 +86,9 @@ int config_parse_memory_limit(const char *unit, const char *filename, unsigned l
int config_parse_tasks_max(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_device_policy(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_device_allow(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_io_weight(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_io_device_weight(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_io_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_blockio_weight(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_blockio_device_weight(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_blockio_bandwidth(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/libcore/machine-id-setup.c b/src/libcore/machine-id-setup.c
index 30f27ffc67..812e4b038c 100644
--- a/src/libcore/machine-id-setup.c
+++ b/src/libcore/machine-id-setup.c
@@ -101,14 +101,23 @@ static int read_machine_id(int fd, char id[34]) {
return 0;
}
-static int write_machine_id(int fd, char id[34]) {
+static int write_machine_id(int fd, const char id[34]) {
+ int r;
+
assert(fd >= 0);
assert(id);
if (lseek(fd, 0, SEEK_SET) < 0)
return -errno;
- return loop_write(fd, id, 33, false);
+ r = loop_write(fd, id, 33, false);
+ if (r < 0)
+ return r;
+
+ if (fsync(fd) < 0)
+ return -errno;
+
+ return 0;
}
static int generate_machine_id(char id[34], const char *root) {
@@ -120,10 +129,7 @@ static int generate_machine_id(char id[34], const char *root) {
assert(id);
- if (isempty(root))
- dbus_machine_id = "/var/lib/dbus/machine-id";
- else
- dbus_machine_id = strjoina(root, "/var/lib/dbus/machine-id");
+ dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
/* First, try reading the D-Bus machine id, unless it is a symlink */
fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
@@ -203,18 +209,8 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
char id[34]; /* 32 + \n + \0 */
int r;
- if (isempty(root)) {
- etc_machine_id = "/etc/machine-id";
- run_machine_id = "/run/machine-id";
- } else {
- char *x;
-
- x = strjoina(root, "/etc/machine-id");
- etc_machine_id = path_kill_slashes(x);
-
- x = strjoina(root, "/run/machine-id");
- run_machine_id = path_kill_slashes(x);
- }
+ etc_machine_id = prefix_roota(root, "/etc/machine-id");
+ run_machine_id = prefix_roota(root, "/run/machine-id");
RUN_WITH_UMASK(0000) {
/* We create this 0444, to indicate that this isn't really
@@ -274,10 +270,10 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
RUN_WITH_UMASK(0022) {
r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE);
- }
- if (r < 0) {
- (void) unlink(run_machine_id);
- return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
+ if (r < 0) {
+ (void) unlink(run_machine_id);
+ return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
+ }
}
/* And now, let's mount it over */
@@ -301,14 +297,7 @@ int machine_id_commit(const char *root) {
char id[34]; /* 32 + \n + \0 */
int r;
- if (isempty(root))
- etc_machine_id = "/etc/machine-id";
- else {
- char *x;
-
- x = strjoina(root, "/etc/machine-id");
- etc_machine_id = path_kill_slashes(x);
- }
+ etc_machine_id = prefix_roota(root, "/etc/machine-id");
r = path_is_mount_point(etc_machine_id, 0);
if (r < 0)
diff --git a/src/libcore/manager.c b/src/libcore/manager.c
index 9a34742cf6..831fdbaabf 100644
--- a/src/libcore/manager.c
+++ b/src/libcore/manager.c
@@ -49,6 +49,7 @@
#include "dbus-manager.h"
#include "dbus-unit.h"
#include "dbus.h"
+#include "dirent-util.h"
#include "env-util.h"
#include "escape.h"
#include "exit-status.h"
@@ -63,6 +64,7 @@
#include "manager.h"
#include "missing.h"
#include "mkdir.h"
+#include "mkdir.h"
#include "parse-util.h"
#include "path-lookup.h"
#include "path-util.h"
@@ -85,6 +87,7 @@
#include "watchdog.h"
#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
+#define CGROUPS_AGENT_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)
@@ -92,13 +95,13 @@
#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata);
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata);
static int manager_run_generators(Manager *m);
-static void manager_undo_generators(Manager *m);
static void manager_watch_jobs_in_progress(Manager *m) {
usec_t next;
@@ -483,15 +486,15 @@ static int manager_setup_signals(Manager *m) {
(void) sd_event_source_set_description(m->signal_event_source, "manager-signal");
- /* Process signals a bit earlier than the rest of things, but
- * later than notify_fd processing, so that the notify
- * processing can still figure out to which process/service a
- * message belongs, before we reap the process. */
- r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ /* Process signals a bit earlier than the rest of things, but later than notify_fd processing, so that the
+ * notify processing can still figure out to which process/service a message belongs, before we reap the
+ * process. Also, process this before handling cgroup notifications, so that we always collect child exit
+ * status information before detecting that there's no process in a cgroup. */
+ r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-6);
if (r < 0)
return r;
- if (m->running_as == MANAGER_SYSTEM)
+ if (MANAGER_IS_SYSTEM(m))
return enable_special_signals(m);
return 0;
@@ -518,7 +521,7 @@ static void manager_clean_environment(Manager *m) {
static int manager_default_environment(Manager *m) {
assert(m);
- if (m->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(m)) {
/* The system manager always starts with a clean
* environment for its children. It does not import
* the kernel or the parents exported variables.
@@ -547,52 +550,45 @@ static int manager_default_environment(Manager *m) {
}
-int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
-
- static const char * const unit_log_fields[_MANAGER_RUNNING_AS_MAX] = {
- [MANAGER_SYSTEM] = "UNIT=",
- [MANAGER_USER] = "USER_UNIT=",
- };
-
- static const char * const unit_log_format_strings[_MANAGER_RUNNING_AS_MAX] = {
- [MANAGER_SYSTEM] = "UNIT=%s",
- [MANAGER_USER] = "USER_UNIT=%s",
- };
-
+int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
Manager *m;
int r;
assert(_m);
- assert(running_as >= 0);
- assert(running_as < _MANAGER_RUNNING_AS_MAX);
+ assert(IN_SET(scope, UNIT_FILE_SYSTEM, UNIT_FILE_USER));
m = new0(Manager, 1);
if (!m)
return -ENOMEM;
-#ifdef ENABLE_EFI
- if (running_as == MANAGER_SYSTEM && detect_container() <= 0)
- boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
-#endif
-
- m->running_as = running_as;
+ m->unit_file_scope = scope;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
m->default_tasks_accounting = true;
m->default_tasks_max = UINT64_C(512);
+#ifdef ENABLE_EFI
+ if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
+ boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
+#endif
+
/* Prepare log fields we can use for structured logging */
- m->unit_log_field = unit_log_fields[running_as];
- m->unit_log_format_string = unit_log_format_strings[running_as];
+ if (MANAGER_IS_SYSTEM(m)) {
+ m->unit_log_field = "UNIT=";
+ m->unit_log_format_string = "UNIT=%s";
+ } else {
+ m->unit_log_field = "USER_UNIT=";
+ m->unit_log_format_string = "USER_UNIT=%s";
+ }
m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd =
- m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd = -1;
+ m->pin_cgroupfs_fd = m->notify_fd = m->cgroups_agent_fd = m->signal_fd = m->time_change_fd =
+ m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->cgroup_inotify_fd =
+ m->ask_password_inotify_fd = -1;
m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
- m->ask_password_inotify_fd = -1;
m->have_ask_password = -EINVAL; /* we don't know */
m->first_boot = -1;
@@ -683,6 +679,7 @@ static int manager_setup_notify(Manager *m) {
.sa.sa_family = AF_UNIX,
};
static const int one = 1;
+ const char *e;
/* First free all secondary fields */
m->notify_socket = mfree(m->notify_socket);
@@ -694,19 +691,13 @@ static int manager_setup_notify(Manager *m) {
fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
- if (m->running_as == MANAGER_SYSTEM)
- m->notify_socket = strdup("/run/systemd/notify");
- else {
- const char *e;
-
- e = getenv("XDG_RUNTIME_DIR");
- if (!e) {
- log_error_errno(errno, "XDG_RUNTIME_DIR is not set: %m");
- return -EINVAL;
- }
-
- m->notify_socket = strappend(e, "/systemd/notify");
+ e = manager_get_runtime_prefix(m);
+ if (!e) {
+ log_error("Failed to determine runtime prefix.");
+ return -EINVAL;
}
+
+ m->notify_socket = strappend(e, "/systemd/notify");
if (!m->notify_socket)
return log_oom();
@@ -714,7 +705,7 @@ static int manager_setup_notify(Manager *m) {
(void) unlink(m->notify_socket);
strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1);
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
+ r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
@@ -733,8 +724,8 @@ static int manager_setup_notify(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to allocate notify event source: %m");
- /* Process signals a bit earlier than SIGCHLD, so that we can
- * still identify to which service an exit message belongs */
+ /* Process notification messages a bit earlier than SIGCHLD, so that we can still identify to which
+ * service an exit message belongs. */
r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-7);
if (r < 0)
return log_error_errno(r, "Failed to set priority of notify event source: %m");
@@ -745,6 +736,79 @@ static int manager_setup_notify(Manager *m) {
return 0;
}
+static int manager_setup_cgroups_agent(Manager *m) {
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/cgroups-agent",
+ };
+ int r;
+
+ /* This creates a listening socket we receive cgroups agent messages on. We do not use D-Bus for delivering
+ * these messages from the cgroups agent binary to PID 1, as the cgroups agent binary is very short-living, and
+ * each instance of it needs a new D-Bus connection. Since D-Bus connections are SOCK_STREAM/AF_UNIX, on
+ * overloaded systems the backlog of the D-Bus socket becomes relevant, as not more than the configured number
+ * of D-Bus connections may be queued until the kernel will start dropping further incoming connections,
+ * possibly resulting in lost cgroups agent messages. To avoid this, we'll use a private SOCK_DGRAM/AF_UNIX
+ * socket, where no backlog is relevant as communication may take place without an actual connect() cycle, and
+ * we thus won't lose messages.
+ *
+ * Note that PID 1 will forward the agent message to system bus, so that the user systemd instance may listen
+ * to it. The system instance hence listens on this special socket, but the user instances listen on the system
+ * bus for these messages. */
+
+ if (m->test_run)
+ return 0;
+
+ if (!MANAGER_IS_SYSTEM(m))
+ return 0;
+
+ if (cg_unified() > 0) /* We don't need this anymore on the unified hierarchy */
+ return 0;
+
+ if (m->cgroups_agent_fd < 0) {
+ _cleanup_close_ int fd = -1;
+
+ /* First free all secondary fields */
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
+
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to allocate cgroups agent socket: %m");
+
+ fd_inc_rcvbuf(fd, CGROUPS_AGENT_RCVBUF_SIZE);
+
+ (void) unlink(sa.un.sun_path);
+
+ /* Only allow root to connect to this socket */
+ RUN_WITH_UMASK(0077)
+ r = bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ if (r < 0)
+ return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
+
+ m->cgroups_agent_fd = fd;
+ fd = -1;
+ }
+
+ if (!m->cgroups_agent_event_source) {
+ r = sd_event_add_io(m->event, &m->cgroups_agent_event_source, m->cgroups_agent_fd, EPOLLIN, manager_dispatch_cgroups_agent_fd, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate cgroups agent event source: %m");
+
+ /* Process cgroups notifications early, but after having processed service notification messages or
+ * SIGCHLD signals, so that a cgroup running empty is always just the last safety net of notification,
+ * and we collected the metadata the notification and SIGCHLD stuff offers first. Also see handling of
+ * cgroup inotify for the unified cgroup stuff. */
+ r = sd_event_source_set_priority(m->cgroups_agent_event_source, SD_EVENT_PRIORITY_NORMAL-5);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set priority of cgroups agent event source: %m");
+
+ (void) sd_event_source_set_description(m->cgroups_agent_event_source, "manager-cgroups-agent");
+ }
+
+ return 0;
+}
+
static int manager_setup_kdbus(Manager *m) {
_cleanup_free_ char *p = NULL;
@@ -756,8 +820,8 @@ static int manager_setup_kdbus(Manager *m) {
return -ESOCKTNOSUPPORT;
m->kdbus_fd = bus_kernel_create_bus(
- m->running_as == MANAGER_SYSTEM ? "system" : "user",
- m->running_as == MANAGER_SYSTEM, &p);
+ MANAGER_IS_SYSTEM(m) ? "system" : "user",
+ MANAGER_IS_SYSTEM(m), &p);
if (m->kdbus_fd < 0)
return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
@@ -778,7 +842,7 @@ static int manager_connect_bus(Manager *m, bool reexecuting) {
try_bus_connect =
m->kdbus_fd >= 0 ||
reexecuting ||
- (m->running_as == MANAGER_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
+ (MANAGER_IS_USER(m) && getenv("DBUS_SESSION_BUS_ADDRESS"));
/* Try to connect to the buses, if possible. */
return bus_init(m, try_bus_connect);
@@ -940,7 +1004,7 @@ Manager* manager_free(Manager *m) {
* around */
manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
- manager_undo_generators(m);
+ lookup_paths_flush_generator(&m->lookup_paths);
bus_done(m);
@@ -955,12 +1019,14 @@ Manager* manager_free(Manager *m) {
sd_event_source_unref(m->signal_event_source);
sd_event_source_unref(m->notify_event_source);
+ sd_event_source_unref(m->cgroups_agent_event_source);
sd_event_source_unref(m->time_change_event_source);
sd_event_source_unref(m->jobs_in_progress_event_source);
sd_event_source_unref(m->run_queue_event_source);
safe_close(m->signal_fd);
safe_close(m->notify_fd);
+ safe_close(m->cgroups_agent_fd);
safe_close(m->time_change_fd);
safe_close(m->kdbus_fd);
@@ -1037,7 +1103,6 @@ static void manager_coldplug(Manager *m) {
static void manager_build_unit_path_cache(Manager *m) {
char **i;
- _cleanup_closedir_ DIR *d = NULL;
int r;
assert(m);
@@ -1046,29 +1111,27 @@ static void manager_build_unit_path_cache(Manager *m) {
m->unit_path_cache = set_new(&string_hash_ops);
if (!m->unit_path_cache) {
- log_error("Failed to allocate unit path cache.");
- return;
+ r = -ENOMEM;
+ goto fail;
}
/* This simply builds a list of files we know exist, so that
* we don't always have to go to disk */
- STRV_FOREACH(i, m->lookup_paths.unit_path) {
+ STRV_FOREACH(i, m->lookup_paths.search_path) {
+ _cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
d = opendir(*i);
if (!d) {
if (errno != ENOENT)
- log_error_errno(errno, "Failed to open directory %s: %m", *i);
+ log_warning_errno(errno, "Failed to open directory %s, ignoring: %m", *i);
continue;
}
- while ((de = readdir(d))) {
+ FOREACH_DIRENT(de, d, r = -errno; goto fail) {
char *p;
- if (hidden_file(de->d_name))
- continue;
-
p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
if (!p) {
r = -ENOMEM;
@@ -1079,20 +1142,15 @@ static void manager_build_unit_path_cache(Manager *m) {
if (r < 0)
goto fail;
}
-
- d = safe_closedir(d);
}
return;
fail:
- log_error_errno(r, "Failed to build unit path cache: %m");
-
- set_free_free(m->unit_path_cache);
- m->unit_path_cache = NULL;
+ log_warning_errno(r, "Failed to build unit path cache, proceeding without: %m");
+ m->unit_path_cache = set_free_free(m->unit_path_cache);
}
-
static void manager_distribute_fds(Manager *m, FDSet *fds) {
Iterator i;
Unit *u;
@@ -1116,28 +1174,29 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
assert(m);
- dual_timestamp_get(&m->generators_start_timestamp);
- r = manager_run_generators(m);
- dual_timestamp_get(&m->generators_finish_timestamp);
+ r = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
+ if (r < 0)
+ return r;
+
+ /* Make sure the transient directory always exists, so that it remains in the search path */
+ r = mkdir_p_label(m->lookup_paths.transient, 0755);
if (r < 0)
return r;
- r = lookup_paths_init(
- &m->lookup_paths, m->running_as, true,
- NULL,
- m->generator_unit_path,
- m->generator_unit_path_early,
- m->generator_unit_path_late);
+ dual_timestamp_get(&m->generators_start_timestamp);
+ r = manager_run_generators(m);
+ dual_timestamp_get(&m->generators_finish_timestamp);
if (r < 0)
return r;
+ lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
/* If we will deserialize make sure that during enumeration
* this is already known, so we increase the counter here
* already */
if (serialization)
- m->n_reloading ++;
+ m->n_reloading++;
/* First, enumerate what we can from all config files */
dual_timestamp_get(&m->units_load_start_timestamp);
@@ -1160,6 +1219,10 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (q < 0 && r == 0)
r = q;
+ q = manager_setup_cgroups_agent(m);
+ if (q < 0 && r == 0)
+ r = q;
+
/* We might have deserialized the kdbus control fd, but if we
* didn't, then let's create the bus now. */
manager_setup_kdbus(m);
@@ -1171,7 +1234,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
if (serialization) {
assert(m->n_reloading > 0);
- m->n_reloading --;
+ m->n_reloading--;
/* Let's wait for the UnitNew/JobNew messages being
* sent, before we notify that the reload is
@@ -1333,8 +1396,12 @@ int manager_load_unit_prepare(
t = unit_name_to_type(name);
- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
+ if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
+ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
+ return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is missing the instance name.", name);
+
return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
+ }
ret = manager_get_unit(m, name);
if (ret) {
@@ -1427,7 +1494,7 @@ void manager_clear_jobs(Manager *m) {
while ((j = hashmap_first(m->jobs)))
/* No need to recurse. We're cancelling all jobs. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
+ job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
@@ -1493,6 +1560,35 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
return n;
}
+static int manager_dispatch_cgroups_agent_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ Manager *m = userdata;
+ char buf[PATH_MAX+1];
+ ssize_t n;
+
+ n = recv(fd, buf, sizeof(buf), 0);
+ if (n < 0)
+ return log_error_errno(errno, "Failed to read cgroups agent message: %m");
+ if (n == 0) {
+ log_error("Got zero-length cgroups agent message, ignoring.");
+ return 0;
+ }
+ if ((size_t) n >= sizeof(buf)) {
+ log_error("Got overly long cgroups agent message, ignoring.");
+ return 0;
+ }
+
+ if (memchr(buf, 0, n)) {
+ log_error("Got cgroups agent message with embedded NUL byte, ignoring.");
+ return 0;
+ }
+ buf[n] = 0;
+
+ manager_notify_cgroup_empty(m, buf);
+ bus_forward_agent_released(m, buf);
+
+ return 0;
+}
+
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;
@@ -1631,7 +1727,9 @@ static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) {
log_unit_debug(u, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
unit_unwatch_pid(u, si->si_pid);
- UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
+
+ if (UNIT_VTABLE(u)->sigchld_event)
+ UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
}
static int manager_dispatch_sigchld(Manager *m) {
@@ -1738,7 +1836,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
}
log_received_signal(sfsi.ssi_signo == SIGCHLD ||
- (sfsi.ssi_signo == SIGTERM && m->running_as == MANAGER_USER)
+ (sfsi.ssi_signo == SIGTERM && MANAGER_IS_USER(m))
? LOG_DEBUG : LOG_INFO,
&sfsi);
@@ -1749,7 +1847,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGTERM:
- if (m->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(m)) {
/* This is for compatibility with the
* original sysvinit */
m->exit_code = MANAGER_REEXECUTE;
@@ -1759,7 +1857,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
/* Fall through */
case SIGINT:
- if (m->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(m)) {
/* If the user presses C-A-D more than
* 7 times within 2s, we reboot
@@ -1785,14 +1883,14 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case SIGWINCH:
- if (m->running_as == MANAGER_SYSTEM)
+ if (MANAGER_IS_SYSTEM(m))
manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
break;
case SIGPWR:
- if (m->running_as == MANAGER_SYSTEM)
+ if (MANAGER_IS_SYSTEM(m))
manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
/* This is a nop on non-init */
@@ -1900,7 +1998,7 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t
break;
case 24:
- if (m->running_as == MANAGER_USER) {
+ if (MANAGER_IS_USER(m)) {
m->exit_code = MANAGER_EXIT;
return 0;
}
@@ -2016,7 +2114,7 @@ int manager_loop(Manager *m) {
while (m->exit_code == MANAGER_OK) {
usec_t wait_usec;
- if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM)
+ if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m))
watchdog_ping();
if (!ratelimit_test(&rl)) {
@@ -2041,7 +2139,7 @@ int manager_loop(Manager *m) {
continue;
/* Sleep for half the watchdog time */
- if (m->runtime_watchdog > 0 && m->running_as == MANAGER_SYSTEM) {
+ if (m->runtime_watchdog > 0 && m->runtime_watchdog != USEC_INFINITY && MANAGER_IS_SYSTEM(m)) {
wait_usec = m->runtime_watchdog / 2;
if (wait_usec <= 0)
wait_usec = 1;
@@ -2112,7 +2210,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
const char *msg;
int audit_fd, r;
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return;
audit_fd = get_audit_fd();
@@ -2121,7 +2219,7 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
/* Don't generate audit events if the service was already
* started and we're just deserializing */
- if (m->n_reloading > 0)
+ if (MANAGER_IS_RELOADING(m))
return;
if (u->type != UNIT_SERVICE)
@@ -2147,18 +2245,17 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
}
void manager_send_unit_plymouth(Manager *m, Unit *u) {
- union sockaddr_union sa = PLYMOUTH_SOCKET;
-
- int n = 0;
+ static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *message = NULL;
_cleanup_close_ int fd = -1;
+ int n = 0;
/* Don't generate plymouth events if the service was already
* started and we're just deserializing */
- if (m->n_reloading > 0)
+ if (MANAGER_IS_RELOADING(m))
return;
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return;
if (detect_container() > 0)
@@ -2177,7 +2274,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
return;
}
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
log_error_errno(errno, "connect() failed: %m");
@@ -2202,8 +2299,8 @@ int manager_open_serialization(Manager *m, FILE **_f) {
assert(_f);
- path = m->running_as == MANAGER_SYSTEM ? "/run/systemd" : "/tmp";
- fd = open_tmpfile(path, O_RDWR|O_CLOEXEC);
+ path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp";
+ fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;
@@ -2231,7 +2328,7 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
assert(f);
assert(fds);
- m->n_reloading ++;
+ m->n_reloading++;
fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id);
fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
@@ -2277,6 +2374,16 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
fprintf(f, "notify-socket=%s\n", m->notify_socket);
}
+ if (m->cgroups_agent_fd >= 0) {
+ int copy;
+
+ copy = fdset_put_dup(fds, m->cgroups_agent_fd);
+ if (copy < 0)
+ return copy;
+
+ fprintf(f, "cgroups-agent-fd=%i\n", copy);
+ }
+
if (m->kdbus_fd >= 0) {
int copy;
@@ -2301,13 +2408,13 @@ int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
r = unit_serialize(u, f, fds, !switching_root);
if (r < 0) {
- m->n_reloading --;
+ m->n_reloading--;
return r;
}
}
assert(m->n_reloading > 0);
- m->n_reloading --;
+ m->n_reloading--;
if (ferror(f))
return -EIO;
@@ -2327,7 +2434,7 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
log_debug("Deserializing state...");
- m->n_reloading ++;
+ m->n_reloading++;
for (;;) {
char line[LINE_MAX], *l;
@@ -2444,6 +2551,17 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
free(m->notify_socket);
m->notify_socket = n;
+ } else if (startswith(l, "cgroups-agent-fd=")) {
+ int fd;
+
+ if (safe_atoi(l + 17, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_debug("Failed to parse cgroups agent fd: %s", l + 10);
+ else {
+ m->cgroups_agent_event_source = sd_event_source_unref(m->cgroups_agent_event_source);
+ safe_close(m->cgroups_agent_fd);
+ m->cgroups_agent_fd = fdset_remove(fds, fd);
+ }
+
} else if (startswith(l, "kdbus-fd=")) {
int fd;
@@ -2495,7 +2613,7 @@ finish:
r = -EIO;
assert(m->n_reloading > 0);
- m->n_reloading --;
+ m->n_reloading--;
return r;
}
@@ -2511,45 +2629,41 @@ int manager_reload(Manager *m) {
if (r < 0)
return r;
- m->n_reloading ++;
+ m->n_reloading++;
bus_manager_send_reloading(m, true);
fds = fdset_new();
if (!fds) {
- m->n_reloading --;
+ m->n_reloading--;
return -ENOMEM;
}
r = manager_serialize(m, f, fds, false);
if (r < 0) {
- m->n_reloading --;
+ m->n_reloading--;
return r;
}
if (fseeko(f, 0, SEEK_SET) < 0) {
- m->n_reloading --;
+ m->n_reloading--;
return -errno;
}
/* From here on there is no way back. */
manager_clear_jobs_and_units(m);
- manager_undo_generators(m);
+ lookup_paths_flush_generator(&m->lookup_paths);
lookup_paths_free(&m->lookup_paths);
- /* Find new unit paths */
- q = manager_run_generators(m);
+ q = lookup_paths_init(&m->lookup_paths, m->unit_file_scope, 0, NULL);
if (q < 0 && r >= 0)
r = q;
- q = lookup_paths_init(
- &m->lookup_paths, m->running_as, true,
- NULL,
- m->generator_unit_path,
- m->generator_unit_path_early,
- m->generator_unit_path_late);
+ /* Find new unit paths */
+ q = manager_run_generators(m);
if (q < 0 && r >= 0)
r = q;
+ lookup_paths_reduce(&m->lookup_paths);
manager_build_unit_path_cache(m);
/* First, enumerate what we can from all config files */
@@ -2568,6 +2682,10 @@ int manager_reload(Manager *m) {
if (q < 0 && r >= 0)
r = q;
+ q = manager_setup_cgroups_agent(m);
+ if (q < 0 && r >= 0)
+ r = q;
+
/* Third, fire things up! */
manager_coldplug(m);
@@ -2583,12 +2701,6 @@ int manager_reload(Manager *m) {
return r;
}
-bool manager_is_reloading_or_reexecuting(Manager *m) {
- assert(m);
-
- return m->n_reloading != 0;
-}
-
void manager_reset_failed(Manager *m) {
Unit *u;
Iterator i;
@@ -2620,7 +2732,7 @@ static void manager_notify_finished(Manager *m) {
if (m->test_run)
return;
- if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0) {
+ if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
/* Note that m->kernel_usec.monotonic is always at 0,
* and m->firmware_usec.monotonic and
@@ -2685,7 +2797,7 @@ static void manager_notify_finished(Manager *m) {
void manager_check_finished(Manager *m) {
assert(m);
- if (m->n_reloading > 0)
+ if (MANAGER_IS_RELOADING(m))
return;
/* Verify that we are actually running currently. Initially
@@ -2726,77 +2838,6 @@ void manager_check_finished(Manager *m) {
manager_invalidate_startup_units(m);
}
-static int create_generator_dir(Manager *m, char **generator, const char *name) {
- char *p;
- int r;
-
- assert(m);
- assert(generator);
- assert(name);
-
- if (*generator)
- return 0;
-
- if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
- /* systemd --system, not running --test */
-
- p = strappend("/run/systemd/", name);
- if (!p)
- return log_oom();
-
- r = mkdir_p_label(p, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create generator directory %s: %m", p);
- free(p);
- return r;
- }
- } else if (m->running_as == MANAGER_USER) {
- const char *s = NULL;
-
- s = getenv("XDG_RUNTIME_DIR");
- if (!s)
- return -EINVAL;
- p = strjoin(s, "/systemd/", name, NULL);
- if (!p)
- return log_oom();
-
- r = mkdir_p_label(p, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create generator directory %s: %m", p);
- free(p);
- return r;
- }
- } else {
- /* systemd --system --test */
-
- p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
- if (!p)
- return log_oom();
-
- if (!mkdtemp(p)) {
- log_error_errno(errno, "Failed to create generator directory %s: %m", p);
- free(p);
- return -errno;
- }
- }
-
- *generator = p;
- return 0;
-}
-
-static void trim_generator_dir(Manager *m, char **generator) {
- assert(m);
- assert(generator);
-
- if (!*generator)
- return;
-
- if (rmdir(*generator) >= 0)
- *generator = mfree(*generator);
-
- return;
-}
-
static int manager_run_generators(Manager *m) {
_cleanup_strv_free_ char **paths = NULL;
const char *argv[5];
@@ -2808,71 +2849,40 @@ static int manager_run_generators(Manager *m) {
if (m->test_run)
return 0;
- paths = generator_paths(m->running_as);
+ paths = generator_binary_paths(m->unit_file_scope);
if (!paths)
return log_oom();
/* Optimize by skipping the whole process by not creating output directories
* if no generators are found. */
STRV_FOREACH(path, paths) {
- r = access(*path, F_OK);
- if (r == 0)
+ if (access(*path, F_OK) >= 0)
goto found;
if (errno != ENOENT)
log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
}
+
return 0;
found:
- r = create_generator_dir(m, &m->generator_unit_path, "generator");
- if (r < 0)
- goto finish;
-
- r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early");
- if (r < 0)
- goto finish;
-
- r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late");
+ r = lookup_paths_mkdir_generator(&m->lookup_paths);
if (r < 0)
goto finish;
argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
- argv[1] = m->generator_unit_path;
- argv[2] = m->generator_unit_path_early;
- argv[3] = m->generator_unit_path_late;
+ argv[1] = m->lookup_paths.generator;
+ argv[2] = m->lookup_paths.generator_early;
+ argv[3] = m->lookup_paths.generator_late;
argv[4] = NULL;
RUN_WITH_UMASK(0022)
execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv);
finish:
- trim_generator_dir(m, &m->generator_unit_path);
- trim_generator_dir(m, &m->generator_unit_path_early);
- trim_generator_dir(m, &m->generator_unit_path_late);
+ lookup_paths_trim_generator(&m->lookup_paths);
return r;
}
-static void remove_generator_dir(Manager *m, char **generator) {
- assert(m);
- assert(generator);
-
- if (!*generator)
- return;
-
- strv_remove(m->lookup_paths.unit_path, *generator);
- (void) rm_rf(*generator, REMOVE_ROOT);
-
- *generator = mfree(*generator);
-}
-
-static void manager_undo_generators(Manager *m) {
- assert(m);
-
- remove_generator_dir(m, &m->generator_unit_path);
- remove_generator_dir(m, &m->generator_unit_path_early);
- remove_generator_dir(m, &m->generator_unit_path_late);
-}
-
int manager_environment_add(Manager *m, char **minus, char **plus) {
char **a = NULL, **b = NULL, **l;
assert(m);
@@ -2935,7 +2945,7 @@ void manager_recheck_journal(Manager *m) {
assert(m);
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return;
u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
@@ -2959,7 +2969,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
assert(m);
assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return;
if (m->show_status != mode)
@@ -2976,7 +2986,7 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
static bool manager_get_show_status(Manager *m, StatusType type) {
assert(m);
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return false;
if (m->no_console_output)
@@ -2998,7 +3008,7 @@ static bool manager_get_show_status(Manager *m, StatusType type) {
void manager_set_first_boot(Manager *m, bool b) {
assert(m);
- if (m->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(m))
return;
if (m->first_boot != (int) b) {
@@ -3044,7 +3054,7 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
const char *manager_get_runtime_prefix(Manager *m) {
assert(m);
- return m->running_as == MANAGER_SYSTEM ?
+ return MANAGER_IS_SYSTEM(m) ?
"/run" :
getenv("XDG_RUNTIME_DIR");
}
diff --git a/src/libcore/manager.h b/src/libcore/manager.h
index d6c97d8f3b..70d79ce549 100644
--- a/src/libcore/manager.h
+++ b/src/libcore/manager.h
@@ -132,6 +132,9 @@ struct Manager {
int notify_fd;
sd_event_source *notify_event_source;
+ int cgroups_agent_fd;
+ sd_event_source *cgroups_agent_event_source;
+
int signal_fd;
sd_event_source *signal_event_source;
@@ -140,6 +143,7 @@ struct Manager {
sd_event_source *jobs_in_progress_event_source;
+ UnitFileScope unit_file_scope;
LookupPaths lookup_paths;
Set *unit_path_cache;
@@ -162,10 +166,6 @@ struct Manager {
dual_timestamp units_load_start_timestamp;
dual_timestamp units_load_finish_timestamp;
- char *generator_unit_path;
- char *generator_unit_path_early;
- char *generator_unit_path_late;
-
struct udev* udev;
/* Data specific to the device subsystem */
@@ -228,7 +228,6 @@ struct Manager {
unsigned n_in_gc_queue;
/* Flags */
- ManagerRunningAs running_as;
ManagerExitCode exit_code:5;
bool dispatching_load_queue:1;
@@ -256,6 +255,7 @@ struct Manager {
bool default_cpu_accounting;
bool default_memory_accounting;
+ bool default_io_accounting;
bool default_blockio_accounting;
bool default_tasks_accounting;
@@ -304,10 +304,15 @@ struct Manager {
const char *unit_log_field;
const char *unit_log_format_string;
- int first_boot;
+ int first_boot; /* tri-state */
};
-int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
+#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
+#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM)
+
+#define MANAGER_IS_RELOADING(m) ((m)->n_reloading > 0)
+
+int manager_new(UnitFileScope scope, bool test_run, Manager **m);
Manager* manager_free(Manager *m);
void manager_enumerate(Manager *m);
@@ -345,8 +350,6 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
int manager_reload(Manager *m);
-bool manager_is_reloading_or_reexecuting(Manager *m) _pure_;
-
void manager_reset_failed(Manager *m);
void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
diff --git a/src/libcore/mount-setup.c b/src/libcore/mount-setup.c
index de1a361cc4..40fc548b42 100644
--- a/src/libcore/mount-setup.c
+++ b/src/libcore/mount-setup.c
@@ -94,7 +94,7 @@ static const MountPoint mount_table[] = {
#endif
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup", "cgroup", "__DEVEL__sane_behavior", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ { "cgroup", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_FATAL|MNT_IN_CONTAINER },
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
@@ -375,6 +375,7 @@ int mount_setup(bool loaded_policy) {
before_relabel = now(CLOCK_MONOTONIC);
nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
+ nftw("/dev/shm", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
after_relabel = now(CLOCK_MONOTONIC);
diff --git a/src/libcore/mount.c b/src/libcore/mount.c
index d573e92759..7db9d1325b 100644
--- a/src/libcore/mount.c
+++ b/src/libcore/mount.c
@@ -86,6 +86,15 @@ static bool mount_is_network(const MountParameters *p) {
return mount_needs_network(p->options, p->fstype);
}
+static bool mount_is_loop(const MountParameters *p) {
+ assert(p);
+
+ if (fstab_test_option(p->options, "loop\0"))
+ return true;
+
+ return false;
+}
+
static bool mount_is_bind(const MountParameters *p) {
assert(p);
@@ -104,6 +113,28 @@ static bool mount_is_auto(const MountParameters *p) {
return !fstab_test_option(p->options, "noauto\0");
}
+static bool mount_is_automount(const MountParameters *p) {
+ assert(p);
+
+ return fstab_test_option(p->options,
+ "comment=systemd.automount\0"
+ "x-systemd.automount\0");
+}
+
+static bool mount_state_active(MountState state) {
+ return IN_SET(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);
+}
+
static bool needs_quota(const MountParameters *p) {
assert(p);
@@ -261,12 +292,12 @@ static int mount_add_mount_links(Mount *m) {
}
/* Adds in links to other mount points that might be needed
- * for the source path (if this is a bind mount) to be
+ * for the source path (if this is a bind mount or a loop mount) to be
* available. */
pm = get_mount_parameters_fragment(m);
if (pm && pm->what &&
path_is_absolute(pm->what) &&
- !mount_is_network(pm)) {
+ (mount_is_bind(pm) || mount_is_loop(pm) || !mount_is_network(pm))) {
r = unit_require_mounts_for(UNIT(m), pm->what);
if (r < 0)
@@ -328,7 +359,7 @@ static int mount_add_device_links(Mount *m) {
if (path_equal(m->where, "/"))
return 0;
- if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
+ if (mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager))
device_wants_mount = true;
r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES);
@@ -344,7 +375,7 @@ static int mount_add_quota_links(Mount *m) {
assert(m);
- if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
return 0;
p = get_mount_parameters_fragment(m);
@@ -368,8 +399,8 @@ static int mount_add_quota_links(Mount *m) {
static bool should_umount(Mount *m) {
MountParameters *p;
- if (path_equal(m->where, "/") ||
- path_equal(m->where, "/usr"))
+ if (PATH_IN_SET(m->where, "/", "/usr") ||
+ path_startswith(m->where, "/run/initramfs"))
return false;
p = get_mount_parameters(m);
@@ -390,16 +421,17 @@ static int mount_add_default_dependencies(Mount *m) {
if (!UNIT(m)->default_dependencies)
return 0;
- if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
return 0;
- /* We do not add any default dependencies to / and /usr, since
- * they are guaranteed to stay mounted the whole time, since
- * our system is on it. Also, don't bother with anything
- * mounted below virtual file systems, it's also going to be
- * virtual, and hence not worth the effort. */
- if (path_equal(m->where, "/") ||
- path_equal(m->where, "/usr") ||
+ /* We do not add any default dependencies to /, /usr or
+ * /run/initramfs/, since they are guaranteed to stay
+ * mounted the whole time, since our system is on it.
+ * Also, don't bother with anything mounted below virtual
+ * file systems, it's also going to be virtual, and hence
+ * not worth the effort. */
+ if (PATH_IN_SET(m->where, "/", "/usr") ||
+ path_startswith(m->where, "/run/initramfs") ||
path_startswith(m->where, "/proc") ||
path_startswith(m->where, "/sys") ||
path_startswith(m->where, "/dev"))
@@ -566,23 +598,6 @@ static int mount_load(Unit *u) {
return mount_verify(m);
}
-static int mount_notify_automount(Mount *m, MountState old_state, MountState state) {
- Unit *p;
- int r;
- Iterator i;
-
- assert(m);
-
- SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
- if (p->type == UNIT_AUTOMOUNT) {
- r = automount_update_mount(AUTOMOUNT(p), old_state, state);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
static void mount_set_state(Mount *m, MountState state) {
MountState old_state;
assert(m);
@@ -590,24 +605,13 @@ static void mount_set_state(Mount *m, MountState state) {
old_state = m->state;
m->state = state;
- if (state != MOUNT_MOUNTING &&
- state != MOUNT_MOUNTING_DONE &&
- state != MOUNT_REMOUNTING &&
- state != MOUNT_UNMOUNTING &&
- state != MOUNT_MOUNTING_SIGTERM &&
- state != MOUNT_MOUNTING_SIGKILL &&
- state != MOUNT_UNMOUNTING_SIGTERM &&
- state != MOUNT_UNMOUNTING_SIGKILL &&
- state != MOUNT_REMOUNTING_SIGTERM &&
- state != MOUNT_REMOUNTING_SIGKILL) {
+ if (!mount_state_active(state)) {
m->timer_event_source = sd_event_source_unref(m->timer_event_source);
mount_unwatch_control_pid(m);
m->control_command = NULL;
m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
}
- mount_notify_automount(m, old_state, state);
-
if (state != old_state)
log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
@@ -633,17 +637,7 @@ static int mount_coldplug(Unit *u) {
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)) {
+ mount_state_active(new_state)) {
r = unit_watch_pid(UNIT(m), m->control_pid);
if (r < 0)
@@ -703,7 +697,6 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
.apply_permissions = true,
.apply_chroot = true,
.apply_tty_stdin = true,
- .bus_endpoint_fd = -1,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
@@ -967,6 +960,7 @@ fail:
static int mount_start(Unit *u) {
Mount *m = MOUNT(u);
+ int r;
assert(m);
@@ -985,6 +979,12 @@ static int mount_start(Unit *u) {
assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
m->result = MOUNT_SUCCESS;
m->reload_result = MOUNT_SUCCESS;
m->reset_cpu_usage = true;
@@ -1385,7 +1385,7 @@ static int mount_setup_unit(
goto fail;
}
- if (m->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(m)) {
const char* target;
target = mount_needs_network(options, fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
@@ -1413,7 +1413,7 @@ static int mount_setup_unit(
}
}
- if (m->running_as == MANAGER_SYSTEM &&
+ if (MANAGER_IS_SYSTEM(m) &&
mount_needs_network(options, fstype)) {
/* _netdev option may have shown up late, or on a
* remount. Add remote-fs dependencies, even though
@@ -1782,6 +1782,14 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
}
+static int mount_control_pid(Unit *u) {
+ Mount *m = MOUNT(u);
+
+ assert(m);
+
+ return m->control_pid;
+}
+
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
@@ -1796,7 +1804,8 @@ static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
[MOUNT_FAILURE_TIMEOUT] = "timeout",
[MOUNT_FAILURE_EXIT_CODE] = "exit-code",
[MOUNT_FAILURE_SIGNAL] = "signal",
- [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
+ [MOUNT_FAILURE_CORE_DUMP] = "core-dump",
+ [MOUNT_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
@@ -1814,9 +1823,6 @@ const UnitVTable mount_vtable = {
"Install\0",
.private_section = "Mount",
- .no_alias = true,
- .no_instances = true,
-
.init = mount_init,
.load = mount_load,
.done = mount_done,
@@ -1843,6 +1849,8 @@ const UnitVTable mount_vtable = {
.reset_failed = mount_reset_failed,
+ .control_pid = mount_control_pid,
+
.bus_vtable = bus_mount_vtable,
.bus_set_property = bus_mount_set_property,
.bus_commit_properties = bus_mount_commit_properties,
diff --git a/src/libcore/mount.h b/src/libcore/mount.h
index 3b343c6b1f..da529c44f4 100644
--- a/src/libcore/mount.h
+++ b/src/libcore/mount.h
@@ -39,6 +39,7 @@ typedef enum MountResult {
MOUNT_FAILURE_EXIT_CODE,
MOUNT_FAILURE_SIGNAL,
MOUNT_FAILURE_CORE_DUMP,
+ MOUNT_FAILURE_START_LIMIT_HIT,
_MOUNT_RESULT_MAX,
_MOUNT_RESULT_INVALID = -1
} MountResult;
diff --git a/src/libcore/namespace.c b/src/libcore/namespace.c
index 4fa381db5b..203d122810 100644
--- a/src/libcore/namespace.c
+++ b/src/libcore/namespace.c
@@ -44,6 +44,8 @@
#include "user-util.h"
#include "util.h"
+#define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC)
+
typedef enum MountMode {
/* This is ordered by priority! */
INACCESSIBLE,
@@ -51,7 +53,6 @@ typedef enum MountMode {
PRIVATE_TMP,
PRIVATE_VAR_TMP,
PRIVATE_DEV,
- PRIVATE_BUS_ENDPOINT,
READWRITE
} MountMode;
@@ -154,7 +155,7 @@ static int mount_dev(BindMount *m) {
dev = strjoina(temporary_mount, "/dev");
(void) mkdir(dev, 0755);
- if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
+ if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
r = -errno;
goto fail;
}
@@ -238,6 +239,8 @@ static int mount_dev(BindMount *m) {
*/
(void) mkdir_p_label(m->path, 0755);
+ /* Unmount everything in old /dev */
+ umount_recursive(m->path, 0);
if (mount(dev, m->path, NULL, MS_MOVE, NULL) < 0) {
r = -errno;
goto fail;
@@ -268,78 +271,6 @@ fail:
return r;
}
-static int mount_kdbus(BindMount *m) {
-
- char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX";
- _cleanup_free_ char *basepath = NULL;
- _cleanup_umask_ mode_t u;
- char *busnode = NULL, *root;
- struct stat st;
- int r;
-
- assert(m);
-
- u = umask(0000);
-
- if (!mkdtemp(temporary_mount))
- return log_error_errno(errno, "Failed create temp dir: %m");
-
- root = strjoina(temporary_mount, "/kdbus");
- (void) mkdir(root, 0755);
- if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
- r = -errno;
- goto fail;
- }
-
- /* create a new /dev/null dev node copy so we have some fodder to
- * bind-mount the custom endpoint over. */
- if (stat("/dev/null", &st) < 0) {
- r = log_error_errno(errno, "Failed to stat /dev/null: %m");
- goto fail;
- }
-
- busnode = strjoina(root, "/bus");
- if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
- r = log_error_errno(errno, "mknod() for %s failed: %m",
- busnode);
- goto fail;
- }
-
- r = mount(m->path, busnode, NULL, MS_BIND, NULL);
- if (r < 0) {
- r = log_error_errno(errno, "bind mount of %s failed: %m",
- m->path);
- goto fail;
- }
-
- basepath = dirname_malloc(m->path);
- if (!basepath) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
- r = log_error_errno(errno, "bind mount of %s failed: %m",
- basepath);
- goto fail;
- }
-
- rmdir(temporary_mount);
- return 0;
-
-fail:
- if (busnode) {
- umount(busnode);
- unlink(busnode);
- }
-
- umount(root);
- rmdir(root);
- rmdir(temporary_mount);
-
- return r;
-}
-
static int apply_mount(
BindMount *m,
const char *tmp_dir,
@@ -379,9 +310,6 @@ static int apply_mount(
case PRIVATE_DEV:
return mount_dev(m);
- case PRIVATE_BUS_ENDPOINT:
- return mount_kdbus(m);
-
default:
assert_not_reached("Unknown mode");
}
@@ -404,9 +332,11 @@ static int make_read_only(BindMount *m) {
if (IN_SET(m->mode, INACCESSIBLE, READONLY))
r = bind_remount_recursive(m->path, true);
- else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV))
+ else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV)) {
r = bind_remount_recursive(m->path, false);
- else
+ if (r == 0 && m->mode == PRIVATE_DEV) /* can be readonly but the submounts can't*/
+ r = mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL);
+ } else
r = 0;
if (m->ignore && r == -ENOENT)
@@ -422,7 +352,6 @@ int setup_namespace(
char** inaccessible_dirs,
const char* tmp_dir,
const char* var_tmp_dir,
- const char* bus_endpoint_path,
bool private_dev,
ProtectHome protect_home,
ProtectSystem protect_system,
@@ -438,7 +367,7 @@ int setup_namespace(
if (unshare(CLONE_NEWNS) < 0)
return -errno;
- n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path +
+ n = !!tmp_dir + !!var_tmp_dir +
strv_length(read_write_dirs) +
strv_length(read_only_dirs) +
strv_length(inaccessible_dirs) +
@@ -479,12 +408,6 @@ int setup_namespace(
m++;
}
- if (bus_endpoint_path) {
- m->path = prefix_roota(root_directory, bus_endpoint_path);
- m->mode = PRIVATE_BUS_ENDPOINT;
- m++;
- }
-
if (protect_home != PROTECT_HOME_NO) {
const char *home_dir, *run_user_dir, *root_dir;
diff --git a/src/libcore/namespace.h b/src/libcore/namespace.h
index 40bee74e2c..b54b7b47d6 100644
--- a/src/libcore/namespace.h
+++ b/src/libcore/namespace.h
@@ -45,7 +45,6 @@ int setup_namespace(const char *chroot,
char **inaccessible_dirs,
const char *tmp_dir,
const char *var_tmp_dir,
- const char *endpoint_path,
bool private_dev,
ProtectHome protect_home,
ProtectSystem protect_system,
diff --git a/src/libcore/path.c b/src/libcore/path.c
index 460c1d3bf2..0dd0d375d8 100644
--- a/src/libcore/path.c
+++ b/src/libcore/path.c
@@ -110,16 +110,14 @@ int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
} else {
exists = true;
- /* Path exists, we don't need to watch parent
- too closely. */
+ /* Path exists, we don't need to watch parent too closely. */
if (oldslash) {
char *cut2 = oldslash + (oldslash == s->path);
char tmp2 = *cut2;
*cut2 = '\0';
- inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
- /* Error is ignored, the worst can happen is
- we get spurious events. */
+ (void) inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
+ /* Error is ignored, the worst can happen is we get spurious events. */
*cut2 = tmp2;
}
@@ -320,7 +318,7 @@ static int path_add_default_dependencies(Path *p) {
if (r < 0)
return r;
- if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(UNIT(p)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@@ -476,7 +474,7 @@ static void path_enter_running(Path *p) {
trigger = UNIT_TRIGGER(UNIT(p));
if (!trigger) {
log_unit_error(UNIT(p), "Unit to trigger vanished.");
- path_enter_dead(p, TIMER_FAILURE_RESOURCES);
+ path_enter_dead(p, PATH_FAILURE_RESOURCES);
return;
}
@@ -562,6 +560,7 @@ static void path_mkdir(Path *p) {
static int path_start(Unit *u) {
Path *p = PATH(u);
Unit *trigger;
+ int r;
assert(p);
assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
@@ -572,6 +571,12 @@ static int path_start(Unit *u) {
return -ENOENT;
}
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
path_mkdir(p);
p->result = PATH_SUCCESS;
@@ -741,6 +746,7 @@ DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
static const char* const path_result_table[_PATH_RESULT_MAX] = {
[PATH_SUCCESS] = "success",
[PATH_FAILURE_RESOURCES] = "resources",
+ [PATH_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
diff --git a/src/libcore/path.h b/src/libcore/path.h
index bbbcebd78e..4230c8fb99 100644
--- a/src/libcore/path.h
+++ b/src/libcore/path.h
@@ -62,6 +62,7 @@ static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) {
typedef enum PathResult {
PATH_SUCCESS,
PATH_FAILURE_RESOURCES,
+ PATH_FAILURE_START_LIMIT_HIT,
_PATH_RESULT_MAX,
_PATH_RESULT_INVALID = -1
} PathResult;
diff --git a/src/libcore/scope.c b/src/libcore/scope.c
index c5d0ecef04..238f63a729 100644
--- a/src/libcore/scope.c
+++ b/src/libcore/scope.c
@@ -50,8 +50,7 @@ static void scope_init(Unit *u) {
assert(u->load_state == UNIT_STUB);
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
-
- UNIT(s)->ignore_on_isolate = true;
+ u->ignore_on_isolate = true;
}
static void scope_done(Unit *u) {
@@ -139,7 +138,7 @@ static int scope_verify(Scope *s) {
return 0;
if (set_isempty(UNIT(s)->pids) &&
- !manager_is_reloading_or_reexecuting(UNIT(s)->manager) &&
+ !MANAGER_IS_RELOADING(UNIT(s)->manager) &&
!unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
return -EINVAL;
@@ -155,26 +154,27 @@ static int scope_load(Unit *u) {
assert(s);
assert(u->load_state == UNIT_STUB);
- if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
+ if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
+ /* Refuse to load non-transient scope units, but allow them while reloading. */
return -ENOENT;
- u->load_state = UNIT_LOADED;
-
- r = unit_load_dropin(u);
+ r = unit_load_fragment_and_dropin_optional(u);
if (r < 0)
return r;
- r = unit_patch_contexts(u);
- if (r < 0)
- return r;
+ if (u->load_state == UNIT_LOADED) {
+ r = unit_patch_contexts(u);
+ if (r < 0)
+ return r;
- r = unit_set_default_slice(u);
- if (r < 0)
- return r;
+ r = unit_set_default_slice(u);
+ if (r < 0)
+ return r;
- r = scope_add_default_dependencies(s);
- if (r < 0)
- return r;
+ r = scope_add_default_dependencies(s);
+ if (r < 0)
+ return r;
+ }
return scope_verify(s);
}
@@ -293,7 +293,7 @@ static int scope_start(Unit *u) {
assert(s->state == SCOPE_DEAD);
- if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
+ if (!u->transient && !MANAGER_IS_RELOADING(u->manager))
return -ENOENT;
(void) unit_realize_cgroup(u);
@@ -569,8 +569,6 @@ const UnitVTable scope_vtable = {
"Install\0",
.private_section = "Scope",
- .no_alias = true,
- .no_instances = true,
.can_transient = true,
.init = scope_init,
diff --git a/src/libcore/selinux-access.c b/src/libcore/selinux-access.c
index 76fcc9a6be..2c04fb0a8f 100644
--- a/src/libcore/selinux-access.c
+++ b/src/libcore/selinux-access.c
@@ -110,6 +110,7 @@ static int callback_type_to_priority(int type) {
*/
_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
va_list ap;
+ const char *fmt2;
#ifdef HAVE_AUDIT
int fd;
@@ -131,8 +132,10 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
}
#endif
+ fmt2 = strjoina("selinux: ", fmt);
+
va_start(ap, fmt);
- log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
+ log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt2, ap);
va_end(ap);
return 0;
diff --git a/src/libcore/selinux-setup.c b/src/libcore/selinux-setup.c
index 9a115a4387..4072df58e6 100644
--- a/src/libcore/selinux-setup.c
+++ b/src/libcore/selinux-setup.c
@@ -88,7 +88,7 @@ int mac_selinux_setup(bool *loaded_policy) {
log_open();
log_error("Failed to compute init label, ignoring.");
} else {
- r = setcon(label);
+ r = setcon_raw(label);
log_open();
if (r < 0)
diff --git a/src/libcore/service.c b/src/libcore/service.c
index ac7e41d777..7ebabca5d6 100644
--- a/src/libcore/service.c
+++ b/src/libcore/service.c
@@ -113,7 +113,6 @@ static void service_init(Unit *u) {
s->runtime_max_usec = USEC_INFINITY;
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;
@@ -181,20 +180,17 @@ static int service_set_main_pid(Service *s, pid_t pid) {
return 0;
}
-static void service_close_socket_fd(Service *s) {
+void service_close_socket_fd(Service *s) {
assert(s);
- s->socket_fd = asynchronous_close(s->socket_fd);
-}
-
-static void service_connection_unref(Service *s) {
- assert(s);
+ /* Undo the effect of service_set_socket_fd(). */
- if (!UNIT_ISSET(s->accept_socket))
- return;
+ s->socket_fd = asynchronous_close(s->socket_fd);
- socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
- unit_ref_unset(&s->accept_socket);
+ if (UNIT_ISSET(s->accept_socket)) {
+ socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
+ unit_ref_unset(&s->accept_socket);
+ }
}
static void service_stop_watchdog(Service *s) {
@@ -321,9 +317,7 @@ static void service_done(Unit *u) {
s->bus_name_owner = mfree(s->bus_name_owner);
- s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd);
service_close_socket_fd(s);
- service_connection_unref(s);
unit_ref_unset(&s->accept_socket);
@@ -525,7 +519,7 @@ static int service_add_default_dependencies(Service *s) {
/* Add a number of automatic dependencies useful for the
* majority of services. */
- if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
/* First, pull in the really early boot stuff, and
* require it, so that we fail if we can't acquire
* it. */
@@ -834,7 +828,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
return 0;
}
-static int service_search_main_pid(Service *s) {
+static void service_search_main_pid(Service *s) {
pid_t pid = 0;
int r;
@@ -843,30 +837,24 @@ static int service_search_main_pid(Service *s) {
/* If we know it anyway, don't ever fallback to unreliable
* heuristics */
if (s->main_pid_known)
- return 0;
+ return;
if (!s->guess_main_pid)
- return 0;
+ return;
assert(s->main_pid <= 0);
- r = unit_search_main_pid(UNIT(s), &pid);
- if (r < 0)
- return r;
+ if (unit_search_main_pid(UNIT(s), &pid) < 0)
+ return;
log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid);
- r = service_set_main_pid(s, pid);
- if (r < 0)
- return r;
+ if (service_set_main_pid(s, pid) < 0)
+ return;
r = unit_watch_pid(UNIT(s), pid);
- if (r < 0) {
+ if (r < 0)
/* FIXME: we need to do something here */
log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
- return r;
- }
-
- return 0;
}
static void service_set_state(Service *s, ServiceState state) {
@@ -918,17 +906,15 @@ static void service_set_state(Service *s, ServiceState state) {
SERVICE_RUNNING, SERVICE_RELOAD,
SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
- !(state == SERVICE_DEAD && UNIT(s)->job)) {
+ !(state == SERVICE_DEAD && UNIT(s)->job))
service_close_socket_fd(s);
- service_connection_unref(s);
- }
if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
service_stop_watchdog(s);
/* For the inactive states unit_notify() will trim the cgroup,
* but for exit we have to do that ourselves... */
- if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
+ if (state == SERVICE_EXITED && !MANAGER_IS_RELOADING(UNIT(s)->manager))
unit_prune_cgroup(UNIT(s));
/* For remain_after_exit services, let's see if we can "release" the
@@ -944,7 +930,7 @@ static void service_set_state(Service *s, ServiceState state) {
if (ec && exec_context_may_touch_console(ec)) {
Manager *m = UNIT(s)->manager;
- m->n_on_console --;
+ m->n_on_console--;
if (m->n_on_console == 0)
/* unset no_console_output flag, since the console is free */
m->no_console_output = false;
@@ -1157,7 +1143,6 @@ static int service_spawn(
pid_t *_pid) {
_cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
- _cleanup_free_ char *bus_endpoint_path = NULL;
_cleanup_free_ int *fds = NULL;
unsigned n_fds = 0, n_env = 0;
const char *path;
@@ -1167,7 +1152,6 @@ static int service_spawn(
.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,
@@ -1221,7 +1205,7 @@ static int service_spawn(
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
return -ENOMEM;
- if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
return -ENOMEM;
@@ -1267,18 +1251,6 @@ static int service_spawn(
} else
path = UNIT(s)->cgroup_path;
- if (s->exec_context.bus_endpoint) {
- r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user",
- UNIT(s)->id, &bus_endpoint_path);
- if (r < 0)
- return r;
-
- /* Pass the fd to the exec_params so that the child process can upload the policy.
- * Keep a reference to the fd in the service, so the endpoint is kept alive as long
- * as the service is running. */
- exec_params.bus_endpoint_fd = s->bus_endpoint_fd = r;
- }
-
exec_params.argv = argv;
exec_params.fds = fds;
exec_params.fd_names = fd_names;
@@ -1290,7 +1262,6 @@ static int service_spawn(
exec_params.cgroup_delegate = s->cgroup_context.delegate;
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;
@@ -1986,6 +1957,7 @@ fail:
static int service_start(Unit *u) {
Service *s = SERVICE(u);
+ int r;
assert(s);
@@ -2012,6 +1984,13 @@ static int service_start(Unit *u) {
assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
+ /* Make sure we don't enter a busy loop of some kind. */
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
+ return r;
+ }
+
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
s->main_pid_known = false;
@@ -2126,9 +2105,6 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
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;
@@ -2154,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);
+ dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
@@ -2263,15 +2238,6 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
asynchronous_close(s->socket_fd);
s->socket_fd = fdset_remove(fds, fd);
}
- } else if (streq(key, "endpoint-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "Failed to parse endpoint-fd value: %s", value);
- else {
- safe_close(s->bus_endpoint_fd);
- s->bus_endpoint_fd = fdset_remove(fds, fd);
- }
} else if (streq(key, "fd-store-fd")) {
const char *fdv;
size_t pf;
@@ -2759,7 +2725,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
}
} else
- (void) service_search_main_pid(s);
+ service_search_main_pid(s);
service_enter_start_post(s);
break;
@@ -2781,16 +2747,15 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
}
} else
- (void) service_search_main_pid(s);
+ service_search_main_pid(s);
service_enter_running(s, SERVICE_SUCCESS);
break;
case SERVICE_RELOAD:
- if (f == SERVICE_SUCCESS) {
- service_load_pid_file(s, true);
- (void) service_search_main_pid(s);
- }
+ if (f == SERVICE_SUCCESS)
+ if (service_load_pid_file(s, true) < 0)
+ service_search_main_pid(s);
s->reload_result = f;
service_enter_running(s, SERVICE_SUCCESS);
@@ -3176,9 +3141,8 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
assert(s);
assert(fd >= 0);
- /* This is called by the socket code when instantiating a new
- * service for a stream socket and the socket needs to be
- * configured. */
+ /* This is called by the socket code when instantiating a new service for a stream socket and the socket needs
+ * to be configured. We take ownership of the passed fd on success. */
if (UNIT(s)->load_state != UNIT_LOADED)
return -EINVAL;
@@ -3206,12 +3170,15 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context
return r;
}
+ r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+ if (r < 0)
+ return r;
+
s->socket_fd = fd;
s->socket_fd_selinux_context_net = selinux_context_net;
unit_ref_set(&s->accept_socket, UNIT(sock));
-
- return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
+ return 0;
}
static void service_reset_failed(Unit *u) {
@@ -3232,6 +3199,22 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
}
+static int service_main_pid(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(s);
+
+ return s->main_pid;
+}
+
+static int service_control_pid(Unit *u) {
+ Service *s = SERVICE(u);
+
+ assert(s);
+
+ return s->control_pid;
+}
+
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
[SERVICE_RESTART_NO] = "no",
[SERVICE_RESTART_ON_SUCCESS] = "on-success",
@@ -3291,6 +3274,7 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
[SERVICE_FAILURE_SIGNAL] = "signal",
[SERVICE_FAILURE_CORE_DUMP] = "core-dump",
[SERVICE_FAILURE_WATCHDOG] = "watchdog",
+ [SERVICE_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
@@ -3340,6 +3324,9 @@ const UnitVTable service_vtable = {
.notify_cgroup_empty = service_notify_cgroup_empty_event,
.notify_message = service_notify_message,
+ .main_pid = service_main_pid,
+ .control_pid = service_control_pid,
+
.bus_name_owner_change = service_bus_name_owner_change,
.bus_vtable = bus_service_vtable,
diff --git a/src/libcore/service.h b/src/libcore/service.h
index d342e000bb..4af3d40439 100644
--- a/src/libcore/service.h
+++ b/src/libcore/service.h
@@ -80,12 +80,13 @@ typedef enum NotifyState {
typedef enum ServiceResult {
SERVICE_SUCCESS,
- SERVICE_FAILURE_RESOURCES,
+ SERVICE_FAILURE_RESOURCES, /* a bit of a misnomer, just our catch-all error for errnos we didn't expect */
SERVICE_FAILURE_TIMEOUT,
SERVICE_FAILURE_EXIT_CODE,
SERVICE_FAILURE_SIGNAL,
SERVICE_FAILURE_CORE_DUMP,
SERVICE_FAILURE_WATCHDOG,
+ SERVICE_FAILURE_START_LIMIT_HIT,
_SERVICE_RESULT_MAX,
_SERVICE_RESULT_INVALID = -1
} ServiceResult;
@@ -150,8 +151,6 @@ struct Service {
int socket_fd;
bool socket_fd_selinux_context_net;
- int bus_endpoint_fd;
-
bool permissions_start_only;
bool root_directory_start_only;
bool remain_after_exit;
@@ -200,6 +199,7 @@ struct Service {
extern const UnitVTable service_vtable;
int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
+void service_close_socket_fd(Service *s);
const char* service_restart_to_string(ServiceRestart i) _const_;
ServiceRestart service_restart_from_string(const char *s) _pure_;
diff --git a/src/libcore/shutdown.c b/src/libcore/shutdown.c
index 6296b4c94a..e14755d84e 100644
--- a/src/libcore/shutdown.c
+++ b/src/libcore/shutdown.c
@@ -202,7 +202,7 @@ int main(int argc, char *argv[]) {
goto error;
}
- cg_get_root_path(&cgroup);
+ (void) cg_get_root_path(&cgroup);
use_watchdog = !!getenv("WATCHDOG_USEC");
@@ -397,9 +397,14 @@ int main(int argc, char *argv[]) {
if (!in_container) {
_cleanup_free_ char *param = NULL;
- if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
+ r = read_one_line_file("/run/systemd/reboot-param", &param);
+ if (r < 0)
+ log_warning_errno(r, "Failed to read reboot parameter file: %m");
+
+ if (!isempty(param)) {
log_info("Rebooting with argument '%s'.", param);
syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
+ log_warning_errno(errno, "Failed to reboot with parameter, retrying without: %m");
}
}
diff --git a/src/libcore/slice.c b/src/libcore/slice.c
index d65364c6f4..c7700b8857 100644
--- a/src/libcore/slice.c
+++ b/src/libcore/slice.c
@@ -34,6 +34,13 @@ static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_ACTIVE] = UNIT_ACTIVE
};
+static void slice_init(Unit *u) {
+ assert(u);
+ assert(u->load_state == UNIT_STUB);
+
+ u->ignore_on_isolate = true;
+}
+
static void slice_set_state(Slice *t, SliceState state) {
SliceState old_state;
assert(t);
@@ -128,6 +135,7 @@ static int slice_load(Unit *u) {
int r;
assert(s);
+ assert(u->load_state == UNIT_STUB);
r = unit_load_fragment_and_dropin_optional(u);
if (r < 0)
@@ -301,10 +309,9 @@ const UnitVTable slice_vtable = {
"Install\0",
.private_section = "Slice",
- .no_alias = true,
- .no_instances = true,
.can_transient = true,
+ .init = slice_init,
.load = slice_load,
.coldplug = slice_coldplug,
diff --git a/src/libcore/smack-setup.c b/src/libcore/smack-setup.c
index 0c26e85460..5a6d11cfa1 100644
--- a/src/libcore/smack-setup.c
+++ b/src/libcore/smack-setup.c
@@ -261,7 +261,7 @@ static int write_netlabel_rules(const char* srcdir) {
}
}
- return r;
+ return r;
}
#endif
diff --git a/src/libcore/socket.c b/src/libcore/socket.c
index f36e312f7b..f6204d04bf 100644
--- a/src/libcore/socket.c
+++ b/src/libcore/socket.c
@@ -28,7 +28,6 @@
#include <unistd.h>
#include <linux/sctp.h>
-#include <systemd/sd-event.h>
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
@@ -38,6 +37,7 @@
#include "exit-status.h"
#include "fd-util.h"
#include "formats-util.h"
+#include "io-util.h"
#include "label.h"
#include "log.h"
#include "missing.h"
@@ -99,6 +99,9 @@ static void socket_init(Unit *u) {
s->exec_context.std_error = u->manager->default_std_error;
s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
+
+ s->trigger_limit.interval = USEC_INFINITY;
+ s->trigger_limit.burst = (unsigned) -1;
}
static void socket_unwatch_control_pid(Socket *s) {
@@ -227,7 +230,6 @@ int socket_instantiate_service(Socket *s) {
if (r < 0)
return r;
- u->no_gc = true;
unit_ref_set(&s->service, u);
return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
@@ -301,7 +303,7 @@ static int socket_add_default_dependencies(Socket *s) {
if (r < 0)
return r;
- if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(UNIT(s)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@@ -327,6 +329,25 @@ static int socket_add_extras(Socket *s) {
assert(s);
+ /* Pick defaults for the trigger limit, if nothing was explicitly configured. We pick a relatively high limit
+ * in Accept=yes mode, and a lower limit for Accept=no. Reason: in Accept=yes mode we are invoking accept()
+ * ourselves before the trigger limit can hit, thus incoming connections are taken off the socket queue quickly
+ * and reliably. This is different for Accept=no, where the spawned service has to take the incoming traffic
+ * off the queues, which it might not necessarily do. Moreover, while Accept=no services are supposed to
+ * process whatever is queued in one go, and thus should normally never have to be started frequently. This is
+ * different for Accept=yes where each connection is processed by a new service instance, and thus frequent
+ * service starts are typical. */
+
+ if (s->trigger_limit.interval == USEC_INFINITY)
+ s->trigger_limit.interval = 2 * USEC_PER_SEC;
+
+ if (s->trigger_limit.burst == (unsigned) -1) {
+ if (s->accept)
+ s->trigger_limit.burst = 200;
+ else
+ s->trigger_limit.burst = 20;
+ }
+
if (have_non_accept_socket(s)) {
if (!UNIT_DEREF(s->service)) {
@@ -619,8 +640,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
if (!isempty(s->user) || !isempty(s->group))
fprintf(f,
- "%sOwnerUser: %s\n"
- "%sOwnerGroup: %s\n",
+ "%sSocketUser: %s\n"
+ "%sSocketGroup: %s\n",
prefix, strna(s->user),
prefix, strna(s->group));
@@ -669,6 +690,12 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
}
+ fprintf(f,
+ "%sTriggerLimitIntervalSec: %s\n"
+ "%sTriggerLimitBurst: %u\n",
+ prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->trigger_limit.interval, USEC_PER_SEC),
+ prefix, s->trigger_limit.burst);
+
exec_context_dump(&s->exec_context, f, prefix);
kill_context_dump(&s->kill_context, f, prefix);
@@ -792,47 +819,45 @@ static void socket_close_fds(Socket *s) {
assert(s);
LIST_FOREACH(port, p, s->ports) {
+ bool was_open;
- p->event_source = sd_event_source_unref(p->event_source);
-
- if (p->fd < 0)
- continue;
+ was_open = p->fd >= 0;
+ p->event_source = sd_event_source_unref(p->event_source);
p->fd = safe_close(p->fd);
socket_cleanup_fd_list(p);
- /* One little note: we should normally not delete any
- * sockets in the file system here! After all some
- * other process we spawned might still have a
- * reference of this fd and wants to continue to use
- * it. Therefore we delete sockets in the file system
- * before we create a new one, not after we stopped
- * using one! */
+ /* One little note: we should normally not delete any sockets in the file system here! After all some
+ * other process we spawned might still have a reference of this fd and wants to continue to use
+ * it. Therefore we normally delete sockets in the file system before we create a new one, not after we
+ * stopped using one! That all said, if the user explicitly requested this, we'll delete them here
+ * anyway, but only then. */
- if (s->remove_on_stop) {
- switch (p->type) {
+ if (!was_open || !s->remove_on_stop)
+ continue;
- case SOCKET_FIFO:
- unlink(p->path);
- break;
+ switch (p->type) {
- case SOCKET_MQUEUE:
- mq_unlink(p->path);
- break;
+ case SOCKET_FIFO:
+ (void) unlink(p->path);
+ break;
- case SOCKET_SOCKET:
- socket_address_unlink(&p->address);
- break;
+ case SOCKET_MQUEUE:
+ (void) mq_unlink(p->path);
+ break;
- default:
- break;
- }
+ case SOCKET_SOCKET:
+ (void) socket_address_unlink(&p->address);
+ break;
+
+ default:
+ break;
}
}
if (s->remove_on_stop)
STRV_FOREACH(i, s->symlinks)
- unlink(*i);
+ (void) unlink(*i);
}
static void socket_apply_socket_options(Socket *s, int fd) {
@@ -1222,6 +1247,45 @@ fail:
return r;
}
+static int socket_determine_selinux_label(Socket *s, char **ret) {
+ ExecCommand *c;
+ int r;
+
+ assert(s);
+ assert(ret);
+
+ if (s->selinux_context_from_net) {
+ /* If this is requested, get label from the network label */
+
+ r = mac_selinux_get_our_label(ret);
+ if (r == -EOPNOTSUPP)
+ goto no_label;
+
+ } else {
+ /* Otherwise, get it from the executable we are about to start */
+ r = socket_instantiate_service(s);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_ISSET(s->service))
+ goto no_label;
+
+ c = SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START];
+ if (!c)
+ goto no_label;
+
+ r = mac_selinux_get_create_label_from_exe(c->path, ret);
+ if (r == -EPERM || r == -EOPNOTSUPP)
+ goto no_label;
+ }
+
+ return r;
+
+no_label:
+ *ret = NULL;
+ return 0;
+}
+
static int socket_open_fds(Socket *s) {
_cleanup_(mac_selinux_freep) char *label = NULL;
bool know_label = false;
@@ -1240,46 +1304,28 @@ static int socket_open_fds(Socket *s) {
case SOCKET_SOCKET:
if (!know_label) {
- /* Figure out label, if we don't it know
- * yet. We do it once, for the first
- * socket where we need this and
- * remember it for the rest. */
-
- if (s->selinux_context_from_net) {
- /* Get it from the network label */
-
- r = mac_selinux_get_our_label(&label);
- if (r < 0 && r != -EOPNOTSUPP)
- goto rollback;
+ /* Figure out label, if we don't it know yet. We do it once, for the first socket where
+ * we need this and remember it for the rest. */
- } else {
- /* Get it from the executable we are about to start */
-
- r = socket_instantiate_service(s);
- if (r < 0)
- goto rollback;
-
- if (UNIT_ISSET(s->service) &&
- SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
- r = mac_selinux_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
- if (r < 0 && r != -EPERM && r != -EOPNOTSUPP)
- goto rollback;
- }
- }
+ r = socket_determine_selinux_label(s, &label);
+ if (r < 0)
+ goto rollback;
know_label = true;
}
/* Apply the socket protocol */
- switch(p->address.type) {
+ switch (p->address.type) {
+
case SOCK_STREAM:
case SOCK_SEQPACKET:
- if (p->socket->socket_protocol == IPPROTO_SCTP)
- p->address.protocol = p->socket->socket_protocol;
+ if (s->socket_protocol == IPPROTO_SCTP)
+ p->address.protocol = s->socket_protocol;
break;
+
case SOCK_DGRAM:
- if (p->socket->socket_protocol == IPPROTO_UDPLITE)
- p->address.protocol = p->socket->socket_protocol;
+ if (s->socket_protocol == IPPROTO_UDPLITE)
+ p->address.protocol = s->socket_protocol;
break;
}
@@ -1340,9 +1386,12 @@ static int socket_open_fds(Socket *s) {
}
break;
- case SOCKET_USB_FUNCTION:
+ case SOCKET_USB_FUNCTION: {
+ _cleanup_free_ char *ep = NULL;
- p->fd = usbffs_address_create(p->path);
+ ep = path_make_absolute("ep0", p->path);
+
+ p->fd = usbffs_address_create(ep);
if (p->fd < 0) {
r = p->fd;
goto rollback;
@@ -1357,7 +1406,7 @@ static int socket_open_fds(Socket *s) {
goto rollback;
break;
-
+ }
default:
assert_not_reached("Unknown port type");
}
@@ -1420,6 +1469,34 @@ fail:
return r;
}
+enum {
+ SOCKET_OPEN_NONE,
+ SOCKET_OPEN_SOME,
+ SOCKET_OPEN_ALL,
+};
+
+static int socket_check_open(Socket *s) {
+ bool have_open = false, have_closed = false;
+ SocketPort *p;
+
+ assert(s);
+
+ LIST_FOREACH(port, p, s->ports) {
+ if (p->fd < 0)
+ have_closed = true;
+ else
+ have_open = true;
+
+ if (have_open && have_closed)
+ return SOCKET_OPEN_SOME;
+ }
+
+ if (have_open)
+ return SOCKET_OPEN_ALL;
+
+ return SOCKET_OPEN_NONE;
+}
+
static void socket_set_state(Socket *s, SocketState state) {
SocketState old_state;
assert(s);
@@ -1499,14 +1576,24 @@ static int socket_coldplug(Unit *u) {
SOCKET_START_CHOWN,
SOCKET_START_POST,
SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL)) {
-
- r = socket_open_fds(s);
- if (r < 0)
- return r;
+ SOCKET_RUNNING)) {
+
+ /* Originally, we used to simply reopen all sockets here that we didn't have file descriptors
+ * for. However, this is problematic, as we won't traverse throught the SOCKET_START_CHOWN state for
+ * them, and thus the UID/GID wouldn't be right. Hence, instead simply check if we have all fds open,
+ * and if there's a mismatch, warn loudly. */
+
+ r = socket_check_open(s);
+ if (r == SOCKET_OPEN_NONE)
+ log_unit_warning(UNIT(s),
+ "Socket unit configuration has changed while unit has been running, "
+ "no open socket file descriptor left. "
+ "The socket unit is not functional until restarted.");
+ else if (r == SOCKET_OPEN_SOME)
+ log_unit_warning(UNIT(s),
+ "Socket unit configuration has changed while unit has been running, "
+ "and some socket file descriptors have not been opened yet. "
+ "The socket unit is not fully functional until restarted.");
}
if (s->deserialized_state == SOCKET_LISTENING) {
@@ -1527,7 +1614,6 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
.apply_permissions = true,
.apply_chroot = true,
.apply_tty_stdin = true,
- .bus_endpoint_fd = -1,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
@@ -1880,38 +1966,47 @@ fail:
socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
}
+static void flush_ports(Socket *s) {
+ SocketPort *p;
+
+ /* Flush all incoming traffic, regardless if actual bytes or new connections, so that this socket isn't busy
+ * anymore */
+
+ LIST_FOREACH(port, p, s->ports) {
+ if (p->fd < 0)
+ continue;
+
+ (void) flush_accept(p->fd);
+ (void) flush_fd(p->fd);
+ }
+}
+
static void socket_enter_running(Socket *s, int cfd) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
+ /* Note that this call takes possession of the connection fd passed. It either has to assign it somewhere or
+ * close it. */
+
assert(s);
- /* We don't take connections anymore if we are supposed to
- * shut down anyway */
+ /* We don't take connections anymore if we are supposed to shut down anyway */
if (unit_stop_pending(UNIT(s))) {
log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled.");
if (cfd >= 0)
- safe_close(cfd);
- else {
- /* Flush all sockets by closing and reopening them */
- socket_close_fds(s);
-
- r = socket_open_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to listen on sockets: %m");
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- return;
- }
+ cfd = safe_close(cfd);
+ else
+ flush_ports(s);
- r = socket_watch_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- }
- }
+ return;
+ }
+ if (!ratelimit_test(&s->trigger_limit)) {
+ safe_close(cfd);
+ log_unit_warning(UNIT(s), "Trigger limit hit, refusing further activation.");
+ socket_enter_stop_pre(s, SOCKET_FAILURE_TRIGGER_LIMIT_HIT);
return;
}
@@ -1946,7 +2041,7 @@ static void socket_enter_running(Socket *s, int cfd) {
Service *service;
if (s->n_connections >= s->max_connections) {
- log_unit_warning(UNIT(s), "Too many incoming connections (%u)", s->n_connections);
+ log_unit_warning(UNIT(s), "Too many incoming connections (%u), refusing connection attempt.", s->n_connections);
safe_close(cfd);
return;
}
@@ -1962,6 +2057,7 @@ static void socket_enter_running(Socket *s, int cfd) {
/* ENOTCONN is legitimate if TCP RST was received.
* This connection is over, but the socket unit lives on. */
+ log_unit_debug(UNIT(s), "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring.");
safe_close(cfd);
return;
}
@@ -1980,22 +2076,24 @@ static void socket_enter_running(Socket *s, int cfd) {
service = SERVICE(UNIT_DEREF(s->service));
unit_ref_unset(&s->service);
- s->n_accepted ++;
-
- UNIT(service)->no_gc = false;
+ s->n_accepted++;
unit_choose_id(UNIT(service), name);
r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net);
if (r < 0)
goto fail;
- cfd = -1;
- s->n_connections ++;
+ cfd = -1; /* We passed ownership of the fd to the service now. Forget it here. */
+ s->n_connections++;
r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
- if (r < 0)
+ if (r < 0) {
+ /* We failed to activate the new service, but it still exists. Let's make sure the service
+ * closes and forgets the connection fd again, immediately. */
+ service_close_socket_fd(service);
goto fail;
+ }
/* Notify clients about changed counters */
unit_add_to_dbus_queue(UNIT(s));
@@ -2042,6 +2140,7 @@ fail:
static int socket_start(Unit *u) {
Socket *s = SOCKET(u);
+ int r;
assert(s);
@@ -2086,6 +2185,12 @@ static int socket_start(Unit *u) {
assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
s->result = SOCKET_SUCCESS;
s->reset_cpu_usage = true;
@@ -2720,17 +2825,26 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
assert(u);
assert(other);
- /* Don't propagate state changes from the service if we are
- already down or accepting connections */
- if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING) || s->accept)
+ /* Filter out invocations with bogus state */
+ if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
+ return;
+
+ /* Don't propagate state changes from the service if we are already down */
+ if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING))
return;
+ /* We don't care for the service state if we are in Accept=yes mode */
+ if (s->accept)
+ return;
+
+ /* Propagate start limit hit state */
if (other->start_limit_hit) {
socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT);
return;
}
- if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
+ /* Don't propagate anything if there's still a job queued */
+ if (other->job)
return;
if (IN_SET(SERVICE(other)->state,
@@ -2778,6 +2892,14 @@ char *socket_fdname(Socket *s) {
return UNIT(s)->id;
}
+static int socket_control_pid(Unit *u) {
+ Socket *s = SOCKET(u);
+
+ assert(s);
+
+ return s->control_pid;
+}
+
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "StartPre",
[SOCKET_EXEC_START_CHOWN] = "StartChown",
@@ -2795,6 +2917,8 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
[SOCKET_FAILURE_EXIT_CODE] = "exit-code",
[SOCKET_FAILURE_SIGNAL] = "signal",
[SOCKET_FAILURE_CORE_DUMP] = "core-dump",
+ [SOCKET_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
+ [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit",
[SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit"
};
@@ -2843,6 +2967,8 @@ const UnitVTable socket_vtable = {
.reset_failed = socket_reset_failed,
+ .control_pid = socket_control_pid,
+
.bus_vtable = bus_socket_vtable,
.bus_set_property = bus_socket_set_property,
.bus_commit_properties = bus_socket_commit_properties,
diff --git a/src/libcore/socket.h b/src/libcore/socket.h
index b537b026a7..0f1ac69c6f 100644
--- a/src/libcore/socket.h
+++ b/src/libcore/socket.h
@@ -52,6 +52,8 @@ typedef enum SocketResult {
SOCKET_FAILURE_EXIT_CODE,
SOCKET_FAILURE_SIGNAL,
SOCKET_FAILURE_CORE_DUMP,
+ SOCKET_FAILURE_START_LIMIT_HIT,
+ SOCKET_FAILURE_TRIGGER_LIMIT_HIT,
SOCKET_FAILURE_SERVICE_START_LIMIT_HIT,
_SOCKET_RESULT_MAX,
_SOCKET_RESULT_INVALID = -1
@@ -156,6 +158,8 @@ struct Socket {
bool reset_cpu_usage:1;
char *fdname;
+
+ RateLimit trigger_limit;
};
/* Called from the service code when collecting fds */
diff --git a/src/libcore/swap.c b/src/libcore/swap.c
index 1bf0c0a808..a532b15be8 100644
--- a/src/libcore/swap.c
+++ b/src/libcore/swap.c
@@ -198,7 +198,7 @@ static int swap_add_device_links(Swap *s) {
return 0;
if (is_device_path(s->what))
- return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM, UNIT_BINDS_TO);
+ return unit_add_node_link(UNIT(s), s->what, MANAGER_IS_SYSTEM(UNIT(s)->manager), UNIT_BINDS_TO);
else
/* File based swap devices need to be ordered after
* systemd-remount-fs.service, since they might need a
@@ -214,7 +214,7 @@ static int swap_add_default_dependencies(Swap *s) {
if (!UNIT(s)->default_dependencies)
return 0;
- if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
return 0;
if (detect_container() > 0)
@@ -609,7 +609,6 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
.apply_permissions = true,
.apply_chroot = true,
.apply_tty_stdin = true,
- .bus_endpoint_fd = -1,
.stdin_fd = -1,
.stdout_fd = -1,
.stderr_fd = -1,
@@ -815,6 +814,7 @@ fail:
static int swap_start(Unit *u) {
Swap *s = SWAP(u), *other;
+ int r;
assert(s);
@@ -843,6 +843,12 @@ static int swap_start(Unit *u) {
if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
return -EAGAIN;
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
s->result = SWAP_SUCCESS;
s->reset_cpu_usage = true;
@@ -1427,6 +1433,14 @@ static bool swap_supported(void) {
return supported;
}
+static int swap_control_pid(Unit *u) {
+ Swap *s = SWAP(u);
+
+ assert(s);
+
+ return s->control_pid;
+}
+
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
[SWAP_EXEC_ACTIVATE] = "ExecActivate",
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
@@ -1440,7 +1454,8 @@ static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
[SWAP_FAILURE_TIMEOUT] = "timeout",
[SWAP_FAILURE_EXIT_CODE] = "exit-code",
[SWAP_FAILURE_SIGNAL] = "signal",
- [SWAP_FAILURE_CORE_DUMP] = "core-dump"
+ [SWAP_FAILURE_CORE_DUMP] = "core-dump",
+ [SWAP_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
@@ -1458,9 +1473,6 @@ const UnitVTable swap_vtable = {
"Install\0",
.private_section = "Swap",
- .no_alias = true,
- .no_instances = true,
-
.init = swap_init,
.load = swap_load,
.done = swap_done,
@@ -1488,6 +1500,8 @@ const UnitVTable swap_vtable = {
.reset_failed = swap_reset_failed,
+ .control_pid = swap_control_pid,
+
.bus_vtable = bus_swap_vtable,
.bus_set_property = bus_swap_set_property,
.bus_commit_properties = bus_swap_commit_properties,
diff --git a/src/libcore/swap.h b/src/libcore/swap.h
index ac7a63d81b..fbf66debdc 100644
--- a/src/libcore/swap.h
+++ b/src/libcore/swap.h
@@ -38,6 +38,7 @@ typedef enum SwapResult {
SWAP_FAILURE_EXIT_CODE,
SWAP_FAILURE_SIGNAL,
SWAP_FAILURE_CORE_DUMP,
+ SWAP_FAILURE_START_LIMIT_HIT,
_SWAP_RESULT_MAX,
_SWAP_RESULT_INVALID = -1
} SwapResult;
diff --git a/src/libcore/timer.c b/src/libcore/timer.c
index 3d0bae16e5..3206296f09 100644
--- a/src/libcore/timer.c
+++ b/src/libcore/timer.c
@@ -109,7 +109,7 @@ static int timer_add_default_dependencies(Timer *t) {
if (r < 0)
return r;
- if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
@@ -135,7 +135,7 @@ static int timer_setup_persistent(Timer *t) {
if (!t->persistent)
return 0;
- if (UNIT(t)->manager->running_as == MANAGER_SYSTEM) {
+ if (MANAGER_IS_SYSTEM(UNIT(t)->manager)) {
r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
if (r < 0)
@@ -320,7 +320,7 @@ static usec_t monotonic_to_boottime(usec_t t) {
if (t <= 0)
return 0;
- a = now(CLOCK_BOOTTIME);
+ a = now(clock_boottime_or_monotonic());
b = now(CLOCK_MONOTONIC);
if (t + a > b)
@@ -373,7 +373,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
* rather than the monotonic clock. */
ts_realtime = now(CLOCK_REALTIME);
- ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
+ ts_monotonic = now(t->wake_system ? clock_boottime_or_monotonic() : CLOCK_MONOTONIC);
t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
LIST_FOREACH(value, v, t->values) {
@@ -599,6 +599,7 @@ static int timer_start(Unit *u) {
Timer *t = TIMER(u);
TimerValue *v;
Unit *trigger;
+ int r;
assert(t);
assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
@@ -609,6 +610,12 @@ static int timer_start(Unit *u) {
return -ENOENT;
}
+ r = unit_start_limit_test(u);
+ if (r < 0) {
+ timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
+ return r;
+ }
+
t->last_trigger = DUAL_TIMESTAMP_NULL;
/* Reenable all timers that depend on unit activation time */
@@ -808,7 +815,8 @@ DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
[TIMER_SUCCESS] = "success",
- [TIMER_FAILURE_RESOURCES] = "resources"
+ [TIMER_FAILURE_RESOURCES] = "resources",
+ [TIMER_FAILURE_START_LIMIT_HIT] = "start-limit-hit",
};
DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
diff --git a/src/libcore/timer.h b/src/libcore/timer.h
index 698e6da2f5..9c4b64f898 100644
--- a/src/libcore/timer.h
+++ b/src/libcore/timer.h
@@ -48,6 +48,7 @@ typedef struct TimerValue {
typedef enum TimerResult {
TIMER_SUCCESS,
TIMER_FAILURE_RESOURCES,
+ TIMER_FAILURE_START_LIMIT_HIT,
_TIMER_RESULT_MAX,
_TIMER_RESULT_INVALID = -1
} TimerResult;
diff --git a/src/libcore/transaction.c b/src/libcore/transaction.c
index b28fc76785..e06a48a2f1 100644
--- a/src/libcore/transaction.c
+++ b/src/libcore/transaction.c
@@ -391,6 +391,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
if (delete) {
+ const char *status;
/* logging for j not k here here to provide consistent narrative */
log_unit_warning(j->unit,
"Breaking ordering cycle by deleting job %s/%s",
@@ -399,7 +400,13 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
"Job %s/%s deleted to break ordering cycle starting with %s/%s",
delete->unit->id, job_type_to_string(delete->type),
j->unit->id, job_type_to_string(j->type));
- unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL,
+
+ if (log_get_show_color())
+ status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL;
+ else
+ status = " SKIP ";
+
+ unit_status_printf(delete->unit, status,
"Ordering cycle found, skipping %s");
transaction_delete_unit(tr, delete->unit);
return -EAGAIN;
@@ -590,7 +597,7 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
/* Not invalidating recursively. Avoids triggering
* OnFailure= actions of dependent jobs. Also avoids
* invalidating our iterator. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
+ job_finish_and_invalidate(j, JOB_CANCELED, false, false);
}
}
@@ -848,7 +855,7 @@ int transaction_add_job_and_dependencies(
* This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
* This way, we "recursively" coldplug units, ensuring that we do not look at state of
* not-yet-coldplugged units. */
- if (unit->manager->n_reloading > 0)
+ if (MANAGER_IS_RELOADING(unit->manager))
unit_coldplug(unit);
/* log_debug("Pulling in %s/%s from %s/%s", */
@@ -932,7 +939,7 @@ int transaction_add_job_and_dependencies(
if (r < 0) {
/* unit masked, job type not applicable and unit not found are not considered as errors. */
log_unit_full(dep,
- IN_SET(r, -ESHUTDOWN, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
+ IN_SET(r, -ERFKILL, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
r, "Cannot add dependency job, ignoring: %s",
bus_error_message(e, r));
sd_bus_error_free(e);
diff --git a/src/libcore/umount.c b/src/libcore/umount.c
index a458768e7d..c21a2be54e 100644
--- a/src/libcore/umount.c
+++ b/src/libcore/umount.c
@@ -412,6 +412,7 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
#ifndef HAVE_SPLIT_USR
|| path_equal(m->path, "/usr")
#endif
+ || path_startswith(m->path, "/run/initramfs")
)
continue;
@@ -472,7 +473,7 @@ static int loopback_points_list_detach(MountPoint **head, bool *changed) {
major(root_st.st_dev) != 0 &&
lstat(m->path, &loopback_st) >= 0 &&
root_st.st_dev == loopback_st.st_rdev) {
- n_failed ++;
+ n_failed++;
continue;
}
@@ -507,7 +508,7 @@ static int dm_points_list_detach(MountPoint **head, bool *changed) {
if (k >= 0 &&
major(root_st.st_dev) != 0 &&
root_st.st_dev == m->devnum) {
- n_failed ++;
+ n_failed++;
continue;
}
diff --git a/src/libcore/unit-printf.c b/src/libcore/unit-printf.c
index fc057d965c..f11df42af3 100644
--- a/src/libcore/unit-printf.c
+++ b/src/libcore/unit-printf.c
@@ -140,14 +140,9 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char **
assert(u);
- if (u->manager->running_as == MANAGER_SYSTEM)
- e = "/run";
- else {
- e = getenv("XDG_RUNTIME_DIR");
- if (!e)
- return -EOPNOTSUPP;
- }
-
+ e = manager_get_runtime_prefix(u->manager);
+ if (!e)
+ return -EOPNOTSUPP;
n = strdup(e);
if (!n)
return -ENOMEM;
diff --git a/src/libcore/unit.c b/src/libcore/unit.c
index 4f7c0e2449..8bd39f87f9 100644
--- a/src/libcore/unit.c
+++ b/src/libcore/unit.c
@@ -47,11 +47,13 @@
#include "path-util.h"
#include "process-util.h"
#include "set.h"
+#include "signal-util.h"
#include "special.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
+#include "umask-util.h"
#include "unit-name.h"
#include "unit.h"
#include "user-util.h"
@@ -130,6 +132,7 @@ static void unit_init(Unit *u) {
* been initialized */
cc->cpu_accounting = u->manager->default_cpu_accounting;
+ cc->io_accounting = u->manager->default_io_accounting;
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
cc->tasks_accounting = u->manager->default_tasks_accounting;
@@ -191,7 +194,7 @@ int unit_add_name(Unit *u, const char *text) {
if (r < 0)
return r;
- if (i && unit_vtable[t]->no_instances)
+ if (i && !unit_type_may_template(t))
return -EINVAL;
/* Ensure that this unit is either instanced or not instanced,
@@ -200,7 +203,7 @@ int unit_add_name(Unit *u, const char *text) {
if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
return -EINVAL;
- if (unit_vtable[t]->no_alias && !set_isempty(u->names))
+ if (!unit_type_may_alias(t) && !set_isempty(u->names))
return -EEXIST;
if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
@@ -364,7 +367,7 @@ void unit_add_to_gc_queue(Unit *u) {
LIST_PREPEND(gc_queue, u->manager->gc_queue, u);
u->in_gc_queue = true;
- u->manager->n_in_gc_queue ++;
+ u->manager->n_in_gc_queue++;
}
void unit_add_to_dbus_queue(Unit *u) {
@@ -418,13 +421,22 @@ static void unit_remove_transient(Unit *u) {
(void) unlink(u->fragment_path);
STRV_FOREACH(i, u->dropin_paths) {
- _cleanup_free_ char *p = NULL;
+ _cleanup_free_ char *p = NULL, *pp = NULL;
- (void) unlink(*i);
+ p = dirname_malloc(*i); /* Get the drop-in directory from the drop-in file */
+ if (!p)
+ continue;
+
+ pp = dirname_malloc(p); /* Get the config directory from the drop-in directory */
+ if (!pp)
+ continue;
- p = dirname_malloc(*i);
- if (p)
- (void) rmdir(p);
+ /* Only drop transient drop-ins */
+ if (!path_equal(u->manager->lookup_paths.transient, pp))
+ continue;
+
+ (void) unlink(*i);
+ (void) rmdir(p);
}
}
@@ -483,7 +495,10 @@ void unit_free(Unit *u) {
assert(u);
- if (u->manager->n_reloading <= 0)
+ if (u->transient_file)
+ fclose(u->transient_file);
+
+ if (!MANAGER_IS_RELOADING(u->manager))
unit_remove_transient(u);
bus_unit_send_removed_signal(u);
@@ -706,6 +721,9 @@ int unit_merge(Unit *u, Unit *other) {
if (!u->instance != !other->instance)
return -EINVAL;
+ if (!unit_type_may_alias(u->type)) /* Merging only applies to unit names that support aliases */
+ return -EEXIST;
+
if (other->load_state != UNIT_STUB &&
other->load_state != UNIT_NOT_FOUND)
return -EEXIST;
@@ -762,9 +780,9 @@ int unit_merge(Unit *u, Unit *other) {
}
int unit_merge_by_name(Unit *u, const char *name) {
+ _cleanup_free_ char *s = NULL;
Unit *other;
int r;
- _cleanup_free_ char *s = NULL;
assert(u);
assert(name);
@@ -814,7 +832,7 @@ int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
return r;
}
- if (u->manager->running_as != MANAGER_SYSTEM)
+ if (!MANAGER_IS_SYSTEM(u->manager))
return 0;
if (c->private_tmp) {
@@ -888,7 +906,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
"%s\tInstance: %s\n"
"%s\tUnit Load State: %s\n"
"%s\tUnit Active State: %s\n"
- "%s\nState Change Timestamp: %s\n"
+ "%s\tState Change Timestamp: %s\n"
"%s\tInactive Exit Timestamp: %s\n"
"%s\tActive Enter Timestamp: %s\n"
"%s\tActive Exit Timestamp: %s\n"
@@ -1196,6 +1214,7 @@ static int unit_add_startup_units(Unit *u) {
return 0;
if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID &&
+ c->startup_io_weight == CGROUP_WEIGHT_INVALID &&
c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID)
return 0;
@@ -1222,6 +1241,17 @@ int unit_load(Unit *u) {
if (u->load_state != UNIT_STUB)
return 0;
+ if (u->transient_file) {
+ r = fflush_and_check(u->transient_file);
+ if (r < 0)
+ goto fail;
+
+ fclose(u->transient_file);
+ u->transient_file = NULL;
+
+ u->fragment_mtime = now(CLOCK_REALTIME);
+ }
+
if (UNIT_VTABLE(u)->load) {
r = UNIT_VTABLE(u)->load(u);
if (r < 0)
@@ -1434,7 +1464,7 @@ void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
unit_status_print_starting_stopping(u, t);
}
-static int unit_start_limit_test(Unit *u) {
+int unit_start_limit_test(Unit *u) {
assert(u);
if (ratelimit_test(&u->start_limit)) {
@@ -1460,7 +1490,6 @@ static int unit_start_limit_test(Unit *u) {
int unit_start(Unit *u) {
UnitActiveState state;
Unit *following;
- int r;
assert(u);
@@ -1472,11 +1501,6 @@ int unit_start(Unit *u) {
if (UNIT_IS_ACTIVE_OR_RELOADING(state))
return -EALREADY;
- /* Make sure we don't enter a busy loop of some kind. */
- r = unit_start_limit_test(u);
- if (r < 0)
- return r;
-
/* Units that aren't loaded cannot be started */
if (u->load_state != UNIT_LOADED)
return -EINVAL;
@@ -1834,7 +1858,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
m = u->manager;
/* Update timestamps for state changes */
- if (m->n_reloading <= 0) {
+ if (!MANAGER_IS_RELOADING(m)) {
dual_timestamp_get(&u->state_change_timestamp);
if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
@@ -1864,13 +1888,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
ec = unit_get_exec_context(u);
if (ec && exec_context_may_touch_console(ec)) {
if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
- m->n_on_console --;
+ m->n_on_console--;
if (m->n_on_console == 0)
/* unset no_console_output flag, since the console is free */
m->no_console_output = false;
} else
- m->n_on_console ++;
+ m->n_on_console++;
}
}
@@ -1894,12 +1918,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_VERIFY_ACTIVE:
if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
+ job_finish_and_invalidate(u->job, JOB_DONE, true, false);
else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
}
break;
@@ -1910,12 +1934,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true);
+ job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true, false);
else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
+ job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true, false);
}
}
@@ -1926,10 +1950,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_TRY_RESTART:
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
+ job_finish_and_invalidate(u->job, JOB_DONE, true, false);
else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
unexpected = true;
- job_finish_and_invalidate(u->job, JOB_FAILED, true);
+ job_finish_and_invalidate(u->job, JOB_FAILED, true, false);
}
break;
@@ -1941,7 +1965,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
} else
unexpected = true;
- if (m->n_reloading <= 0) {
+ if (!MANAGER_IS_RELOADING(m)) {
/* If this state change happened without being
* requested by a job, then let's retroactively start
@@ -1978,7 +2002,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->type == UNIT_SERVICE &&
!UNIT_IS_ACTIVE_OR_RELOADING(os) &&
- m->n_reloading <= 0) {
+ !MANAGER_IS_RELOADING(m)) {
/* Write audit record if we have just finished starting up */
manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true);
u->in_audit = true;
@@ -1995,7 +2019,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->type == UNIT_SERVICE &&
UNIT_IS_INACTIVE_OR_FAILED(ns) &&
!UNIT_IS_INACTIVE_OR_FAILED(os) &&
- m->n_reloading <= 0) {
+ !MANAGER_IS_RELOADING(m)) {
/* Hmm, if there was no start record written
* write it now, so that we always have a nice
@@ -2016,7 +2040,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
manager_recheck_journal(m);
unit_trigger_notify(u);
- if (u->manager->n_reloading <= 0) {
+ if (!MANAGER_IS_RELOADING(u->manager)) {
/* Maybe we finished startup and are now ready for
* being stopped because unneeded? */
unit_check_unneeded(u);
@@ -2378,9 +2402,11 @@ int unit_set_slice(Unit *u, Unit *slice) {
if (UNIT_DEREF(u->slice) == slice)
return 0;
- if (UNIT_ISSET(u->slice))
+ /* Disallow slice changes if @u is already bound to cgroups */
+ if (UNIT_ISSET(u->slice) && u->cgroup_realized)
return -EBUSY;
+ unit_ref_unset(&u->slice);
unit_ref_set(&u->slice, slice);
return 1;
}
@@ -2413,7 +2439,7 @@ int unit_set_default_slice(Unit *u) {
if (!escaped)
return -ENOMEM;
- if (u->manager->running_as == MANAGER_SYSTEM)
+ if (MANAGER_IS_SYSTEM(u->manager))
b = strjoin("system-", escaped, ".slice", NULL);
else
b = strappend(escaped, ".slice");
@@ -2423,7 +2449,7 @@ int unit_set_default_slice(Unit *u) {
slice_name = b;
} else
slice_name =
- u->manager->running_as == MANAGER_SYSTEM && !unit_has_name(u, SPECIAL_INIT_SCOPE)
+ MANAGER_IS_SYSTEM(u->manager) && !unit_has_name(u, SPECIAL_INIT_SCOPE)
? SPECIAL_SYSTEM_SLICE
: SPECIAL_ROOT_SLICE;
@@ -2493,12 +2519,11 @@ int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
return -EBUSY;
match = strjoina("type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged',"
- "arg0='", name, "'",
- NULL);
+ "sender='org.freedesktop.DBus',"
+ "path='/org/freedesktop/DBus',"
+ "interface='org.freedesktop.DBus',"
+ "member='NameOwnerChanged',"
+ "arg0='", name, "'");
return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
}
@@ -2884,7 +2909,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep
return r;
r = unit_add_two_dependencies(u, UNIT_AFTER,
- u->manager->running_as == MANAGER_SYSTEM ? dep : UNIT_WANTS,
+ MANAGER_IS_SYSTEM(u->manager) ? dep : UNIT_WANTS,
device, true);
if (r < 0)
return r;
@@ -2924,59 +2949,47 @@ int unit_coldplug(Unit *u) {
return 0;
}
-bool unit_need_daemon_reload(Unit *u) {
- _cleanup_strv_free_ char **t = NULL;
- char **path;
+static bool fragment_mtime_newer(const char *path, usec_t mtime) {
struct stat st;
- unsigned loaded_cnt, current_cnt;
- assert(u);
+ if (!path)
+ return false;
- if (u->fragment_path) {
- zero(st);
- if (stat(u->fragment_path, &st) < 0)
- /* What, cannot access this anymore? */
- return true;
+ if (stat(path, &st) < 0)
+ /* What, cannot access this anymore? */
+ return true;
- if (u->fragment_mtime > 0 &&
- timespec_load(&st.st_mtim) != u->fragment_mtime)
- return true;
- }
+ if (mtime > 0)
+ /* For non-empty files check the mtime */
+ return timespec_load(&st.st_mtim) > mtime;
+ else if (!null_or_empty(&st))
+ /* For masked files check if they are still so */
+ return true;
- if (u->source_path) {
- zero(st);
- if (stat(u->source_path, &st) < 0)
- return true;
+ return false;
+}
- if (u->source_mtime > 0 &&
- timespec_load(&st.st_mtim) != u->source_mtime)
- return true;
- }
+bool unit_need_daemon_reload(Unit *u) {
+ _cleanup_strv_free_ char **t = NULL;
+ char **path;
- (void) unit_find_dropin_paths(u, &t);
- loaded_cnt = strv_length(t);
- current_cnt = strv_length(u->dropin_paths);
+ assert(u);
- if (loaded_cnt == current_cnt) {
- if (loaded_cnt == 0)
- return false;
+ if (fragment_mtime_newer(u->fragment_path, u->fragment_mtime))
+ return true;
- if (strv_overlap(u->dropin_paths, t)) {
- STRV_FOREACH(path, u->dropin_paths) {
- zero(st);
- if (stat(*path, &st) < 0)
- return true;
+ if (fragment_mtime_newer(u->source_path, u->source_mtime))
+ return true;
- if (u->dropin_mtime > 0 &&
- timespec_load(&st.st_mtim) > u->dropin_mtime)
- return true;
- }
+ (void) unit_find_dropin_paths(u, &t);
+ if (!strv_equal(u->dropin_paths, t))
+ return true;
- return false;
- } else
+ STRV_FOREACH(path, u->dropin_paths)
+ if (fragment_mtime_newer(*path, u->dropin_mtime))
return true;
- } else
- return true;
+
+ return false;
}
void unit_reset_failed(Unit *u) {
@@ -3044,8 +3057,7 @@ bool unit_active_or_pending(Unit *u) {
int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
assert(u);
assert(w >= 0 && w < _KILL_WHO_MAX);
- assert(signo > 0);
- assert(signo < _NSIG);
+ assert(SIGNAL_VALID(signo));
if (!UNIT_VTABLE(u)->kill)
return -EOPNOTSUPP;
@@ -3162,7 +3174,7 @@ UnitFileState unit_get_unit_file_state(Unit *u) {
if (u->unit_file_state < 0 && u->fragment_path) {
r = unit_file_get_state(
- u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+ u->manager->unit_file_scope,
NULL,
basename(u->fragment_path),
&u->unit_file_state);
@@ -3178,7 +3190,7 @@ int unit_get_unit_file_preset(Unit *u) {
if (u->unit_file_preset < 0 && u->fragment_path)
u->unit_file_preset = unit_file_query_preset(
- u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
+ u->manager->unit_file_scope,
NULL,
basename(u->fragment_path));
@@ -3203,6 +3215,10 @@ void unit_ref_unset(UnitRef *ref) {
if (!ref->unit)
return;
+ /* We are about to drop a reference to the unit, make sure the garbage collection has a look at it as it might
+ * be unreferenced now. */
+ unit_add_to_gc_queue(ref->unit);
+
LIST_REMOVE(refs, ref->unit->refs, ref);
ref->unit = NULL;
}
@@ -3229,7 +3245,7 @@ int unit_patch_contexts(Unit *u) {
return -ENOMEM;
}
- if (u->manager->running_as == MANAGER_USER &&
+ if (MANAGER_IS_USER(u->manager) &&
!ec->working_directory) {
r = get_home_dir(&ec->working_directory);
@@ -3241,7 +3257,7 @@ int unit_patch_contexts(Unit *u) {
ec->working_directory_missing_ok = true;
}
- if (u->manager->running_as == MANAGER_USER &&
+ if (MANAGER_IS_USER(u->manager) &&
(ec->syscall_whitelist ||
!set_isempty(ec->syscall_filter) ||
!set_isempty(ec->syscall_archs) ||
@@ -3319,59 +3335,62 @@ ExecRuntime *unit_get_exec_runtime(Unit *u) {
return *(ExecRuntime**) ((uint8_t*) u + offset);
}
-static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) {
+static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) {
assert(u);
- if (u->manager->running_as == MANAGER_USER) {
- int r;
+ if (!IN_SET(mode, UNIT_RUNTIME, UNIT_PERSISTENT))
+ return NULL;
- if (mode == UNIT_PERSISTENT && !transient)
- r = user_config_home(dir);
- else
- r = user_runtime_dir(dir);
- if (r == 0)
- return -ENOENT;
+ if (u->transient) /* Redirect drop-ins for transient units always into the transient directory. */
+ return u->manager->lookup_paths.transient;
- return r;
- }
+ if (mode == UNIT_RUNTIME)
+ return u->manager->lookup_paths.runtime_control;
- if (mode == UNIT_PERSISTENT && !transient)
- *dir = strdup("/etc/systemd/system");
- else
- *dir = strdup("/run/systemd/system");
- if (!*dir)
- return -ENOMEM;
+ if (mode == UNIT_PERSISTENT)
+ return u->manager->lookup_paths.persistent_control;
- return 0;
+ return NULL;
}
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
-
- _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
+ _cleanup_free_ char *p = NULL, *q = NULL;
+ const char *dir, *prefixed;
int r;
assert(u);
+ if (u->transient_file) {
+ /* When this is a transient unit file in creation, then let's not create a new drop-in but instead
+ * write to the transient unit file. */
+ fputs(data, u->transient_file);
+ return 0;
+ }
+
if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
return 0;
- r = unit_drop_in_dir(u, mode, u->transient, &dir);
- if (r < 0)
- return r;
+ dir = unit_drop_in_dir(u, mode);
+ if (!dir)
+ return -EINVAL;
+
+ prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n",
+ data);
- r = write_drop_in(dir, u->id, 50, name, data);
+ r = drop_in_file(dir, u->id, 50, name, &p, &q);
if (r < 0)
return r;
- r = drop_in_file(dir, u->id, 50, name, &p, &q);
+ (void) mkdir_p(p, 0755);
+ r = write_string_file_atomic_label(q, prefixed);
if (r < 0)
return r;
- r = strv_extend(&u->dropin_paths, q);
+ r = strv_push(&u->dropin_paths, q);
if (r < 0)
return r;
+ q = NULL;
- strv_sort(u->dropin_paths);
strv_uniq(u->dropin_paths);
u->dropin_mtime = now(CLOCK_REALTIME);
@@ -3402,7 +3421,7 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n
}
int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
- _cleanup_free_ char *ndata = NULL;
+ const char *ndata;
assert(u);
assert(name);
@@ -3414,9 +3433,7 @@ int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *
if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
return 0;
- ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
- if (!ndata)
- return -ENOMEM;
+ ndata = strjoina("[", UNIT_VTABLE(u)->private_section, "]\n", data);
return unit_write_drop_in(u, mode, name, ndata);
}
@@ -3444,24 +3461,51 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
}
int unit_make_transient(Unit *u) {
+ FILE *f;
+ char *path;
+
assert(u);
if (!UNIT_VTABLE(u)->can_transient)
return -EOPNOTSUPP;
- u->load_state = UNIT_STUB;
- u->load_error = 0;
- u->transient = true;
+ path = strjoin(u->manager->lookup_paths.transient, "/", u->id, NULL);
+ if (!path)
+ return -ENOMEM;
+
+ /* Let's open the file we'll write the transient settings into. This file is kept open as long as we are
+ * creating the transient, and is closed in unit_load(), as soon as we start loading the file. */
+
+ RUN_WITH_UMASK(0022) {
+ f = fopen(path, "we");
+ if (!f) {
+ free(path);
+ return -errno;
+ }
+ }
+
+ if (u->transient_file)
+ fclose(u->transient_file);
+ u->transient_file = f;
+
+ free(u->fragment_path);
+ u->fragment_path = path;
- u->fragment_path = mfree(u->fragment_path);
u->source_path = mfree(u->source_path);
u->dropin_paths = strv_free(u->dropin_paths);
u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
+ u->load_state = UNIT_STUB;
+ u->load_error = 0;
+ u->transient = true;
+
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
unit_add_to_load_queue(u);
+ fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n",
+ u->transient_file);
+
return 0;
}
@@ -3553,7 +3597,7 @@ int unit_kill_context(
* cases. It doesn't work at all in
* containers, and outside of containers it
* can be confused easily by left-over
- * directories in the cgroup -- which however
+ * directories in the cgroup — which however
* should not exist in non-delegated units. On
* the unified hierarchy that's different,
* there we get proper events. Hence rely on
@@ -3754,3 +3798,21 @@ bool unit_is_pristine(Unit *u) {
u->job ||
u->merged_into);
}
+
+pid_t unit_control_pid(Unit *u) {
+ assert(u);
+
+ if (UNIT_VTABLE(u)->control_pid)
+ return UNIT_VTABLE(u)->control_pid(u);
+
+ return 0;
+}
+
+pid_t unit_main_pid(Unit *u) {
+ assert(u);
+
+ if (UNIT_VTABLE(u)->main_pid)
+ return UNIT_VTABLE(u)->main_pid(u);
+
+ return 0;
+}
diff --git a/src/libcore/unit.h b/src/libcore/unit.h
index 601e763ce2..08a927962d 100644
--- a/src/libcore/unit.h
+++ b/src/libcore/unit.h
@@ -95,6 +95,9 @@ struct Unit {
usec_t source_mtime;
usec_t dropin_mtime;
+ /* If this is a transient unit we are currently writing, this is where we are writing it to */
+ FILE *transient_file;
+
/* If there is something to do with this unit, then this is the installed job for it */
Job *job;
@@ -183,6 +186,7 @@ struct Unit {
/* Counterparts in the cgroup filesystem */
char *cgroup_path;
CGroupMask cgroup_realized_mask;
+ CGroupMask cgroup_enabled_mask;
CGroupMask cgroup_subtree_mask;
CGroupMask cgroup_members_mask;
int cgroup_inotify_wd;
@@ -387,6 +391,12 @@ struct UnitVTable {
/* Returns the next timeout of a unit */
int (*get_timeout)(Unit *u, usec_t *timeout);
+ /* Returns the main PID if there is any defined, or 0. */
+ pid_t (*main_pid)(Unit *u);
+
+ /* Returns the main PID if there is any defined, or 0. */
+ pid_t (*control_pid)(Unit *u);
+
/* This is called for each unit type and should be used to
* enumerate existing devices and load them. However,
* everything that is loaded here should still stay in
@@ -407,12 +417,6 @@ struct UnitVTable {
/* The strings to print in status messages */
UnitStatusMessageFormats status_message_formats;
- /* Can units of this type have multiple names? */
- bool no_alias:1;
-
- /* Instances make no sense for this type */
- bool no_instances:1;
-
/* True if transient units of this type are OK */
bool can_transient:1;
};
@@ -598,6 +602,9 @@ bool unit_type_supported(UnitType t);
bool unit_is_pristine(Unit *u);
+pid_t unit_control_pid(Unit *u);
+pid_t unit_main_pid(Unit *u);
+
static inline bool unit_supported(Unit *u) {
return unit_type_supported(u->type);
}
@@ -605,6 +612,8 @@ 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);
+int unit_start_limit_test(Unit *u);
+
/* Macros which append UNIT= or USER_UNIT= to the message */
#define log_unit_full(unit, level, error, ...) \
diff --git a/src/libfirewall/firewall-util.c b/src/libfirewall/firewall-util.c
index 0d3da2e6d2..f73108eaa3 100644
--- a/src/libfirewall/firewall-util.c
+++ b/src/libfirewall/firewall-util.c
@@ -17,14 +17,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#warning "Temporary work-around for broken glibc vs. linux kernel header definitions"
+#warning "This really should be removed sooner rather than later, when this is fixed upstream"
+#define _NET_IF_H 1
+
#include <alloca.h>
#include <arpa/inet.h>
#include <endian.h>
#include <errno.h>
-#include <net/if.h>
#include <stddef.h>
#include <string.h>
#include <sys/socket.h>
+#include <net/if.h>
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#include <linux/if.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter/xt_addrtype.h>
@@ -34,6 +42,7 @@
#include "firewall-util.h"
#include "in-addr-util.h"
#include "macro.h"
+#include "socket-util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free);
@@ -49,10 +58,9 @@ static int entry_fill_basics(
assert(entry);
- if (out_interface && strlen(out_interface) >= IFNAMSIZ)
+ if (out_interface && !ifname_valid(out_interface))
return -EINVAL;
-
- if (in_interface && strlen(in_interface) >= IFNAMSIZ)
+ if (in_interface && !ifname_valid(in_interface))
return -EINVAL;
entry->ip.proto = protocol;
diff --git a/src/libshared/Makefile b/src/libshared/Makefile
index 6d2117a77d..67a19f4e21 100644
--- a/src/libshared/Makefile
+++ b/src/libshared/Makefile
@@ -28,14 +28,13 @@ noinst_LTLIBRARIES += \
libshared_la_SOURCES = \
src/shared/output-mode.h \
+ src/shared/output-mode.c \
src/shared/gpt.h \
src/shared/udev-util.h \
src/shared/linux/auto_dev-ioctl.h \
src/shared/initreq.h \
src/shared/dns-domain.c \
src/shared/dns-domain.h \
- src/shared/architecture.c \
- src/shared/architecture.h \
src/shared/efivars.c \
src/shared/efivars.h \
src/shared/fstab-util.c \
@@ -104,7 +103,11 @@ libshared_la_SOURCES = \
src/shared/machine-pool.c \
src/shared/machine-pool.h \
src/shared/resolve-util.c \
- src/shared/resolve-util.h
+ src/shared/resolve-util.h \
+ src/shared/bus-unit-util.c \
+ src/shared/bus-unit-util.h \
+ src/shared/tests.h \
+ src/shared/tests.c
ifneq ($(HAVE_UTMP),)
libshared_la_SOURCES += \
diff --git a/src/libshared/acpi-fpdt.c b/src/libshared/acpi-fpdt.c
index 3cb9e781fd..6779691c28 100644
--- a/src/libshared/acpi-fpdt.c
+++ b/src/libshared/acpi-fpdt.c
@@ -119,7 +119,7 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) {
}
if (ptr == 0)
- return -EINVAL;
+ return -ENODATA;
/* read Firmware Basic Boot Performance Data Record */
fd = open("/dev/mem", O_CLOEXEC|O_RDONLY);
@@ -146,6 +146,10 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) {
if (brec.type != ACPI_FPDT_BOOT_REC)
return -EINVAL;
+ if (brec.exit_services_exit == 0)
+ /* Non-UEFI compatible boot. */
+ return -ENODATA;
+
if (brec.startup_start == 0 || brec.exit_services_exit < brec.startup_start)
return -EINVAL;
if (brec.exit_services_exit > NSEC_PER_HOUR)
diff --git a/src/libshared/ask-password-api.c b/src/libshared/ask-password-api.c
index 6805873f9e..4a4bd8d3b8 100644
--- a/src/libshared/ask-password-api.c
+++ b/src/libshared/ask-password-api.c
@@ -431,7 +431,7 @@ static int create_socket(char **name) {
snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64());
RUN_WITH_UMASK(0177) {
- if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (bind(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
}
diff --git a/src/libshared/bus-unit-util.c b/src/libshared/bus-unit-util.c
new file mode 100644
index 0000000000..f68c4a41ac
--- /dev/null
+++ b/src/libshared/bus-unit-util.c
@@ -0,0 +1,1307 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "bus-internal.h"
+#include "bus-unit-util.h"
+#include "bus-util.h"
+#include "cgroup-util.h"
+#include "env-util.h"
+#include "escape.h"
+#include "hashmap.h"
+#include "list.h"
+#include "locale-util.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "rlimit-util.h"
+#include "signal-util.h"
+#include "string-util.h"
+#include "syslog-util.h"
+#include "terminal-util.h"
+#include "utf8.h"
+#include "util.h"
+
+int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
+ assert(message);
+ assert(u);
+
+ u->machine = NULL;
+
+ return sd_bus_message_read(
+ message,
+ "(ssssssouso)",
+ &u->id,
+ &u->description,
+ &u->load_state,
+ &u->active_state,
+ &u->sub_state,
+ &u->following,
+ &u->unit_path,
+ &u->job_id,
+ &u->job_type,
+ &u->job_path);
+}
+
+int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
+ const char *eq, *field;
+ int r, rl;
+
+ assert(m);
+ assert(assignment);
+
+ eq = strchr(assignment, '=');
+ if (!eq) {
+ log_error("Not an assignment: %s", assignment);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ field = strndupa(assignment, eq - assignment);
+ eq++;
+
+ if (streq(field, "CPUQuota")) {
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
+ else if (endswith(eq, "%")) {
+ double percent;
+
+ if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
+ log_error("CPU quota '%s' invalid.", eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100);
+ } else {
+ log_error("CPU quota needs to be in percent.");
+ return -EINVAL;
+ }
+
+ goto finish;
+
+ } else if (streq(field, "EnvironmentFile")) {
+
+ r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
+ eq[0] == '-' ? eq + 1 : eq,
+ eq[0] == '-');
+ goto finish;
+
+ } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
+ char *n;
+ usec_t t;
+ size_t l;
+ r = parse_sec(eq, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
+
+ l = strlen(field);
+ n = newa(char, l + 2);
+ if (!n)
+ return log_oom();
+
+ /* Change suffix Sec → USec */
+ strcpy(mempcpy(n, field, l - 3), "USec");
+ r = sd_bus_message_append(m, "sv", n, "t", t);
+ goto finish;
+ }
+
+ r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ rl = rlimit_from_string(field);
+ if (rl >= 0) {
+ const char *sn;
+ struct rlimit l;
+
+ r = rlimit_parse(rl, eq, &l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resource limit: %s", eq);
+
+ r = sd_bus_message_append(m, "v", "t", l.rlim_max);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ sn = strjoina(field, "Soft");
+ r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
+
+ } else if (STR_IN_SET(field,
+ "CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", "TasksAccounting",
+ "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
+ "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
+ "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
+ "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
+
+ r = parse_boolean(eq);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment);
+
+ r = sd_bus_message_append(m, "v", "b", r);
+
+ } else if (streq(field, "MemoryLimit")) {
+ uint64_t bytes;
+
+ if (isempty(eq) || streq(eq, "infinity"))
+ bytes = (uint64_t) -1;
+ else {
+ r = parse_size(eq, 1024, &bytes);
+ if (r < 0) {
+ log_error("Failed to parse bytes specification %s", assignment);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "t", bytes);
+
+ } else if (streq(field, "TasksMax")) {
+ uint64_t n;
+
+ if (isempty(eq) || streq(eq, "infinity"))
+ n = (uint64_t) -1;
+ else {
+ r = safe_atou64(eq, &n);
+ if (r < 0) {
+ log_error("Failed to parse maximum tasks specification %s", assignment);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "t", n);
+
+ } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
+ uint64_t u;
+
+ r = cg_cpu_shares_parse(eq, &u);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", u);
+
+ } else if (STR_IN_SET(field, "IOWeight", "StartupIOWeight")) {
+ uint64_t u;
+
+ r = cg_weight_parse(eq, &u);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", u);
+
+ } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
+ uint64_t u;
+
+ r = cg_blkio_weight_parse(eq, &u);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", u);
+
+ } else if (STR_IN_SET(field,
+ "User", "Group", "DevicePolicy", "KillMode",
+ "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
+ "StandardInput", "StandardOutput", "StandardError",
+ "Description", "Slice", "Type", "WorkingDirectory",
+ "RootDirectory", "SyslogIdentifier", "ProtectSystem",
+ "ProtectHome", "SELinuxContext"))
+ r = sd_bus_message_append(m, "v", "s", eq);
+
+ else if (streq(field, "SyslogLevel")) {
+ int level;
+
+ level = log_level_from_string(eq);
+ if (level < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", level);
+
+ } else if (streq(field, "SyslogFacility")) {
+ int facility;
+
+ facility = log_facility_unshifted_from_string(eq);
+ if (facility < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", facility);
+
+ } else if (streq(field, "DeviceAllow")) {
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "v", "a(ss)", 0);
+ else {
+ const char *path, *rwm, *e;
+
+ e = strchr(eq, ' ');
+ if (e) {
+ path = strndupa(eq, e - eq);
+ rwm = e+1;
+ } else {
+ path = eq;
+ rwm = "";
+ }
+
+ if (!path_startswith(path, "/dev")) {
+ log_error("%s is not a device file in /dev.", path);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
+ }
+
+ } else if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "v", "a(st)", 0);
+ else {
+ const char *path, *bandwidth, *e;
+ uint64_t bytes;
+
+ e = strchr(eq, ' ');
+ if (e) {
+ path = strndupa(eq, e - eq);
+ bandwidth = e+1;
+ } else {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ if (!path_startswith(path, "/dev")) {
+ log_error("%s is not a device file in /dev.", path);
+ return -EINVAL;
+ }
+
+ if (streq(bandwidth, "max")) {
+ bytes = CGROUP_LIMIT_MAX;
+ } else {
+ r = parse_size(bandwidth, 1000, &bytes);
+ if (r < 0) {
+ log_error("Failed to parse byte value %s.", bandwidth);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
+ }
+
+ } else if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) {
+
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "v", "a(st)", 0);
+ else {
+ const char *path, *weight, *e;
+ uint64_t u;
+
+ e = strchr(eq, ' ');
+ if (e) {
+ path = strndupa(eq, e - eq);
+ weight = e+1;
+ } else {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ if (!path_startswith(path, "/dev")) {
+ log_error("%s is not a device file in /dev.", path);
+ return -EINVAL;
+ }
+
+ r = safe_atou64(weight, &u);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, weight);
+ return -EINVAL;
+ }
+ r = sd_bus_message_append(m, "v", "a(st)", 1, path, u);
+ }
+
+ } else if (streq(field, "Nice")) {
+ int32_t i;
+
+ r = safe_atoi32(eq, &i);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", i);
+
+ } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
+ if (r < 0) {
+ log_error("Failed to parse Environment value %s", eq);
+ return -EINVAL;
+ }
+ if (r == 0)
+ break;
+
+ if (streq(field, "Environment")) {
+ if (!env_assignment_is_valid(word)) {
+ log_error("Invalid environment assignment: %s", word);
+ return -EINVAL;
+ }
+ } else { /* PassEnvironment */
+ if (!env_name_is_valid(word)) {
+ log_error("Invalid environment variable name: %s", word);
+ return -EINVAL;
+ }
+ }
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (streq(field, "KillSignal")) {
+ int sig;
+
+ sig = signal_from_string_try_harder(eq);
+ if (sig < 0) {
+ log_error("Failed to parse %s value %s.", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", sig);
+
+ } else if (streq(field, "TimerSlackNSec")) {
+ nsec_t n;
+
+ r = parse_nsec(eq, &n);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "t", n);
+ } else if (streq(field, "OOMScoreAdjust")) {
+ int oa;
+
+ r = safe_atoi(eq, &oa);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ if (!oom_score_adjust_is_valid(oa)) {
+ log_error("OOM score adjust value out of range");
+ return -EINVAL;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", oa);
+ } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ int offset;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+ if (r == 0)
+ break;
+
+ if (!utf8_is_valid(word)) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ offset = word[0] == '-';
+ if (!path_is_absolute(word + offset)) {
+ log_error("Failed to parse %s value %s", field, eq);
+ return -EINVAL;
+ }
+
+ path_kill_slashes(word + offset);
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (streq(field, "RuntimeDirectory")) {
+ const char *p;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ p = eq;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s", field, eq);
+
+ if (r == 0)
+ break;
+
+ r = sd_bus_message_append_basic(m, 's', word);
+ if (r < 0)
+ return bus_log_create_error(r);
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else {
+ log_error("Unknown assignment %s.", assignment);
+ return -EINVAL;
+ }
+
+finish:
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ return 0;
+}
+
+typedef struct BusWaitForJobs {
+ sd_bus *bus;
+ Set *jobs;
+
+ char *name;
+ char *result;
+
+ sd_bus_slot *slot_job_removed;
+ sd_bus_slot *slot_disconnected;
+} BusWaitForJobs;
+
+static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ assert(m);
+
+ log_error("Warning! D-Bus connection terminated.");
+ sd_bus_close(sd_bus_message_get_bus(m));
+
+ return 0;
+}
+
+static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ const char *path, *unit, *result;
+ BusWaitForJobs *d = userdata;
+ uint32_t id;
+ char *found;
+ int r;
+
+ assert(m);
+ assert(d);
+
+ r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
+ if (r < 0) {
+ bus_log_parse_error(r);
+ return 0;
+ }
+
+ found = set_remove(d->jobs, (char*) path);
+ if (!found)
+ return 0;
+
+ free(found);
+
+ if (!isempty(result))
+ d->result = strdup(result);
+
+ if (!isempty(unit))
+ d->name = strdup(unit);
+
+ return 0;
+}
+
+void bus_wait_for_jobs_free(BusWaitForJobs *d) {
+ if (!d)
+ return;
+
+ set_free_free(d->jobs);
+
+ sd_bus_slot_unref(d->slot_disconnected);
+ sd_bus_slot_unref(d->slot_job_removed);
+
+ sd_bus_unref(d->bus);
+
+ free(d->name);
+ free(d->result);
+
+ free(d);
+}
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
+ _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
+ int r;
+
+ assert(bus);
+ assert(ret);
+
+ d = new0(BusWaitForJobs, 1);
+ if (!d)
+ return -ENOMEM;
+
+ d->bus = sd_bus_ref(bus);
+
+ /* When we are a bus client we match by sender. Direct
+ * connections OTOH have no initialized sender field, and
+ * hence we ignore the sender then */
+ r = sd_bus_add_match(
+ bus,
+ &d->slot_job_removed,
+ bus->bus_client ?
+ "type='signal',"
+ "sender='org.freedesktop.systemd1',"
+ "interface='org.freedesktop.systemd1.Manager',"
+ "member='JobRemoved',"
+ "path='/org/freedesktop/systemd1'" :
+ "type='signal',"
+ "interface='org.freedesktop.systemd1.Manager',"
+ "member='JobRemoved',"
+ "path='/org/freedesktop/systemd1'",
+ match_job_removed, d);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_add_match(
+ bus,
+ &d->slot_disconnected,
+ "type='signal',"
+ "sender='org.freedesktop.DBus.Local',"
+ "interface='org.freedesktop.DBus.Local',"
+ "member='Disconnected'",
+ match_disconnected, d);
+ if (r < 0)
+ return r;
+
+ *ret = d;
+ d = NULL;
+
+ return 0;
+}
+
+static int bus_process_wait(sd_bus *bus) {
+ int r;
+
+ for (;;) {
+ r = sd_bus_process(bus, NULL);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return 0;
+
+ r = sd_bus_wait(bus, (uint64_t) -1);
+ if (r < 0)
+ return r;
+ }
+}
+
+static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
+ _cleanup_free_ char *dbus_path = NULL;
+
+ assert(d);
+ assert(d->name);
+ assert(result);
+
+ dbus_path = unit_dbus_path_from_name(d->name);
+ if (!dbus_path)
+ return -ENOMEM;
+
+ return sd_bus_get_property_string(d->bus,
+ "org.freedesktop.systemd1",
+ dbus_path,
+ "org.freedesktop.systemd1.Service",
+ "Result",
+ NULL,
+ result);
+}
+
+static const struct {
+ const char *result, *explanation;
+} explanations [] = {
+ { "resources", "of unavailable resources or another system error" },
+ { "timeout", "a timeout was exceeded" },
+ { "exit-code", "the control process exited with error code" },
+ { "signal", "a fatal signal was delivered to the control process" },
+ { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
+ { "watchdog", "the service failed to send watchdog ping" },
+ { "start-limit", "start of the service was attempted too often" }
+};
+
+static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
+ _cleanup_free_ char *service_shell_quoted = NULL;
+ const char *systemctl = "systemctl", *journalctl = "journalctl";
+
+ assert(service);
+
+ service_shell_quoted = shell_maybe_quote(service);
+
+ if (extra_args && extra_args[1]) {
+ _cleanup_free_ char *t;
+
+ t = strv_join((char**) extra_args, " ");
+ systemctl = strjoina("systemctl ", t ? : "<args>");
+ journalctl = strjoina("journalctl ", t ? : "<args>");
+ }
+
+ if (!isempty(result)) {
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(explanations); ++i)
+ if (streq(result, explanations[i].result))
+ break;
+
+ if (i < ELEMENTSOF(explanations)) {
+ log_error("Job for %s failed because %s.\n"
+ "See \"%s status %s\" and \"%s -xe\" for details.\n",
+ service,
+ explanations[i].explanation,
+ systemctl,
+ service_shell_quoted ?: "<service>",
+ journalctl);
+ goto finish;
+ }
+ }
+
+ log_error("Job for %s failed.\n"
+ "See \"%s status %s\" and \"%s -xe\" for details.\n",
+ service,
+ systemctl,
+ service_shell_quoted ?: "<service>",
+ journalctl);
+
+finish:
+ /* For some results maybe additional explanation is required */
+ if (streq_ptr(result, "start-limit"))
+ log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
+ "followed by \"%1$s start %2$s\" again.",
+ systemctl,
+ service_shell_quoted ?: "<service>");
+}
+
+static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+ int r = 0;
+
+ assert(d->result);
+
+ if (!quiet) {
+ if (streq(d->result, "canceled"))
+ log_error("Job for %s canceled.", strna(d->name));
+ else if (streq(d->result, "timeout"))
+ log_error("Job for %s timed out.", strna(d->name));
+ else if (streq(d->result, "dependency"))
+ log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
+ else if (streq(d->result, "invalid"))
+ log_error("%s is not active, cannot reload.", strna(d->name));
+ else if (streq(d->result, "assert"))
+ log_error("Assertion failed on job for %s.", strna(d->name));
+ else if (streq(d->result, "unsupported"))
+ log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
+ else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
+ if (d->name) {
+ int q;
+ _cleanup_free_ char *result = NULL;
+
+ q = bus_job_get_service_result(d, &result);
+ if (q < 0)
+ log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
+
+ log_job_error_with_service_result(d->name, result, extra_args);
+ } else
+ log_error("Job failed. See \"journalctl -xe\" for details.");
+ }
+ }
+
+ if (streq(d->result, "canceled"))
+ r = -ECANCELED;
+ else if (streq(d->result, "timeout"))
+ r = -ETIME;
+ else if (streq(d->result, "dependency"))
+ r = -EIO;
+ else if (streq(d->result, "invalid"))
+ r = -ENOEXEC;
+ else if (streq(d->result, "assert"))
+ r = -EPROTO;
+ else if (streq(d->result, "unsupported"))
+ r = -EOPNOTSUPP;
+ else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
+ r = -EIO;
+
+ return r;
+}
+
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+ int r = 0;
+
+ assert(d);
+
+ while (!set_isempty(d->jobs)) {
+ int q;
+
+ q = bus_process_wait(d->bus);
+ if (q < 0)
+ return log_error_errno(q, "Failed to wait for response: %m");
+
+ if (d->result) {
+ q = check_wait_response(d, quiet, extra_args);
+ /* Return the first error as it is most likely to be
+ * meaningful. */
+ if (q < 0 && r == 0)
+ r = q;
+
+ log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
+ }
+
+ d->name = mfree(d->name);
+ d->result = mfree(d->result);
+ }
+
+ return r;
+}
+
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
+ int r;
+
+ assert(d);
+
+ r = set_ensure_allocated(&d->jobs, &string_hash_ops);
+ if (r < 0)
+ return r;
+
+ return set_put_strdup(d->jobs, path);
+}
+
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
+ int r;
+
+ r = bus_wait_for_jobs_add(d, path);
+ if (r < 0)
+ return log_oom();
+
+ return bus_wait_for_jobs(d, quiet, NULL);
+}
+
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
+ const char *type, *path, *source;
+ int r;
+
+ /* changes is dereferenced when calling unit_file_dump_changes() later,
+ * so we have to make sure this is not NULL. */
+ assert(changes);
+ assert(n_changes);
+
+ r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
+ /* We expect only "success" changes to be sent over the bus.
+ Hence, reject anything negative. */
+ UnitFileChangeType ch = unit_file_change_type_from_string(type);
+
+ if (ch < 0) {
+ log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
+ continue;
+ }
+
+ r = unit_file_changes_add(changes, n_changes, ch, path, source);
+ if (r < 0)
+ return r;
+ }
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ r = sd_bus_message_exit_container(m);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ unit_file_dump_changes(0, NULL, *changes, *n_changes, false);
+ return 0;
+}
+
+struct CGroupInfo {
+ char *cgroup_path;
+ bool is_const; /* If false, cgroup_path should be free()'d */
+
+ Hashmap *pids; /* PID → process name */
+ bool done;
+
+ struct CGroupInfo *parent;
+ LIST_FIELDS(struct CGroupInfo, siblings);
+ LIST_HEAD(struct CGroupInfo, children);
+ size_t n_children;
+};
+
+static bool IS_ROOT(const char *p) {
+ return isempty(p) || streq(p, "/");
+}
+
+static int add_cgroup(Hashmap *cgroups, const char *path, bool is_const, struct CGroupInfo **ret) {
+ struct CGroupInfo *parent = NULL, *cg;
+ int r;
+
+ assert(cgroups);
+ assert(ret);
+
+ if (IS_ROOT(path))
+ path = "/";
+
+ cg = hashmap_get(cgroups, path);
+ if (cg) {
+ *ret = cg;
+ return 0;
+ }
+
+ if (!IS_ROOT(path)) {
+ const char *e, *pp;
+
+ e = strrchr(path, '/');
+ if (!e)
+ return -EINVAL;
+
+ pp = strndupa(path, e - path);
+ if (!pp)
+ return -ENOMEM;
+
+ r = add_cgroup(cgroups, pp, false, &parent);
+ if (r < 0)
+ return r;
+ }
+
+ cg = new0(struct CGroupInfo, 1);
+ if (!cg)
+ return -ENOMEM;
+
+ if (is_const)
+ cg->cgroup_path = (char*) path;
+ else {
+ cg->cgroup_path = strdup(path);
+ if (!cg->cgroup_path) {
+ free(cg);
+ return -ENOMEM;
+ }
+ }
+
+ cg->is_const = is_const;
+ cg->parent = parent;
+
+ r = hashmap_put(cgroups, cg->cgroup_path, cg);
+ if (r < 0) {
+ if (!is_const)
+ free(cg->cgroup_path);
+ free(cg);
+ return r;
+ }
+
+ if (parent) {
+ LIST_PREPEND(siblings, parent->children, cg);
+ parent->n_children++;
+ }
+
+ *ret = cg;
+ return 1;
+}
+
+static int add_process(
+ Hashmap *cgroups,
+ const char *path,
+ pid_t pid,
+ const char *name) {
+
+ struct CGroupInfo *cg;
+ int r;
+
+ assert(cgroups);
+ assert(name);
+ assert(pid > 0);
+
+ r = add_cgroup(cgroups, path, true, &cg);
+ if (r < 0)
+ return r;
+
+ r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops);
+ if (r < 0)
+ return r;
+
+ return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name);
+}
+
+static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) {
+ assert(cgroups);
+ assert(cg);
+
+ while (cg->children)
+ remove_cgroup(cgroups, cg->children);
+
+ hashmap_remove(cgroups, cg->cgroup_path);
+
+ if (!cg->is_const)
+ free(cg->cgroup_path);
+
+ hashmap_free(cg->pids);
+
+ if (cg->parent)
+ LIST_REMOVE(siblings, cg->parent->children, cg);
+
+ free(cg);
+}
+
+static int cgroup_info_compare_func(const void *a, const void *b) {
+ const struct CGroupInfo *x = *(const struct CGroupInfo* const*) a, *y = *(const struct CGroupInfo* const*) b;
+
+ assert(x);
+ assert(y);
+
+ return strcmp(x->cgroup_path, y->cgroup_path);
+}
+
+static int dump_processes(
+ Hashmap *cgroups,
+ const char *cgroup_path,
+ const char *prefix,
+ unsigned n_columns,
+ OutputFlags flags) {
+
+ struct CGroupInfo *cg;
+ int r;
+
+ assert(prefix);
+
+ if (IS_ROOT(cgroup_path))
+ cgroup_path = "/";
+
+ cg = hashmap_get(cgroups, cgroup_path);
+ if (!cg)
+ return 0;
+
+ if (!hashmap_isempty(cg->pids)) {
+ const char *name;
+ size_t n = 0, i;
+ pid_t *pids;
+ void *pidp;
+ Iterator j;
+ int width;
+
+ /* Order processes by their PID */
+ pids = newa(pid_t, hashmap_size(cg->pids));
+
+ HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j)
+ pids[n++] = PTR_TO_PID(pidp);
+
+ assert(n == hashmap_size(cg->pids));
+ qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+
+ width = DECIMAL_STR_WIDTH(pids[n-1]);
+
+ for (i = 0; i < n; i++) {
+ _cleanup_free_ char *e = NULL;
+ const char *special;
+ bool more;
+
+ name = hashmap_get(cg->pids, PID_TO_PTR(pids[i]));
+ assert(name);
+
+ if (n_columns != 0) {
+ unsigned k;
+
+ k = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
+
+ e = ellipsize(name, k, 100);
+ if (e)
+ name = e;
+ }
+
+ more = i+1 < n || cg->children;
+ special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT);
+
+ fprintf(stdout, "%s%s%*"PID_PRI" %s\n",
+ prefix,
+ special,
+ width, pids[i],
+ name);
+ }
+ }
+
+ if (cg->children) {
+ struct CGroupInfo **children, *child;
+ size_t n = 0, i;
+
+ /* Order subcgroups by their name */
+ children = newa(struct CGroupInfo*, cg->n_children);
+ LIST_FOREACH(siblings, child, cg->children)
+ children[n++] = child;
+ assert(n == cg->n_children);
+ qsort_safe(children, n, sizeof(struct CGroupInfo*), cgroup_info_compare_func);
+
+ n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
+
+ for (i = 0; i < n; i++) {
+ _cleanup_free_ char *pp = NULL;
+ const char *name, *special;
+ bool more;
+
+ child = children[i];
+
+ name = strrchr(child->cgroup_path, '/');
+ if (!name)
+ return -EINVAL;
+ name++;
+
+ more = i+1 < n;
+ special = special_glyph(more ? TREE_BRANCH : TREE_RIGHT);
+
+ fputs(prefix, stdout);
+ fputs(special, stdout);
+ fputs(name, stdout);
+ fputc('\n', stdout);
+
+ special = special_glyph(more ? TREE_VERTICAL : TREE_SPACE);
+
+ pp = strappend(prefix, special);
+ if (!pp)
+ return -ENOMEM;
+
+ r = dump_processes(cgroups, child->cgroup_path, pp, n_columns, flags);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ cg->done = true;
+ return 0;
+}
+
+static int dump_extra_processes(
+ Hashmap *cgroups,
+ const char *prefix,
+ unsigned n_columns,
+ OutputFlags flags) {
+
+ _cleanup_free_ pid_t *pids = NULL;
+ _cleanup_hashmap_free_ Hashmap *names = NULL;
+ struct CGroupInfo *cg;
+ size_t n_allocated = 0, n = 0, k;
+ Iterator i;
+ int width, r;
+
+ /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
+ * combined, sorted, linear list. */
+
+ HASHMAP_FOREACH(cg, cgroups, i) {
+ const char *name;
+ void *pidp;
+ Iterator j;
+
+ if (cg->done)
+ continue;
+
+ if (hashmap_isempty(cg->pids))
+ continue;
+
+ r = hashmap_ensure_allocated(&names, &trivial_hash_ops);
+ if (r < 0)
+ return r;
+
+ if (!GREEDY_REALLOC(pids, n_allocated, n + hashmap_size(cg->pids)))
+ return -ENOMEM;
+
+ HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) {
+ pids[n++] = PTR_TO_PID(pidp);
+
+ r = hashmap_put(names, pidp, (void*) name);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ if (n == 0)
+ return 0;
+
+ qsort_safe(pids, n, sizeof(pid_t), pid_compare_func);
+ width = DECIMAL_STR_WIDTH(pids[n-1]);
+
+ for (k = 0; k < n; k++) {
+ _cleanup_free_ char *e = NULL;
+ const char *name;
+
+ name = hashmap_get(names, PID_TO_PTR(pids[k]));
+ assert(name);
+
+ if (n_columns != 0) {
+ unsigned z;
+
+ z = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
+
+ e = ellipsize(name, z, 100);
+ if (e)
+ name = e;
+ }
+
+ fprintf(stdout, "%s%s %*" PID_PRI " %s\n",
+ prefix,
+ special_glyph(TRIANGULAR_BULLET),
+ width, pids[k],
+ name);
+ }
+
+ return 0;
+}
+
+int unit_show_processes(
+ sd_bus *bus,
+ const char *unit,
+ const char *cgroup_path,
+ const char *prefix,
+ unsigned n_columns,
+ OutputFlags flags,
+ sd_bus_error *error) {
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ Hashmap *cgroups = NULL;
+ struct CGroupInfo *cg;
+ int r;
+
+ assert(bus);
+ assert(unit);
+
+ if (flags & OUTPUT_FULL_WIDTH)
+ n_columns = 0;
+ else if (n_columns <= 0)
+ n_columns = columns();
+
+ prefix = strempty(prefix);
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ "GetUnitProcesses",
+ error,
+ &reply,
+ "s",
+ unit);
+ if (r < 0)
+ return r;
+
+ cgroups = hashmap_new(&string_hash_ops);
+ if (!cgroups)
+ return -ENOMEM;
+
+ r = sd_bus_message_enter_container(reply, 'a', "(sus)");
+ if (r < 0)
+ goto finish;
+
+ for (;;) {
+ const char *path = NULL, *name = NULL;
+ uint32_t pid;
+
+ r = sd_bus_message_read(reply, "(sus)", &path, &pid, &name);
+ if (r < 0)
+ goto finish;
+ if (r == 0)
+ break;
+
+ r = add_process(cgroups, path, pid, name);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ goto finish;
+
+ r = dump_processes(cgroups, cgroup_path, prefix, n_columns, flags);
+ if (r < 0)
+ goto finish;
+
+ r = dump_extra_processes(cgroups, prefix, n_columns, flags);
+
+finish:
+ while ((cg = hashmap_first(cgroups)))
+ remove_cgroup(cgroups, cg);
+
+ hashmap_free(cgroups);
+
+ return r;
+}
diff --git a/src/libshared/bus-unit-util.h b/src/libshared/bus-unit-util.h
new file mode 100644
index 0000000000..8327189a63
--- /dev/null
+++ b/src/libshared/bus-unit-util.h
@@ -0,0 +1,57 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <systemd/sd-bus.h>
+
+#include "output-mode.h"
+#include "install.h"
+
+typedef struct UnitInfo {
+ const char *machine;
+ const char *id;
+ const char *description;
+ const char *load_state;
+ const char *active_state;
+ const char *sub_state;
+ const char *following;
+ const char *unit_path;
+ uint32_t job_id;
+ const char *job_type;
+ const char *job_path;
+} UnitInfo;
+
+int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
+
+int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
+
+typedef struct BusWaitForJobs BusWaitForJobs;
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
+void bus_wait_for_jobs_free(BusWaitForJobs *d);
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
+
+int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
+
+int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error);
diff --git a/src/libshared/bus-util.c b/src/libshared/bus-util.c
index a874bb84cc..62b5585e84 100644
--- a/src/libshared/bus-util.c
+++ b/src/libshared/bus-util.c
@@ -39,34 +39,16 @@
#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "cgroup-util.h"
#include "def.h"
-#include "env-util.h"
#include "escape.h"
-#include "extract-word.h"
#include "fd-util.h"
-#include "hashmap.h"
-#include "install.h"
-#include "kdbus.h"
-#include "log.h"
-#include "macro.h"
#include "missing.h"
#include "parse-util.h"
-#include "path-util.h"
#include "proc-cmdline.h"
-#include "process-util.h"
#include "rlimit-util.h"
-#include "set.h"
-#include "signal-util.h"
#include "stdio-util.h"
-#include "string-util.h"
#include "strv.h"
-#include "syslog-util.h"
-#include "time-util.h"
-#include "unit-name.h"
#include "user-util.h"
-#include "utf8.h"
-#include "util.h"
static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
sd_event *e = userdata;
@@ -712,7 +694,15 @@ int bus_connect_user_systemd(sd_bus **_bus) {
return 0;
}
-int bus_print_property(const char *name, sd_bus_message *property, bool all) {
+#define print_property(name, fmt, ...) \
+ do { \
+ if (value) \
+ printf(fmt "\n", __VA_ARGS__); \
+ else \
+ printf("%s=" fmt "\n", name, __VA_ARGS__); \
+ } while(0)
+
+int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all) {
char type;
const char *contents;
int r;
@@ -740,7 +730,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (!escaped)
return -ENOMEM;
- printf("%s=%s\n", name, escaped);
+ print_property(name, "%s", escaped);
}
return 1;
@@ -753,7 +743,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (r < 0)
return r;
- printf("%s=%s\n", name, yes_no(b));
+ print_property(name, "%s", yes_no(b));
return 1;
}
@@ -773,14 +763,14 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
t = format_timestamp(timestamp, sizeof(timestamp), u);
if (t || all)
- printf("%s=%s\n", name, strempty(t));
+ print_property(name, "%s", strempty(t));
} else if (strstr(name, "USec")) {
char timespan[FORMAT_TIMESPAN_MAX];
- printf("%s=%s\n", name, format_timespan(timespan, sizeof(timespan), u, 0));
+ print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
} else
- printf("%s=%llu\n", name, (unsigned long long) u);
+ print_property(name, "%"PRIu64, u);
return 1;
}
@@ -792,7 +782,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (r < 0)
return r;
- printf("%s=%lld\n", name, (long long) i);
+ print_property(name, "%"PRIi64, i);
return 1;
}
@@ -805,9 +795,9 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
return r;
if (strstr(name, "UMask") || strstr(name, "Mode"))
- printf("%s=%04o\n", name, u);
+ print_property(name, "%04o", u);
else
- printf("%s=%u\n", name, (unsigned) u);
+ print_property(name, "%"PRIu32, u);
return 1;
}
@@ -819,7 +809,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (r < 0)
return r;
- printf("%s=%i\n", name, (int) i);
+ print_property(name, "%"PRIi32, i);
return 1;
}
@@ -830,7 +820,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (r < 0)
return r;
- printf("%s=%g\n", name, d);
+ print_property(name, "%g", d);
return 1;
}
@@ -843,10 +833,10 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (r < 0)
return r;
- while((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
+ while ((r = sd_bus_message_read_basic(property, SD_BUS_TYPE_STRING, &str)) > 0) {
_cleanup_free_ char *escaped = NULL;
- if (first)
+ if (first && !value)
printf("%s=", name);
escaped = xescape(str, "\n ");
@@ -860,7 +850,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (r < 0)
return r;
- if (first && all)
+ if (first && all && !value)
printf("%s=", name);
if (!first || all)
puts("");
@@ -882,7 +872,8 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (all || n > 0) {
unsigned int i;
- printf("%s=", name);
+ if (!value)
+ printf("%s=", name);
for (i = 0; i < n; i++)
printf("%02x", u[i]);
@@ -903,7 +894,8 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
if (all || n > 0) {
unsigned int i;
- printf("%s=", name);
+ if (!value)
+ printf("%s=", name);
for (i = 0; i < n; i++)
printf("%08x", u[i]);
@@ -920,7 +912,7 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) {
return 0;
}
-int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) {
+int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -960,7 +952,7 @@ int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, ch
if (r < 0)
return r;
- r = bus_print_property(name, reply, all);
+ r = bus_print_property(name, reply, value, all);
if (r < 0)
return r;
if (r == 0) {
@@ -1068,7 +1060,7 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_
}
case SD_BUS_TYPE_UINT32: {
- uint64_t u;
+ uint32_t u;
uint32_t *p = userdata;
r = sd_bus_message_read_basic(m, type, &u);
@@ -1373,839 +1365,6 @@ int bus_log_create_error(int r) {
return log_error_errno(r, "Failed to create bus message: %m");
}
-int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
- assert(message);
- assert(u);
-
- u->machine = NULL;
-
- return sd_bus_message_read(
- message,
- "(ssssssouso)",
- &u->id,
- &u->description,
- &u->load_state,
- &u->active_state,
- &u->sub_state,
- &u->following,
- &u->unit_path,
- &u->job_id,
- &u->job_type,
- &u->job_path);
-}
-
-int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
- const char *eq, *field;
- int r, rl;
-
- assert(m);
- assert(assignment);
-
- eq = strchr(assignment, '=');
- if (!eq) {
- log_error("Not an assignment: %s", assignment);
- return -EINVAL;
- }
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- field = strndupa(assignment, eq - assignment);
- eq ++;
-
- if (streq(field, "CPUQuota")) {
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
- else if (endswith(eq, "%")) {
- double percent;
-
- if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
- log_error("CPU quota '%s' invalid.", eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100);
- } else {
- log_error("CPU quota needs to be in percent.");
- return -EINVAL;
- }
-
- goto finish;
-
- } else if (streq(field, "EnvironmentFile")) {
-
- r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
- eq[0] == '-' ? eq + 1 : eq,
- eq[0] == '-');
- goto finish;
-
- } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
- char *n;
- usec_t t;
- size_t l;
- r = parse_sec(eq, &t);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
-
- l = strlen(field);
- n = newa(char, l + 2);
- if (!n)
- return log_oom();
-
- /* Change suffix Sec → USec */
- strcpy(mempcpy(n, field, l - 3), "USec");
- r = sd_bus_message_append(m, "sv", n, "t", t);
- goto finish;
- }
-
- r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
- if (r < 0)
- return bus_log_create_error(r);
-
- rl = rlimit_from_string(field);
- if (rl >= 0) {
- const char *sn;
- struct rlimit l;
-
- r = rlimit_parse(rl, eq, &l);
- if (r < 0)
- return log_error_errno(r, "Failed to parse resource limit: %s", eq);
-
- r = sd_bus_message_append(m, "v", "t", l.rlim_max);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
- if (r < 0)
- return bus_log_create_error(r);
-
- sn = strjoina(field, "Soft");
- r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
-
- } else if (STR_IN_SET(field,
- "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
- "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
- "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
- "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
- "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
-
- r = parse_boolean(eq);
- if (r < 0)
- return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment);
-
- r = sd_bus_message_append(m, "v", "b", r);
-
- } else if (streq(field, "MemoryLimit")) {
- uint64_t bytes;
-
- if (isempty(eq) || streq(eq, "infinity"))
- bytes = (uint64_t) -1;
- else {
- r = parse_size(eq, 1024, &bytes);
- if (r < 0) {
- log_error("Failed to parse bytes specification %s", assignment);
- return -EINVAL;
- }
- }
-
- r = sd_bus_message_append(m, "v", "t", bytes);
-
- } else if (streq(field, "TasksMax")) {
- uint64_t n;
-
- if (isempty(eq) || streq(eq, "infinity"))
- n = (uint64_t) -1;
- else {
- r = safe_atou64(eq, &n);
- if (r < 0) {
- log_error("Failed to parse maximum tasks specification %s", assignment);
- return -EINVAL;
- }
- }
-
- r = sd_bus_message_append(m, "v", "t", n);
-
- } else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
- uint64_t u;
-
- r = cg_cpu_shares_parse(eq, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "t", u);
-
- } else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
- uint64_t u;
-
- r = cg_cpu_shares_parse(eq, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "t", u);
-
- } else if (STR_IN_SET(field,
- "User", "Group", "DevicePolicy", "KillMode",
- "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
- "StandardInput", "StandardOutput", "StandardError",
- "Description", "Slice", "Type", "WorkingDirectory",
- "RootDirectory", "SyslogIdentifier", "ProtectSystem",
- "ProtectHome"))
- r = sd_bus_message_append(m, "v", "s", eq);
-
- else if (streq(field, "SyslogLevel")) {
- int level;
-
- level = log_level_from_string(eq);
- if (level < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "i", level);
-
- } else if (streq(field, "SyslogFacility")) {
- int facility;
-
- facility = log_facility_unshifted_from_string(eq);
- if (facility < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "i", facility);
-
- } else if (streq(field, "DeviceAllow")) {
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "v", "a(ss)", 0);
- else {
- const char *path, *rwm, *e;
-
- e = strchr(eq, ' ');
- if (e) {
- path = strndupa(eq, e - eq);
- rwm = e+1;
- } else {
- path = eq;
- rwm = "";
- }
-
- if (!path_startswith(path, "/dev")) {
- log_error("%s is not a device file in /dev.", path);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
- }
-
- } else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "v", "a(st)", 0);
- else {
- const char *path, *bandwidth, *e;
- uint64_t bytes;
-
- e = strchr(eq, ' ');
- if (e) {
- path = strndupa(eq, e - eq);
- bandwidth = e+1;
- } else {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- if (!path_startswith(path, "/dev")) {
- log_error("%s is not a device file in /dev.", path);
- return -EINVAL;
- }
-
- r = parse_size(bandwidth, 1000, &bytes);
- if (r < 0) {
- log_error("Failed to parse byte value %s.", bandwidth);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
- }
-
- } else if (streq(field, "BlockIODeviceWeight")) {
-
- if (isempty(eq))
- r = sd_bus_message_append(m, "v", "a(st)", 0);
- else {
- const char *path, *weight, *e;
- uint64_t u;
-
- e = strchr(eq, ' ');
- if (e) {
- path = strndupa(eq, e - eq);
- weight = e+1;
- } else {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- if (!path_startswith(path, "/dev")) {
- log_error("%s is not a device file in /dev.", path);
- return -EINVAL;
- }
-
- r = safe_atou64(weight, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, weight);
- return -EINVAL;
- }
- r = sd_bus_message_append(m, "v", "a(st)", path, u);
- }
-
- } else if (streq(field, "Nice")) {
- int32_t i;
-
- r = safe_atoi32(eq, &i);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "i", i);
-
- } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
- const char *p;
-
- r = sd_bus_message_open_container(m, 'v', "as");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "s");
- if (r < 0)
- return bus_log_create_error(r);
-
- p = eq;
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
- if (r < 0) {
- log_error("Failed to parse Environment value %s", eq);
- return -EINVAL;
- }
- if (r == 0)
- break;
-
- if (streq(field, "Environment")) {
- if (!env_assignment_is_valid(word)) {
- log_error("Invalid environment assignment: %s", word);
- return -EINVAL;
- }
- } else { /* PassEnvironment */
- if (!env_name_is_valid(word)) {
- log_error("Invalid environment variable name: %s", word);
- return -EINVAL;
- }
- }
-
- r = sd_bus_message_append_basic(m, 's', word);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
-
- } else if (streq(field, "KillSignal")) {
- int sig;
-
- sig = signal_from_string_try_harder(eq);
- if (sig < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "i", sig);
-
- } else if (streq(field, "TimerSlackNSec")) {
- nsec_t n;
-
- r = parse_nsec(eq, &n);
- if (r < 0) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "t", n);
- } else if (streq(field, "OOMScoreAdjust")) {
- int oa;
-
- r = safe_atoi(eq, &oa);
- if (r < 0) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
-
- if (!oom_score_adjust_is_valid(oa)) {
- log_error("OOM score adjust value out of range");
- return -EINVAL;
- }
-
- r = sd_bus_message_append(m, "v", "i", oa);
- } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
- const char *p;
-
- r = sd_bus_message_open_container(m, 'v', "as");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "s");
- if (r < 0)
- return bus_log_create_error(r);
-
- p = eq;
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- int offset;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r < 0) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
- if (r == 0)
- break;
-
- if (!utf8_is_valid(word)) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
-
- offset = word[0] == '-';
- if (!path_is_absolute(word + offset)) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
-
- path_kill_slashes(word + offset);
-
- r = sd_bus_message_append_basic(m, 's', word);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
-
- } else if (streq(field, "RuntimeDirectory")) {
- const char *p;
-
- r = sd_bus_message_open_container(m, 'v', "as");
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "s");
- if (r < 0)
- return bus_log_create_error(r);
-
- p = eq;
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r < 0)
- return log_error_errno(r, "Failed to parse %s value %s", field, eq);
-
- if (r == 0)
- break;
-
- r = sd_bus_message_append_basic(m, 's', word);
- if (r < 0)
- return bus_log_create_error(r);
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
-
- } else {
- log_error("Unknown assignment %s.", assignment);
- return -EINVAL;
- }
-
-finish:
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_close_container(m);
- if (r < 0)
- return bus_log_create_error(r);
-
- return 0;
-}
-
-typedef struct BusWaitForJobs {
- sd_bus *bus;
- Set *jobs;
-
- char *name;
- char *result;
-
- sd_bus_slot *slot_job_removed;
- sd_bus_slot *slot_disconnected;
-} BusWaitForJobs;
-
-static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- assert(m);
-
- log_error("Warning! D-Bus connection terminated.");
- sd_bus_close(sd_bus_message_get_bus(m));
-
- return 0;
-}
-
-static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- const char *path, *unit, *result;
- BusWaitForJobs *d = userdata;
- uint32_t id;
- char *found;
- int r;
-
- assert(m);
- assert(d);
-
- r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- found = set_remove(d->jobs, (char*) path);
- if (!found)
- return 0;
-
- free(found);
-
- if (!isempty(result))
- d->result = strdup(result);
-
- if (!isempty(unit))
- d->name = strdup(unit);
-
- return 0;
-}
-
-void bus_wait_for_jobs_free(BusWaitForJobs *d) {
- if (!d)
- return;
-
- set_free_free(d->jobs);
-
- sd_bus_slot_unref(d->slot_disconnected);
- sd_bus_slot_unref(d->slot_job_removed);
-
- sd_bus_unref(d->bus);
-
- free(d->name);
- free(d->result);
-
- free(d);
-}
-
-int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
- _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
- int r;
-
- assert(bus);
- assert(ret);
-
- d = new0(BusWaitForJobs, 1);
- if (!d)
- return -ENOMEM;
-
- d->bus = sd_bus_ref(bus);
-
- /* When we are a bus client we match by sender. Direct
- * connections OTOH have no initialized sender field, and
- * hence we ignore the sender then */
- r = sd_bus_add_match(
- bus,
- &d->slot_job_removed,
- bus->bus_client ?
- "type='signal',"
- "sender='org.freedesktop.systemd1',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='JobRemoved',"
- "path='/org/freedesktop/systemd1'" :
- "type='signal',"
- "interface='org.freedesktop.systemd1.Manager',"
- "member='JobRemoved',"
- "path='/org/freedesktop/systemd1'",
- match_job_removed, d);
- if (r < 0)
- return r;
-
- r = sd_bus_add_match(
- bus,
- &d->slot_disconnected,
- "type='signal',"
- "sender='org.freedesktop.DBus.Local',"
- "interface='org.freedesktop.DBus.Local',"
- "member='Disconnected'",
- match_disconnected, d);
- if (r < 0)
- return r;
-
- *ret = d;
- d = NULL;
-
- return 0;
-}
-
-static int bus_process_wait(sd_bus *bus) {
- int r;
-
- for (;;) {
- r = sd_bus_process(bus, NULL);
- if (r < 0)
- return r;
- if (r > 0)
- return 0;
-
- r = sd_bus_wait(bus, (uint64_t) -1);
- if (r < 0)
- return r;
- }
-}
-
-static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
- _cleanup_free_ char *dbus_path = NULL;
-
- assert(d);
- assert(d->name);
- assert(result);
-
- dbus_path = unit_dbus_path_from_name(d->name);
- if (!dbus_path)
- return -ENOMEM;
-
- return sd_bus_get_property_string(d->bus,
- "org.freedesktop.systemd1",
- dbus_path,
- "org.freedesktop.systemd1.Service",
- "Result",
- NULL,
- result);
-}
-
-static const struct {
- const char *result, *explanation;
-} explanations [] = {
- { "resources", "a configured resource limit was exceeded" },
- { "timeout", "a timeout was exceeded" },
- { "exit-code", "the control process exited with error code" },
- { "signal", "a fatal signal was delivered to the control process" },
- { "core-dump", "a fatal signal was delivered causing the control process to dump core" },
- { "watchdog", "the service failed to send watchdog ping" },
- { "start-limit", "start of the service was attempted too often" }
-};
-
-static void log_job_error_with_service_result(const char* service, const char *result, const char *extra_args) {
- _cleanup_free_ char *service_shell_quoted = NULL, *systemctl_extra_args = NULL;
-
- assert(service);
-
- service_shell_quoted = shell_maybe_quote(service);
-
- systemctl_extra_args = strjoin("systemctl ", extra_args, " ", NULL);
- if (!systemctl_extra_args) {
- log_oom();
- return;
- }
-
- systemctl_extra_args = strstrip(systemctl_extra_args);
-
- if (!isempty(result)) {
- unsigned i;
-
- for (i = 0; i < ELEMENTSOF(explanations); ++i)
- if (streq(result, explanations[i].result))
- break;
-
- if (i < ELEMENTSOF(explanations)) {
- log_error("Job for %s failed because %s. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
- service,
- explanations[i].explanation,
- systemctl_extra_args,
- strna(service_shell_quoted));
-
- goto finish;
- }
- }
-
- log_error("Job for %s failed. See \"%s status %s\" and \"journalctl -xe\" for details.\n",
- service,
- systemctl_extra_args,
- strna(service_shell_quoted));
-
-finish:
- /* For some results maybe additional explanation is required */
- if (streq_ptr(result, "start-limit"))
- log_info("To force a start use \"%1$s reset-failed %2$s\" followed by \"%1$s start %2$s\" again.",
- systemctl_extra_args,
- strna(service_shell_quoted));
-}
-
-static int check_wait_response(BusWaitForJobs *d, bool quiet, const char *extra_args) {
- int r = 0;
-
- assert(d->result);
-
- if (!quiet) {
- if (streq(d->result, "canceled"))
- log_error("Job for %s canceled.", strna(d->name));
- else if (streq(d->result, "timeout"))
- log_error("Job for %s timed out.", strna(d->name));
- else if (streq(d->result, "dependency"))
- log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
- else if (streq(d->result, "invalid"))
- log_error("%s is not active, cannot reload.", strna(d->name));
- else if (streq(d->result, "assert"))
- log_error("Assertion failed on job for %s.", strna(d->name));
- else if (streq(d->result, "unsupported"))
- log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
- else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
- if (d->name) {
- int q;
- _cleanup_free_ char *result = NULL;
-
- q = bus_job_get_service_result(d, &result);
- if (q < 0)
- log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
-
- log_job_error_with_service_result(d->name, result, extra_args);
- } else
- log_error("Job failed. See \"journalctl -xe\" for details.");
- }
- }
-
- if (streq(d->result, "canceled"))
- r = -ECANCELED;
- else if (streq(d->result, "timeout"))
- r = -ETIME;
- else if (streq(d->result, "dependency"))
- r = -EIO;
- else if (streq(d->result, "invalid"))
- r = -ENOEXEC;
- else if (streq(d->result, "assert"))
- r = -EPROTO;
- else if (streq(d->result, "unsupported"))
- r = -EOPNOTSUPP;
- else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
- r = -EIO;
-
- return r;
-}
-
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char *extra_args) {
- int r = 0;
-
- assert(d);
-
- while (!set_isempty(d->jobs)) {
- int q;
-
- q = bus_process_wait(d->bus);
- if (q < 0)
- return log_error_errno(q, "Failed to wait for response: %m");
-
- if (d->result) {
- q = check_wait_response(d, quiet, extra_args);
- /* Return the first error as it is most likely to be
- * meaningful. */
- if (q < 0 && r == 0)
- r = q;
-
- log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
- }
-
- d->name = mfree(d->name);
- d->result = mfree(d->result);
- }
-
- return r;
-}
-
-int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
- int r;
-
- assert(d);
-
- r = set_ensure_allocated(&d->jobs, &string_hash_ops);
- if (r < 0)
- return r;
-
- return set_put_strdup(d->jobs, path);
-}
-
-int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
- int r;
-
- r = bus_wait_for_jobs_add(d, path);
- if (r < 0)
- return log_oom();
-
- return bus_wait_for_jobs(d, quiet, NULL);
-}
-
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
- const char *type, *path, *source;
- int r;
-
- r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
- if (r < 0)
- return bus_log_parse_error(r);
-
- while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
- if (!quiet) {
- if (streq(type, "symlink"))
- log_info("Created symlink from %s to %s.", path, source);
- else
- log_info("Removed symlink %s.", path);
- }
-
- r = unit_file_changes_add(changes, n_changes, streq(type, "symlink") ? UNIT_FILE_SYMLINK : UNIT_FILE_UNLINK, path, source);
- if (r < 0)
- return r;
- }
- if (r < 0)
- return bus_log_parse_error(r);
-
- r = sd_bus_message_exit_container(m);
- if (r < 0)
- return bus_log_parse_error(r);
-
- return 0;
-}
-
/**
* bus_path_encode_unique() - encode unique object path
* @b: bus connection or NULL
diff --git a/src/libshared/bus-util.h b/src/libshared/bus-util.h
index 77474522be..f2b46530ba 100644
--- a/src/libshared/bus-util.h
+++ b/src/libshared/bus-util.h
@@ -24,15 +24,12 @@
#include <stdint.h>
#include <sys/types.h>
-#include <systemd/sd-bus-vtable.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include "hashmap.h"
-#include "install.h"
#include "macro.h"
#include "string-util.h"
-#include "time-util.h"
typedef enum BusTransport {
BUS_TRANSPORT_LOCAL,
@@ -78,8 +75,8 @@ int bus_connect_user_systemd(sd_bus **_bus);
int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus);
int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus);
-int bus_print_property(const char *name, sd_bus_message *property, bool all);
-int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all);
+int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all);
+int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool value, bool all);
int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
@@ -126,22 +123,6 @@ assert_cc(sizeof(mode_t) == sizeof(uint32_t));
int bus_log_parse_error(int r);
int bus_log_create_error(int r);
-typedef struct UnitInfo {
- const char *machine;
- const char *id;
- const char *description;
- const char *load_state;
- const char *active_state;
- const char *sub_state;
- const char *following;
- const char *unit_path;
- uint32_t job_id;
- const char *job_type;
- const char *job_path;
-} UnitInfo;
-
-int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
-
#define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \
int function(sd_bus *bus, \
const char *path, \
@@ -173,20 +154,6 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \
SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags))
-int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
-
-typedef struct BusWaitForJobs BusWaitForJobs;
-
-int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
-void bus_wait_for_jobs_free(BusWaitForJobs *d);
-int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char *extra_args);
-int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
-
-int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
-
int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path);
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external);
diff --git a/src/libshared/cgroup-show.c b/src/libshared/cgroup-show.c
index f3039b23f7..3e451db715 100644
--- a/src/libshared/cgroup-show.c
+++ b/src/libshared/cgroup-show.c
@@ -37,23 +37,21 @@
#include "string-util.h"
#include "terminal-util.h"
-static int compare(const void *a, const void *b) {
- const pid_t *p = a, *q = b;
+static void show_pid_array(
+ pid_t pids[],
+ unsigned n_pids,
+ const char *prefix,
+ unsigned n_columns,
+ bool extra,
+ bool more,
+ OutputFlags flags) {
- if (*p < *q)
- return -1;
- if (*p > *q)
- return 1;
- return 0;
-}
-
-static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
unsigned i, j, pid_width;
if (n_pids == 0)
return;
- qsort(pids, n_pids, sizeof(pid_t), compare);
+ qsort(pids, n_pids, sizeof(pid_t), pid_compare_func);
/* Filter duplicates */
for (j = 0, i = 1; i < n_pids; i++) {
@@ -78,16 +76,21 @@ static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, un
get_process_cmdline(pids[i], n_columns, true, &t);
if (extra)
- printf("%s%s ", prefix, draw_special_char(DRAW_TRIANGULAR_BULLET));
+ printf("%s%s ", prefix, special_glyph(TRIANGULAR_BULLET));
else
- printf("%s%s", prefix, draw_special_char(((more || i < n_pids-1) ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT)));
+ printf("%s%s", prefix, special_glyph(((more || i < n_pids-1) ? TREE_BRANCH : TREE_RIGHT)));
printf("%*"PID_PRI" %s\n", pid_width, pids[i], strna(t));
}
}
+static int show_cgroup_one_by_path(
+ const char *path,
+ const char *prefix,
+ unsigned n_columns,
+ bool more,
+ OutputFlags flags) {
-static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
char *fn;
_cleanup_fclose_ FILE *f = NULL;
size_t n = 0, n_allocated = 0;
@@ -107,7 +110,7 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
while ((r = cg_read_pid(f, &pid)) > 0) {
- if (!kernel_threads && is_kernel_thread(pid) > 0)
+ if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0)
continue;
if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
@@ -120,12 +123,17 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
if (r < 0)
return r;
- show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
+ show_pid_array(pids, n, prefix, n_columns, false, more, flags);
return 0;
}
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
+int show_cgroup_by_path(
+ const char *path,
+ const char *prefix,
+ unsigned n_columns,
+ OutputFlags flags) {
+
_cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
_cleanup_closedir_ DIR *d = NULL;
char *gn = NULL;
@@ -137,8 +145,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (n_columns <= 0)
n_columns = columns();
- if (!prefix)
- prefix = "";
+ prefix = strempty(prefix);
r = cg_mangle_path(path, &fn);
if (r < 0)
@@ -160,20 +167,20 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
continue;
if (!shown_pids) {
- show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
+ show_cgroup_one_by_path(path, prefix, n_columns, true, flags);
shown_pids = true;
}
if (last) {
- printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_BRANCH), cg_unescape(basename(last)));
+ printf("%s%s%s\n", prefix, special_glyph(TREE_BRANCH), cg_unescape(basename(last)));
if (!p1) {
- p1 = strappend(prefix, draw_special_char(DRAW_TREE_VERTICAL));
+ p1 = strappend(prefix, special_glyph(TREE_VERTICAL));
if (!p1)
return -ENOMEM;
}
- show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
+ show_cgroup_by_path(last, p1, n_columns-2, flags);
free(last);
}
@@ -185,10 +192,10 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
return r;
if (!shown_pids)
- show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
+ show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags);
if (last) {
- printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
+ printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), cg_unescape(basename(last)));
if (!p2) {
p2 = strappend(prefix, " ");
@@ -196,13 +203,17 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
return -ENOMEM;
}
- show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
+ show_cgroup_by_path(last, p2, n_columns-2, flags);
}
return 0;
}
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
+int show_cgroup(const char *controller,
+ const char *path,
+ const char *prefix,
+ unsigned n_columns,
+ OutputFlags flags) {
_cleanup_free_ char *p = NULL;
int r;
@@ -212,10 +223,18 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un
if (r < 0)
return r;
- return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
+ return show_cgroup_by_path(p, prefix, n_columns, flags);
}
-static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids, OutputFlags flags) {
+static int show_extra_pids(
+ const char *controller,
+ const char *path,
+ const char *prefix,
+ unsigned n_columns,
+ const pid_t pids[],
+ unsigned n_pids,
+ OutputFlags flags) {
+
_cleanup_free_ pid_t *copy = NULL;
unsigned i, j;
int r;
@@ -247,24 +266,39 @@ static int show_extra_pids(const char *controller, const char *path, const char
copy[j++] = pids[i];
}
- show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
+ show_pid_array(copy, j, prefix, n_columns, true, false, flags);
return 0;
}
-int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
+int show_cgroup_and_extra(
+ const char *controller,
+ const char *path,
+ const char *prefix,
+ unsigned n_columns,
+ const pid_t extra_pids[],
+ unsigned n_extra_pids,
+ OutputFlags flags) {
+
int r;
assert(path);
- r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
+ r = show_cgroup(controller, path, prefix, n_columns, flags);
if (r < 0)
return r;
return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
}
-int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
+int show_cgroup_and_extra_by_spec(
+ const char *spec,
+ const char *prefix,
+ unsigned n_columns,
+ const pid_t extra_pids[],
+ unsigned n_extra_pids,
+ OutputFlags flags) {
+
_cleanup_free_ char *controller = NULL, *path = NULL;
int r;
@@ -274,5 +308,5 @@ int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned
if (r < 0)
return r;
- return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
+ return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
}
diff --git a/src/libshared/cgroup-show.h b/src/libshared/cgroup-show.h
index 3ab7dfb33c..5c1d6e6d98 100644
--- a/src/libshared/cgroup-show.h
+++ b/src/libshared/cgroup-show.h
@@ -25,8 +25,8 @@
#include "logs-show.h"
#include "output-mode.h"
-int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
-int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
+int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, OutputFlags flags);
+int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, OutputFlags flags);
-int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
-int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
+int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
+int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
diff --git a/src/libshared/condition.c b/src/libshared/condition.c
index 1719a4c7a6..33ca6e029e 100644
--- a/src/libshared/condition.c
+++ b/src/libshared/condition.c
@@ -295,7 +295,7 @@ static int condition_test_needs_update(Condition *c) {
return false;
/* Any other failure means we should allow the condition to be true,
- * so that we rather invoke too many update tools then too
+ * so that we rather invoke too many update tools than too
* few. */
if (!path_is_absolute(c->parameter))
diff --git a/src/libshared/conf-parser.c b/src/libshared/conf-parser.c
index e7fe9ac21e..83be79a4f5 100644
--- a/src/libshared/conf-parser.c
+++ b/src/libshared/conf-parser.c
@@ -37,6 +37,7 @@
#include "path-util.h"
#include "process-util.h"
#include "signal-util.h"
+#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
@@ -294,7 +295,7 @@ int config_parse(const char *unit,
_cleanup_free_ char *section = NULL, *continuation = NULL;
_cleanup_fclose_ FILE *ours = NULL;
unsigned line = 0, section_line = 0;
- bool section_ignored = false;
+ bool section_ignored = false, allow_bom = true;
int r;
assert(filename);
@@ -314,11 +315,11 @@ int config_parse(const char *unit,
fd_warn_permissions(filename, fileno(f));
- while (!feof(f)) {
- char l[LINE_MAX], *p, *c = NULL, *e;
+ for (;;) {
+ char buf[LINE_MAX], *l, *p, *c = NULL, *e;
bool escaped = false;
- if (!fgets(l, sizeof(l), f)) {
+ if (!fgets(buf, sizeof buf, f)) {
if (feof(f))
break;
@@ -326,6 +327,11 @@ int config_parse(const char *unit,
return -errno;
}
+ l = buf;
+ if (allow_bom && startswith(l, UTF8_BYTE_ORDER_MARK))
+ l += strlen(UTF8_BYTE_ORDER_MARK);
+ allow_bom = false;
+
truncate_nl(l);
if (continuation) {
@@ -727,7 +733,7 @@ int config_parse_strv(const char *unit,
for (;;) {
char *word = NULL;
int r;
- r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+ r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_RETAIN_ESCAPE);
if (r == 0)
break;
if (r == -ENOMEM)
@@ -868,3 +874,40 @@ int config_parse_personality(
*personality = p;
return 0;
}
+
+int config_parse_ifname(
+ 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) {
+
+ char **s = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ *s = mfree(*s);
+ return 0;
+ }
+
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ r = free_and_strdup(s, rvalue);
+ if (r < 0)
+ return log_oom();
+
+ return 0;
+}
diff --git a/src/libshared/conf-parser.h b/src/libshared/conf-parser.h
index a91c94c322..f6964e3fd4 100644
--- a/src/libshared/conf-parser.h
+++ b/src/libshared/conf-parser.h
@@ -125,6 +125,7 @@ int config_parse_log_facility(const char *unit, const char *filename, unsigned l
int config_parse_log_level(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int 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);
+int config_parse_ifname(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 DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
int function(const char *unit, \
@@ -178,7 +179,7 @@ int config_parse_personality(const char *unit, const char *filename, unsigned li
assert(data); \
\
xs = new0(type, 1); \
- if(!xs) \
+ if (!xs) \
return -ENOMEM; \
\
*xs = invalid; \
diff --git a/src/libshared/dns-domain.c b/src/libshared/dns-domain.c
index 45d24c0079..835557c6b2 100644
--- a/src/libshared/dns-domain.c
+++ b/src/libshared/dns-domain.c
@@ -180,7 +180,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
unsigned slashes = 0;
for (y = terminal - 1; y >= name && *y == '\\'; y--)
- slashes ++;
+ slashes++;
if (slashes % 2 == 0) {
/* The '.' was not escaped */
@@ -192,7 +192,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha
}
}
- terminal --;
+ terminal--;
}
r = dns_label_unescape(&name, dest, sz);
@@ -331,7 +331,7 @@ int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded
l = strlen(buffer);
- /* Verify that the the result is not longer than one DNS label. */
+ /* Verify that the result is not longer than one DNS label. */
if (l <= 0 || l > DNS_LABEL_MAX)
return -EINVAL;
if (l > decoded_max)
@@ -1172,7 +1172,7 @@ int dns_name_skip(const char *a, unsigned n_labels, const char **ret) {
assert(a);
assert(ret);
- for (; n_labels > 0; n_labels --) {
+ for (; n_labels > 0; n_labels--) {
r = dns_name_parent(&a);
if (r < 0)
return r;
diff --git a/src/libshared/dns-domain.h b/src/libshared/dns-domain.h
index 2de3642cb3..af780f0b8b 100644
--- a/src/libshared/dns-domain.h
+++ b/src/libshared/dns-domain.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,9 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
diff --git a/src/libshared/dropin.c b/src/libshared/dropin.c
index cc1acd6f23..b9cd952ac8 100644
--- a/src/libshared/dropin.c
+++ b/src/libshared/dropin.c
@@ -160,7 +160,7 @@ static int iterate_dir(
if (!de)
break;
- if (hidden_file(de->d_name))
+ if (hidden_or_backup_file(de->d_name))
continue;
f = strjoin(path, "/", de->d_name, NULL);
diff --git a/src/libshared/gcrypt-util.c b/src/libshared/gcrypt-util.c
new file mode 100644
index 0000000000..39b544b6f0
--- /dev/null
+++ b/src/libshared/gcrypt-util.c
@@ -0,0 +1,71 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_GCRYPT
+#include <gcrypt.h>
+
+#include "gcrypt-util.h"
+#include "hexdecoct.h"
+
+void initialize_libgcrypt(bool secmem) {
+ const char *p;
+ if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
+ return;
+
+ p = gcry_check_version("1.4.5");
+ assert(p);
+
+ /* Turn off "secmem". Clients which wish to make use of this
+ * feature should initialize the library manually */
+ if (!secmem)
+ gcry_control(GCRYCTL_DISABLE_SECMEM);
+ gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
+}
+
+int string_hashsum(const char *s, size_t len, int md_algorithm, char **out) {
+ gcry_md_hd_t md = NULL;
+ size_t hash_size;
+ void *hash;
+ char *enc;
+
+ initialize_libgcrypt(false);
+
+ hash_size = gcry_md_get_algo_dlen(md_algorithm);
+ assert(hash_size > 0);
+
+ gcry_md_open(&md, md_algorithm, 0);
+ if (!md)
+ return -EIO;
+
+ gcry_md_write(md, s, len);
+
+ hash = gcry_md_read(md, 0);
+ if (!hash)
+ return -EIO;
+
+ enc = hexmem(hash, hash_size);
+ if (!enc)
+ return -ENOMEM;
+
+ *out = enc;
+ return 0;
+}
+#endif
diff --git a/src/libshared/gcrypt-util.h b/src/libshared/gcrypt-util.h
new file mode 100644
index 0000000000..cf33b3c59c
--- /dev/null
+++ b/src/libshared/gcrypt-util.h
@@ -0,0 +1,39 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+#ifdef HAVE_GCRYPT
+#include <gcrypt.h>
+
+void initialize_libgcrypt(bool secmem);
+int string_hashsum(const char *s, size_t len, int md_algorithm, char **out);
+#endif
+
+static inline int string_hashsum_sha224(const char *s, size_t len, char **out) {
+#ifdef HAVE_GCRYPT
+ return string_hashsum(s, len, GCRY_MD_SHA224, out);
+#else
+ return -EOPNOTSUPP;
+#endif
+}
diff --git a/src/libshared/generator.c b/src/libshared/generator.c
index cd3c35cd55..70afc6a285 100644
--- a/src/libshared/generator.c
+++ b/src/libshared/generator.c
@@ -65,7 +65,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
"Description=File System Check on %2$s\n"
"DefaultDependencies=no\n"
"BindsTo=%3$s\n"
- "After=%3$s local-fs-pre.target\n"
+ "After=initrd-root-device.target local-fs-pre.target\n"
"Before=shutdown.target\n"
"\n"
"[Service]\n"
@@ -191,3 +191,17 @@ int generator_write_timeouts(
"[Unit]\nJobTimeoutSec=%s",
program_invocation_short_name, timeout);
}
+
+int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
+ _cleanup_free_ char *unit = NULL;
+ int r;
+
+ r = unit_name_from_path(what, ".device", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path: %m");
+
+ return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
+ "# Automatically generated by %s\n\n"
+ "[Unit]\nRequires=%s\nAfter=%s",
+ program_invocation_short_name, unit, unit);
+}
diff --git a/src/libshared/generator.h b/src/libshared/generator.h
index a734e13970..a6017c1b76 100644
--- a/src/libshared/generator.h
+++ b/src/libshared/generator.h
@@ -34,3 +34,7 @@ int generator_write_timeouts(
const char *where,
const char *opts,
char **filtered);
+
+int generator_write_initrd_root_device_deps(
+ const char *dir,
+ const char *what);
diff --git a/src/libshared/gpt.h b/src/libshared/gpt.h
index 9b8f59abee..07153b51f4 100644
--- a/src/libshared/gpt.h
+++ b/src/libshared/gpt.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <endian.h>
#include <systemd/sd-id128.h>
diff --git a/src/libshared/install-printf.h b/src/libshared/install-printf.h
index acf519f4f7..8a570fc265 100644
--- a/src/libshared/install-printf.h
+++ b/src/libshared/install-printf.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "install.h"
int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret);
diff --git a/src/libshared/install.c b/src/libshared/install.c
index ef8f485cae..64d66a45d3 100644
--- a/src/libshared/install.c
+++ b/src/libshared/install.c
@@ -40,11 +40,13 @@
#include "hashmap.h"
#include "install-printf.h"
#include "install.h"
+#include "locale-util.h"
#include "log.h"
#include "macro.h"
#include "mkdir.h"
#include "path-lookup.h"
#include "path-util.h"
+#include "rm-rf.h"
#include "set.h"
#include "special.h"
#include "stat-util.h"
@@ -65,7 +67,65 @@ typedef struct {
OrderedHashmap *have_processed;
} InstallContext;
-static int in_search_path(const char *path, char **search) {
+typedef enum {
+ PRESET_UNKNOWN,
+ PRESET_ENABLE,
+ PRESET_DISABLE,
+} PresetAction;
+
+typedef struct {
+ char *pattern;
+ PresetAction action;
+} PresetRule;
+
+typedef struct {
+ PresetRule *rules;
+ size_t n_rules;
+} Presets;
+
+static inline void presets_freep(Presets *p) {
+ size_t i;
+
+ if (!p)
+ return;
+
+ for (i = 0; i < p->n_rules; i++)
+ free(p->rules[i].pattern);
+
+ free(p->rules);
+ p->n_rules = 0;
+}
+
+static int unit_file_lookup_state(UnitFileScope scope, const LookupPaths *paths, const char *name, UnitFileState *ret);
+
+bool unit_type_may_alias(UnitType type) {
+ return IN_SET(type,
+ UNIT_SERVICE,
+ UNIT_SOCKET,
+ UNIT_TARGET,
+ UNIT_DEVICE,
+ UNIT_TIMER,
+ UNIT_PATH);
+}
+
+bool unit_type_may_template(UnitType type) {
+ return IN_SET(type,
+ UNIT_SERVICE,
+ UNIT_SOCKET,
+ UNIT_TARGET,
+ UNIT_TIMER,
+ UNIT_PATH);
+}
+
+static const char *unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
+ [UNIT_FILE_TYPE_REGULAR] = "regular",
+ [UNIT_FILE_TYPE_SYMLINK] = "symlink",
+ [UNIT_FILE_TYPE_MASKED] = "masked",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(unit_file_type, UnitFileType);
+
+static int in_search_path(const LookupPaths *p, const char *path) {
_cleanup_free_ char *parent = NULL;
char **i;
@@ -75,141 +135,141 @@ static int in_search_path(const char *path, char **search) {
if (!parent)
return -ENOMEM;
- STRV_FOREACH(i, search)
+ STRV_FOREACH(i, p->search_path)
if (path_equal(parent, *i))
return true;
return false;
}
-static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
- char *p = NULL;
- int r;
-
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(ret);
+static const char* skip_root(const LookupPaths *p, const char *path) {
+ char *e;
- /* This determines where we shall create or remove our
- * installation ("configuration") symlinks */
+ assert(p);
+ assert(path);
- switch (scope) {
+ if (!p->root_dir)
+ return path;
- case UNIT_FILE_SYSTEM:
+ e = path_startswith(path, p->root_dir);
+ if (!e)
+ return NULL;
- if (runtime)
- p = path_join(root_dir, "/run/systemd/system", NULL);
- else
- p = path_join(root_dir, SYSTEM_CONFIG_UNIT_PATH, NULL);
- break;
+ /* Make sure the returned path starts with a slash */
+ if (e[0] != '/') {
+ if (e == path || e[-1] != '/')
+ return NULL;
- case UNIT_FILE_GLOBAL:
+ e--;
+ }
- if (root_dir)
- return -EINVAL;
+ return e;
+}
- if (runtime)
- p = strdup("/run/systemd/user");
- else
- p = strdup(USER_CONFIG_UNIT_PATH);
- break;
+static int path_is_generator(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
- case UNIT_FILE_USER:
+ assert(p);
+ assert(path);
- if (root_dir)
- return -EINVAL;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
- if (runtime)
- r = user_runtime_dir(&p);
- else
- r = user_config_home(&p);
- if (r < 0)
- return r;
- if (r == 0)
- return -ENOENT;
+ return path_equal_ptr(parent, p->generator) ||
+ path_equal_ptr(parent, p->generator_early) ||
+ path_equal_ptr(parent, p->generator_late);
+}
- break;
+static int path_is_transient(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
- default:
- assert_not_reached("Bad scope");
- }
+ assert(p);
+ assert(path);
- if (!p)
+ parent = dirname_malloc(path);
+ if (!parent)
return -ENOMEM;
- *ret = p;
- return 0;
+ return path_equal_ptr(parent, p->transient);
}
-static bool is_config_path(UnitFileScope scope, const char *path) {
- int r;
+static int path_is_control(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(p);
assert(path);
- /* Checks whether the specified path is intended for
- * configuration or is outside of it */
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
- switch (scope) {
+ return path_equal_ptr(parent, p->persistent_control) ||
+ path_equal_ptr(parent, p->runtime_control);
+}
- case UNIT_FILE_SYSTEM:
- case UNIT_FILE_GLOBAL:
- return path_startswith(path, "/etc") ||
- path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) ||
- path_startswith(path, "/run");
+static int path_is_config(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
+ assert(p);
+ assert(path);
- case UNIT_FILE_USER: {
- _cleanup_free_ char *p = NULL;
+ /* Note that we do *not* have generic checks for /etc or /run in place, since with them we couldn't discern
+ * configuration from transient or generated units */
- r = user_config_home(&p);
- if (r < 0)
- return r;
- if (r > 0 && path_startswith(path, p))
- return true;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
- p = mfree(p);
+ return path_equal_ptr(parent, p->persistent_config) ||
+ path_equal_ptr(parent, p->runtime_config);
+}
- r = user_runtime_dir(&p);
- if (r < 0)
- return r;
- if (r > 0 && path_startswith(path, p))
- return true;
+static int path_is_runtime(const LookupPaths *p, const char *path) {
+ _cleanup_free_ char *parent = NULL;
+ const char *rpath;
- return false;
- }
+ assert(p);
+ assert(path);
- default:
- assert_not_reached("Bad scope");
- }
-}
+ /* Everything in /run is considered runtime. On top of that we also add explicit checks for the various runtime
+ * directories, as safety net. */
+ rpath = skip_root(p, path);
+ if (rpath && path_startswith(rpath, "/run"))
+ return true;
-static int verify_root_dir(UnitFileScope scope, const char **root_dir) {
- int r;
+ parent = dirname_malloc(path);
+ if (!parent)
+ return -ENOMEM;
+
+ return path_equal_ptr(parent, p->runtime_config) ||
+ path_equal_ptr(parent, p->generator) ||
+ path_equal_ptr(parent, p->generator_early) ||
+ path_equal_ptr(parent, p->generator_late) ||
+ path_equal_ptr(parent, p->transient) ||
+ path_equal_ptr(parent, p->runtime_control);
+}
- assert(root_dir);
+static int path_is_vendor(const LookupPaths *p, const char *path) {
+ const char *rpath;
- /* Verifies that the specified root directory to operate on
- * makes sense. Reset it to NULL if it is the root directory
- * or set to empty */
+ assert(p);
+ assert(path);
- if (isempty(*root_dir) || path_equal(*root_dir, "/")) {
- *root_dir = NULL;
+ rpath = skip_root(p, path);
+ if (!rpath)
return 0;
- }
- if (scope != UNIT_FILE_SYSTEM)
- return -EINVAL;
+ if (path_startswith(rpath, "/usr"))
+ return true;
- r = is_dir(*root_dir, true);
- if (r < 0)
- return r;
- if (r == 0)
- return -ENOTDIR;
+#ifdef HAVE_SPLIT_USR
+ if (path_startswith(rpath, "/lib"))
+ return true;
+#endif
- return 0;
+ return path_equal(rpath, SYSTEM_DATA_UNIT_PATH);
}
int unit_file_changes_add(
@@ -219,8 +279,8 @@ int unit_file_changes_add(
const char *path,
const char *source) {
+ _cleanup_free_ char *p = NULL, *s = NULL;
UnitFileChange *c;
- unsigned i;
assert(path);
assert(!changes == !n_changes);
@@ -231,29 +291,22 @@ int unit_file_changes_add(
c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange));
if (!c)
return -ENOMEM;
-
*changes = c;
- i = *n_changes;
-
- c[i].type = type;
- c[i].path = strdup(path);
- if (!c[i].path)
- return -ENOMEM;
- path_kill_slashes(c[i].path);
+ p = strdup(path);
+ if (source)
+ s = strdup(source);
- if (source) {
- c[i].source = strdup(source);
- if (!c[i].source) {
- free(c[i].path);
- return -ENOMEM;
- }
+ if (!p || (source && !s))
+ return -ENOMEM;
- path_kill_slashes(c[i].path);
- } else
- c[i].source = NULL;
+ path_kill_slashes(p);
+ if (s)
+ path_kill_slashes(s);
- *n_changes = i+1;
+ c[*n_changes] = (UnitFileChange) { type, p, s };
+ p = s = NULL;
+ (*n_changes) ++;
return 0;
}
@@ -262,9 +315,6 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
assert(changes || n_changes == 0);
- if (!changes)
- return;
-
for (i = 0; i < n_changes; i++) {
free(changes[i].path);
free(changes[i].source);
@@ -273,6 +323,76 @@ void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) {
free(changes);
}
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet) {
+ unsigned i;
+ bool logged = false;
+
+ assert(changes || n_changes == 0);
+ /* If verb is not specified, errors are not allowed! */
+ assert(verb || r >= 0);
+
+ for (i = 0; i < n_changes; i++) {
+ assert(verb || changes[i].type >= 0);
+
+ switch(changes[i].type) {
+ case UNIT_FILE_SYMLINK:
+ if (!quiet)
+ log_info("Created symlink %s %s %s.",
+ changes[i].path,
+ special_glyph(ARROW),
+ changes[i].source);
+ break;
+ case UNIT_FILE_UNLINK:
+ if (!quiet)
+ log_info("Removed %s.", changes[i].path);
+ break;
+ case UNIT_FILE_IS_MASKED:
+ if (!quiet)
+ log_info("Unit %s is masked, ignoring.", changes[i].path);
+ break;
+ case UNIT_FILE_IS_DANGLING:
+ if (!quiet)
+ log_info("Unit %s is an alias to a unit that is not present, ignoring.",
+ changes[i].path);
+ break;
+ case -EEXIST:
+ if (changes[i].source)
+ log_error_errno(changes[i].type,
+ "Failed to %s unit, file %s already exists and is a symlink to %s.",
+ verb, changes[i].path, changes[i].source);
+ else
+ log_error_errno(changes[i].type,
+ "Failed to %s unit, file %s already exists.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -ERFKILL:
+ log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -EADDRNOTAVAIL:
+ log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ case -ELOOP:
+ log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s",
+ verb, changes[i].path);
+ logged = true;
+ break;
+ default:
+ assert(changes[i].type < 0);
+ log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.",
+ verb, changes[i].path);
+ logged = true;
+ }
+ }
+
+ if (r < 0 && !logged)
+ log_error_errno(r, "Failed to %s: %m.", verb);
+}
+
static int create_symlink(
const char *old_path,
const char *new_path,
@@ -288,36 +408,52 @@ static int create_symlink(
/* Actually create a symlink, and remember that we did. Is
* smart enough to check if there's already a valid symlink in
- * place. */
+ * place.
+ *
+ * Returns 1 if a symlink was created or already exists and points to
+ * the right place, or negative on error.
+ */
mkdir_parents_label(new_path, 0755);
if (symlink(old_path, new_path) >= 0) {
unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
- return 0;
+ return 1;
}
- if (errno != EEXIST)
+ if (errno != EEXIST) {
+ unit_file_changes_add(changes, n_changes, -errno, new_path, NULL);
return -errno;
+ }
r = readlink_malloc(new_path, &dest);
- if (r < 0)
+ if (r < 0) {
+ /* translate EINVAL (non-symlink exists) to EEXIST */
+ if (r == -EINVAL)
+ r = -EEXIST;
+
+ unit_file_changes_add(changes, n_changes, r, new_path, NULL);
return r;
+ }
if (path_equal(dest, old_path))
- return 0;
+ return 1;
- if (!force)
+ if (!force) {
+ unit_file_changes_add(changes, n_changes, -EEXIST, new_path, dest);
return -EEXIST;
+ }
r = symlink_atomic(old_path, new_path);
- if (r < 0)
+ if (r < 0) {
+ unit_file_changes_add(changes, n_changes, r, new_path, NULL);
return r;
+ }
unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL);
unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path);
- return 0;
+ return 1;
}
static int mark_symlink_for_removal(
@@ -353,6 +489,7 @@ static int remove_marked_symlinks_fd(
int fd,
const char *path,
const char *config_path,
+ const LookupPaths *lp,
bool *restart,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -365,6 +502,7 @@ static int remove_marked_symlinks_fd(
assert(fd >= 0);
assert(path);
assert(config_path);
+ assert(lp);
assert(restart);
d = fdopendir(fd);
@@ -400,12 +538,13 @@ static int remove_marked_symlinks_fd(
}
/* This will close nfd, regardless whether it succeeds or not */
- q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes);
+ q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, lp, restart, changes, n_changes);
if (q < 0 && r == 0)
r = q;
} else if (de->d_type == DT_LNK) {
_cleanup_free_ char *p = NULL, *dest = NULL;
+ const char *rp;
bool found;
int q;
@@ -415,42 +554,43 @@ static int remove_marked_symlinks_fd(
p = path_make_absolute(de->d_name, path);
if (!p)
return -ENOMEM;
+ path_kill_slashes(p);
q = readlink_malloc(p, &dest);
+ if (q == -ENOENT)
+ continue;
if (q < 0) {
- if (q == -ENOENT)
- continue;
-
if (r == 0)
r = q;
continue;
}
- /* We remove all links pointing to a file or
- * path that is marked, as well as all files
- * sharing the same name as a file that is
- * marked. */
+ /* We remove all links pointing to a file or path that is marked, as well as all files sharing
+ * the same name as a file that is marked. */
- found =
- set_contains(remove_symlinks_to, dest) ||
+ found = set_contains(remove_symlinks_to, dest) ||
set_contains(remove_symlinks_to, basename(dest)) ||
set_contains(remove_symlinks_to, de->d_name);
if (!found)
continue;
- if (unlink(p) < 0 && errno != ENOENT) {
+ if (unlinkat(fd, de->d_name, 0) < 0 && errno != ENOENT) {
if (r == 0)
r = -errno;
+ unit_file_changes_add(changes, n_changes, -errno, p, NULL);
continue;
}
- path_kill_slashes(p);
(void) rmdir_parents(p, config_path);
unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL);
- q = mark_symlink_for_removal(&remove_symlinks_to, p);
+ /* Now, remember the full path (but with the root prefix removed) of
+ * the symlink we just removed, and remove any symlinks to it, too. */
+
+ rp = skip_root(lp, p);
+ q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: p);
if (q < 0)
return q;
if (q > 0)
@@ -464,6 +604,7 @@ static int remove_marked_symlinks_fd(
static int remove_marked_symlinks(
Set *remove_symlinks_to,
const char *config_path,
+ const LookupPaths *lp,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -472,6 +613,7 @@ static int remove_marked_symlinks(
int r = 0;
assert(config_path);
+ assert(lp);
if (set_size(remove_symlinks_to) <= 0)
return 0;
@@ -489,7 +631,7 @@ static int remove_marked_symlinks(
return -errno;
/* This takes possession of cfd and closes it */
- q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes);
+ q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, lp, &restart, changes, n_changes);
if (r == 0)
r = q;
} while (restart);
@@ -503,6 +645,7 @@ static int find_symlinks_fd(
int fd,
const char *path,
const char *config_path,
+ const LookupPaths *lp,
bool *same_name_link) {
_cleanup_closedir_ DIR *d = NULL;
@@ -513,6 +656,7 @@ static int find_symlinks_fd(
assert(fd >= 0);
assert(path);
assert(config_path);
+ assert(lp);
assert(same_name_link);
d = fdopendir(fd);
@@ -546,7 +690,7 @@ static int find_symlinks_fd(
}
/* This will close nfd, regardless whether it succeeds or not */
- q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link);
+ q = find_symlinks_fd(root_dir, name, nfd, p, config_path, lp, same_name_link);
if (q > 0)
return 1;
if (r == 0)
@@ -624,6 +768,7 @@ static int find_symlinks(
const char *root_dir,
const char *name,
const char *config_path,
+ const LookupPaths *lp,
bool *same_name_link) {
int fd;
@@ -640,29 +785,25 @@ static int find_symlinks(
}
/* This takes possession of fd and closes it */
- return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link);
+ return find_symlinks_fd(root_dir, name, fd, config_path, config_path, lp, same_name_link);
}
static int find_symlinks_in_scope(
UnitFileScope scope,
- const char *root_dir,
+ const LookupPaths *paths,
const char *name,
UnitFileState *state) {
- _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL;
bool same_name_link_runtime = false, same_name_link = false;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
+ assert(paths);
assert(name);
- /* First look in the normal config path */
- r = get_config_path(scope, false, root_dir, &normal_path);
- if (r < 0)
- return r;
-
- r = find_symlinks(root_dir, name, normal_path, &same_name_link);
+ /* First look in the persistent config path */
+ r = find_symlinks(paths->root_dir, name, paths->persistent_config, paths, &same_name_link);
if (r < 0)
return r;
if (r > 0) {
@@ -671,11 +812,7 @@ static int find_symlinks_in_scope(
}
/* Then look in runtime config path */
- r = get_config_path(scope, true, root_dir, &runtime_path);
- if (r < 0)
- return r;
-
- r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime);
+ r = find_symlinks(paths->root_dir, name, paths->runtime_config, paths, &same_name_link_runtime);
if (r < 0)
return r;
if (r > 0) {
@@ -742,6 +879,30 @@ static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *nam
return ordered_hashmap_get(c->will_process, name);
}
+static int install_info_may_process(
+ UnitFileInstallInfo *i,
+ const LookupPaths *paths,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
+ assert(i);
+ assert(paths);
+
+ /* Checks whether the loaded unit file is one we should process, or is masked, transient or generated and thus
+ * not subject to enable/disable operations. */
+
+ if (i->type == UNIT_FILE_TYPE_MASKED) {
+ unit_file_changes_add(changes, n_changes, -ERFKILL, i->path, NULL);
+ return -ERFKILL;
+ }
+ if (path_is_generator(paths, i->path) ||
+ path_is_transient(paths, i->path)) {
+ unit_file_changes_add(changes, n_changes, -EADDRNOTAVAIL, i->path, NULL);
+ return -EADDRNOTAVAIL;
+ }
+
+ return 0;
+}
+
static int install_info_add(
InstallContext *c,
const char *name,
@@ -804,18 +965,34 @@ fail:
return r;
}
-static int install_info_add_auto(
- InstallContext *c,
- const char *name_or_path,
- UnitFileInstallInfo **ret) {
+static int config_parse_alias(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
- assert(c);
- assert(name_or_path);
+ const char *name;
+ UnitType type;
- if (path_is_absolute(name_or_path))
- return install_info_add(c, NULL, name_or_path, ret);
- else
- return install_info_add(c, name_or_path, NULL, ret);
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ name = basename(filename);
+ type = unit_name_to_type(name);
+ if (!unit_type_may_alias(type))
+ return log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Aliases are not allowed for %s units, ignoring.",
+ unit_type_to_string(type));
+
+ return config_parse_strv(unit, filename, line, section, section_line,
+ lvalue, ltype, rvalue, data, userdata);
}
static int config_parse_also(
@@ -874,6 +1051,7 @@ static int config_parse_default_instance(
void *userdata) {
UnitFileInstallInfo *i = data;
+ const char *name;
char *printed;
int r;
@@ -881,6 +1059,15 @@ static int config_parse_default_instance(
assert(lvalue);
assert(rvalue);
+ name = basename(filename);
+ if (unit_name_is_valid(name, UNIT_NAME_INSTANCE))
+ /* When enabling an instance, we might be using a template unit file,
+ * but we should ignore DefaultInstance silently. */
+ return 0;
+ if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
+ return log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "DefaultInstance only makes sense for template units, ignoring.");
+
r = install_full_printf(i, rvalue, &printed);
if (r < 0)
return r;
@@ -900,11 +1087,10 @@ static int unit_file_load(
InstallContext *c,
UnitFileInstallInfo *info,
const char *path,
- const char *root_dir,
SearchFlags flags) {
const ConfigTableItem items[] = {
- { "Install", "Alias", config_parse_strv, 0, &info->aliases },
+ { "Install", "Alias", config_parse_alias, 0, &info->aliases },
{ "Install", "WantedBy", config_parse_strv, 0, &info->wanted_by },
{ "Install", "RequiredBy", config_parse_strv, 0, &info->required_by },
{ "Install", "DefaultInstance", config_parse_default_instance, 0, info },
@@ -912,6 +1098,8 @@ static int unit_file_load(
{}
};
+ const char *name;
+ UnitType type;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_close_ int fd = -1;
struct stat st;
@@ -921,7 +1109,11 @@ static int unit_file_load(
assert(info);
assert(path);
- path = prefix_roota(root_dir, path);
+ name = basename(path);
+ type = unit_name_to_type(name);
+ if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
+ !unit_type_may_template(type))
+ return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type));
if (!(flags & SEARCH_LOAD)) {
r = lstat(path, &st);
@@ -983,26 +1175,26 @@ static int unit_file_load_or_readlink(
const char *root_dir,
SearchFlags flags) {
- _cleanup_free_ char *np = NULL;
+ _cleanup_free_ char *target = NULL;
int r;
- r = unit_file_load(c, info, path, root_dir, flags);
+ r = unit_file_load(c, info, path, flags);
if (r != -ELOOP)
return r;
/* This is a symlink, let's read it. */
- r = readlink_and_make_absolute_root(root_dir, path, &np);
+ r = readlink_malloc(path, &target);
if (r < 0)
return r;
- if (path_equal(np, "/dev/null"))
+ if (path_equal(target, "/dev/null"))
info->type = UNIT_FILE_TYPE_MASKED;
else {
const char *bn;
UnitType a, b;
- bn = basename(np);
+ bn = basename(target);
if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) {
@@ -1029,9 +1221,16 @@ static int unit_file_load_or_readlink(
if (a < 0 || b < 0 || a != b)
return -EINVAL;
+ if (path_is_absolute(target))
+ /* This is an absolute path, prefix the root so that we always deal with fully qualified paths */
+ info->symlink_target = prefix_root(root_dir, target);
+ else
+ /* This is a relative path, take it relative to the dir the symlink is located in. */
+ info->symlink_target = file_in_same_dir(path, target);
+ if (!info->symlink_target)
+ return -ENOMEM;
+
info->type = UNIT_FILE_TYPE_SYMLINK;
- info->symlink_target = np;
- np = NULL;
}
return 0;
@@ -1041,9 +1240,9 @@ static int unit_file_search(
InstallContext *c,
UnitFileInstallInfo *info,
const LookupPaths *paths,
- const char *root_dir,
SearchFlags flags) {
+ _cleanup_free_ char *template = NULL;
char **p;
int r;
@@ -1056,59 +1255,53 @@ static int unit_file_search(
return 0;
if (info->path)
- return unit_file_load_or_readlink(c, info, info->path, root_dir, flags);
+ return unit_file_load_or_readlink(c, info, info->path, paths->root_dir, flags);
assert(info->name);
- STRV_FOREACH(p, paths->unit_path) {
+ STRV_FOREACH(p, paths->search_path) {
_cleanup_free_ char *path = NULL;
path = strjoin(*p, "/", info->name, NULL);
if (!path)
return -ENOMEM;
- r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
- if (r < 0) {
- if (r != -ENOENT)
- return r;
- } else {
+ r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
+ if (r >= 0) {
info->path = path;
path = NULL;
return r;
- }
+ } else if (r != -ENOENT)
+ return r;
}
if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
-
/* Unit file doesn't exist, however instance
* enablement was requested. We will check if it is
* possible to load template unit file. */
- _cleanup_free_ char *template = NULL;
-
r = unit_name_template(info->name, &template);
if (r < 0)
return r;
- STRV_FOREACH(p, paths->unit_path) {
+ STRV_FOREACH(p, paths->search_path) {
_cleanup_free_ char *path = NULL;
path = strjoin(*p, "/", template, NULL);
if (!path)
return -ENOMEM;
- r = unit_file_load_or_readlink(c, info, path, root_dir, flags);
- if (r < 0) {
- if (r != -ENOENT)
- return r;
- } else {
+ r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
+ if (r >= 0) {
info->path = path;
path = NULL;
return r;
- }
+ } else if (r != -ENOENT)
+ return r;
}
}
+ log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
return -ENOENT;
}
@@ -1140,10 +1333,14 @@ static int install_info_follow(
return unit_file_load_or_readlink(c, i, i->path, root_dir, flags);
}
+/**
+ * Search for the unit file. If the unit name is a symlink,
+ * follow the symlink to the target, maybe more than once.
+ * Propagate the instance name if present.
+ */
static int install_info_traverse(
UnitFileScope scope,
InstallContext *c,
- const char *root_dir,
const LookupPaths *paths,
UnitFileInstallInfo *start,
SearchFlags flags,
@@ -1157,7 +1354,7 @@ static int install_info_traverse(
assert(start);
assert(c);
- r = unit_file_search(c, start, paths, root_dir, flags);
+ r = unit_file_search(c, start, paths, flags);
if (r < 0)
return r;
@@ -1168,17 +1365,19 @@ static int install_info_traverse(
if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX)
return -ELOOP;
- if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path))
- return -ELOOP;
+ if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS)) {
+ r = path_is_config(paths, i->path);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ return -ELOOP;
+ }
- r = install_info_follow(c, i, root_dir, flags);
- if (r < 0) {
+ r = install_info_follow(c, i, paths->root_dir, flags);
+ if (r == -EXDEV) {
_cleanup_free_ char *buffer = NULL;
const char *bn;
- if (r != -EXDEV)
- return r;
-
/* Target has a different name, create a new
* install info object for that, and continue
* with that. */
@@ -1205,12 +1404,15 @@ static int install_info_traverse(
if (r < 0)
return r;
- r = unit_file_search(c, i, paths, root_dir, flags);
- if (r < 0)
- return r;
+ /* Try again, with the new target we found. */
+ r = unit_file_search(c, i, paths, flags);
+ if (r == -ENOENT)
+ /* Translate error code to highlight this specific case */
+ return -ENOLINK;
}
- /* Try again, with the new target we found. */
+ if (r < 0)
+ return r;
}
if (ret)
@@ -1219,10 +1421,28 @@ static int install_info_traverse(
return 0;
}
+static int install_info_add_auto(
+ InstallContext *c,
+ const LookupPaths *paths,
+ const char *name_or_path,
+ UnitFileInstallInfo **ret) {
+
+ assert(c);
+ assert(name_or_path);
+
+ if (path_is_absolute(name_or_path)) {
+ const char *pp;
+
+ pp = prefix_roota(paths->root_dir, name_or_path);
+
+ return install_info_add(c, NULL, pp, ret);
+ } else
+ return install_info_add(c, name_or_path, NULL, ret);
+}
+
static int install_info_discover(
UnitFileScope scope,
InstallContext *c,
- const char *root_dir,
const LookupPaths *paths,
const char *name,
SearchFlags flags,
@@ -1235,15 +1455,16 @@ static int install_info_discover(
assert(paths);
assert(name);
- r = install_info_add_auto(c, name, &i);
+ r = install_info_add_auto(c, paths, name, &i);
if (r < 0)
return r;
- return install_info_traverse(scope, c, root_dir, paths, i, flags, ret);
+ return install_info_traverse(scope, c, paths, i, flags, ret);
}
static int install_info_symlink_alias(
UnitFileInstallInfo *i,
+ const LookupPaths *paths,
const char *config_path,
bool force,
UnitFileChange **changes,
@@ -1253,10 +1474,12 @@ static int install_info_symlink_alias(
int r = 0, q;
assert(i);
+ assert(paths);
assert(config_path);
STRV_FOREACH(s, i->aliases) {
_cleanup_free_ char *alias_path = NULL, *dst = NULL;
+ const char *rp;
q = install_full_printf(i, *s, &dst);
if (q < 0)
@@ -1266,7 +1489,9 @@ static int install_info_symlink_alias(
if (!alias_path)
return -ENOMEM;
- q = create_symlink(i->path, alias_path, force, changes, n_changes);
+ rp = skip_root(paths, i->path);
+
+ q = create_symlink(rp ?: i->path, alias_path, force, changes, n_changes);
if (r == 0)
r = q;
}
@@ -1276,10 +1501,10 @@ static int install_info_symlink_alias(
static int install_info_symlink_wants(
UnitFileInstallInfo *i,
+ const LookupPaths *paths,
const char *config_path,
char **list,
const char *suffix,
- bool force,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -1289,6 +1514,7 @@ static int install_info_symlink_wants(
int r = 0, q;
assert(i);
+ assert(paths);
assert(config_path);
if (unit_name_is_valid(i->name, UNIT_NAME_TEMPLATE)) {
@@ -1309,6 +1535,7 @@ static int install_info_symlink_wants(
STRV_FOREACH(s, list) {
_cleanup_free_ char *path = NULL, *dst = NULL;
+ const char *rp;
q = install_full_printf(i, *s, &dst);
if (q < 0)
@@ -1323,7 +1550,9 @@ static int install_info_symlink_wants(
if (!path)
return -ENOMEM;
- q = create_symlink(i->path, path, force, changes, n_changes);
+ rp = skip_root(paths, i->path);
+
+ q = create_symlink(rp ?: i->path, path, true, changes, n_changes);
if (r == 0)
r = q;
}
@@ -1335,12 +1564,12 @@ static int install_info_symlink_link(
UnitFileInstallInfo *i,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
_cleanup_free_ char *path = NULL;
+ const char *rp;
int r;
assert(i);
@@ -1348,22 +1577,25 @@ static int install_info_symlink_link(
assert(config_path);
assert(i->path);
- r = in_search_path(i->path, paths->unit_path);
- if (r != 0)
+ r = in_search_path(paths, i->path);
+ if (r < 0)
return r;
+ if (r > 0)
+ return 0;
path = strjoin(config_path, "/", i->name, NULL);
if (!path)
return -ENOMEM;
- return create_symlink(i->path, path, force, changes, n_changes);
+ rp = skip_root(paths, i->path);
+
+ return create_symlink(rp ?: i->path, path, force, changes, n_changes);
}
static int install_info_apply(
UnitFileInstallInfo *i,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
bool force,
UnitFileChange **changes,
unsigned *n_changes) {
@@ -1377,18 +1609,19 @@ static int install_info_apply(
if (i->type != UNIT_FILE_TYPE_REGULAR)
return 0;
- r = install_info_symlink_alias(i, config_path, force, changes, n_changes);
+ r = install_info_symlink_alias(i, paths, config_path, force, changes, n_changes);
- q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes);
+ q = install_info_symlink_wants(i, paths, config_path, i->wanted_by, ".wants/", changes, n_changes);
if (r == 0)
r = q;
- q = install_info_symlink_wants(i, config_path, i->required_by, ".requires/", force, changes, n_changes);
+ q = install_info_symlink_wants(i, paths, config_path, i->required_by, ".requires/", changes, n_changes);
if (r == 0)
r = q;
- q = install_info_symlink_link(i, paths, config_path, root_dir, force, changes, n_changes);
- if (r == 0)
+ q = install_info_symlink_link(i, paths, config_path, force, changes, n_changes);
+ /* Do not count links to the unit file towards the "carries_install_info" count */
+ if (r == 0 && q < 0)
r = q;
return r;
@@ -1399,7 +1632,6 @@ static int install_context_apply(
InstallContext *c,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
bool force,
SearchFlags flags,
UnitFileChange **changes,
@@ -1427,19 +1659,19 @@ static int install_context_apply(
if (q < 0)
return q;
- r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL);
+ r = install_info_traverse(scope, c, paths, i, flags, NULL);
if (r < 0)
return r;
if (i->type != UNIT_FILE_TYPE_REGULAR)
continue;
- q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes);
+ q = install_info_apply(i, paths, config_path, force, changes, n_changes);
if (r >= 0) {
if (q < 0)
r = q;
else
- r+= q;
+ r += q;
}
}
@@ -1451,8 +1683,7 @@ static int install_context_mark_for_removal(
InstallContext *c,
const LookupPaths *paths,
Set **remove_symlinks_to,
- const char *config_path,
- const char *root_dir) {
+ const char *config_path) {
UnitFileInstallInfo *i;
int r;
@@ -1476,12 +1707,18 @@ static int install_context_mark_for_removal(
if (r < 0)
return r;
- r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
- if (r < 0)
+ r = install_info_traverse(scope, c, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL);
+ if (r == -ENOLINK)
+ return 0;
+ else if (r < 0)
return r;
- if (i->type != UNIT_FILE_TYPE_REGULAR)
+ if (i->type != UNIT_FILE_TYPE_REGULAR) {
+ log_debug("Unit %s has type %s, ignoring.",
+ i->name,
+ unit_file_type_to_string(i->type) ?: "invalid");
continue;
+ }
r = mark_symlink_for_removal(remove_symlinks_to, i->name);
if (r < 0)
@@ -1500,20 +1737,19 @@ int unit_file_mask(
UnitFileChange **changes,
unsigned *n_changes) {
- _cleanup_free_ char *prefix = NULL;
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ const char *config_path;
char **i;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &prefix);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
_cleanup_free_ char *path = NULL;
@@ -1525,7 +1761,7 @@ int unit_file_mask(
continue;
}
- path = path_make_absolute(*i, prefix);
+ path = path_make_absolute(*i, config_path);
if (!path)
return -ENOMEM;
@@ -1545,23 +1781,22 @@ int unit_file_unmask(
UnitFileChange **changes,
unsigned *n_changes) {
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- _cleanup_free_ char *config_path = NULL;
_cleanup_free_ char **todo = NULL;
size_t n_todo = 0, n_allocated = 0;
+ const char *config_path;
char **i;
int r, q;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
_cleanup_free_ char *path = NULL;
@@ -1592,24 +1827,31 @@ int unit_file_unmask(
r = 0;
STRV_FOREACH(i, todo) {
_cleanup_free_ char *path = NULL;
+ const char *rp;
path = path_make_absolute(*i, config_path);
if (!path)
return -ENOMEM;
if (unlink(path) < 0) {
- if (errno != -ENOENT && r >= 0)
- r = -errno;
- } else {
- q = mark_symlink_for_removal(&remove_symlinks_to, path);
- if (q < 0)
- return q;
+ if (errno != ENOENT) {
+ if (r >= 0)
+ r = -errno;
+ unit_file_changes_add(changes, n_changes, -errno, path, NULL);
+ }
- unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+ continue;
}
+
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL);
+
+ rp = skip_root(&paths, path);
+ q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: path);
+ if (q < 0)
+ return q;
}
- q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ q = remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
if (r >= 0)
r = q;
@@ -1626,26 +1868,20 @@ int unit_file_link(
unsigned *n_changes) {
_cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
_cleanup_free_ char **todo = NULL;
size_t n_todo = 0, n_allocated = 0;
+ const char *config_path;
char **i;
int r, q;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
_cleanup_free_ char *full = NULL;
@@ -1659,7 +1895,7 @@ int unit_file_link(
if (!unit_name_is_valid(fn, UNIT_NAME_ANY))
return -EINVAL;
- full = prefix_root(root_dir, *i);
+ full = prefix_root(paths.root_dir, *i);
if (!full)
return -ENOMEM;
@@ -1672,7 +1908,7 @@ int unit_file_link(
if (!S_ISREG(st.st_mode))
return -ENOTTY;
- q = in_search_path(*i, paths.unit_path);
+ q = in_search_path(&paths, *i);
if (q < 0)
return q;
if (q > 0)
@@ -1688,13 +1924,15 @@ int unit_file_link(
r = 0;
STRV_FOREACH(i, todo) {
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *new_path = NULL;
+ const char *old_path;
- path = path_make_absolute(basename(*i), config_path);
- if (!path)
+ old_path = skip_root(&paths, *i);
+ new_path = path_make_absolute(basename(*i), config_path);
+ if (!new_path)
return -ENOMEM;
- q = create_symlink(*i, path, force, changes, n_changes);
+ q = create_symlink(old_path ?: *i, new_path, force, changes, n_changes);
if (q < 0 && r >= 0)
r = q;
}
@@ -1702,6 +1940,182 @@ int unit_file_link(
return r;
}
+static int path_shall_revert(const LookupPaths *paths, const char *path) {
+ int r;
+
+ assert(paths);
+ assert(path);
+
+ /* Checks whether the path is one where the drop-in directories shall be removed. */
+
+ r = path_is_config(paths, path);
+ if (r != 0)
+ return r;
+
+ r = path_is_control(paths, path);
+ if (r != 0)
+ return r;
+
+ return path_is_transient(paths, path);
+}
+
+int unit_file_revert(
+ UnitFileScope scope,
+ const char *root_dir,
+ char **files,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
+
+ _cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+ /* _cleanup_(install_context_done) InstallContext c = {}; */
+ _cleanup_lookup_paths_free_ LookupPaths paths = {};
+ _cleanup_strv_free_ char **todo = NULL;
+ size_t n_todo = 0, n_allocated = 0;
+ char **i;
+ int r, q;
+
+ /* Puts a unit file back into vendor state. This means:
+ *
+ * a) we remove all drop-in snippets added by the user ("config"), add to transient units ("transient"), and
+ * added via "systemctl set-property" ("control"), but not if the drop-in is generated ("generated").
+ *
+ * c) if there's a vendor unit file (i.e. one in /usr) we remove any configured overriding unit files (i.e. in
+ * "config", but not in "transient" or "control" or even "generated").
+ *
+ * We remove all that in both the runtime and the persistent directories, if that applies.
+ */
+
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(i, files) {
+ bool has_vendor = false;
+ char **p;
+
+ if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ STRV_FOREACH(p, paths.search_path) {
+ _cleanup_free_ char *path = NULL, *dropin = NULL;
+ struct stat st;
+
+ path = path_make_absolute(*i, *p);
+ if (!path)
+ return -ENOMEM;
+
+ r = lstat(path, &st);
+ if (r < 0) {
+ if (errno != ENOENT)
+ return -errno;
+ } else if (S_ISREG(st.st_mode)) {
+ /* Check if there's a vendor version */
+ r = path_is_vendor(&paths, path);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ has_vendor = true;
+ }
+
+ dropin = strappend(path, ".d");
+ if (!dropin)
+ return -ENOMEM;
+
+ r = lstat(dropin, &st);
+ if (r < 0) {
+ if (errno != ENOENT)
+ return -errno;
+ } else if (S_ISDIR(st.st_mode)) {
+ /* Remove the drop-ins */
+ r = path_shall_revert(&paths, dropin);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+ return -ENOMEM;
+
+ todo[n_todo++] = dropin;
+ dropin = NULL;
+ }
+ }
+ }
+
+ if (!has_vendor)
+ continue;
+
+ /* OK, there's a vendor version, hence drop all configuration versions */
+ STRV_FOREACH(p, paths.search_path) {
+ _cleanup_free_ char *path = NULL;
+ struct stat st;
+
+ path = path_make_absolute(*i, *p);
+ if (!path)
+ return -ENOMEM;
+
+ r = lstat(path, &st);
+ if (r < 0) {
+ if (errno != ENOENT)
+ return -errno;
+ } else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
+ r = path_is_config(&paths, path);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2))
+ return -ENOMEM;
+
+ todo[n_todo++] = path;
+ path = NULL;
+ }
+ }
+ }
+ }
+
+ strv_uniq(todo);
+
+ r = 0;
+ STRV_FOREACH(i, todo) {
+ _cleanup_strv_free_ char **fs = NULL;
+ const char *rp;
+ char **j;
+
+ (void) get_files_in_directory(*i, &fs);
+
+ q = rm_rf(*i, REMOVE_ROOT|REMOVE_PHYSICAL);
+ if (q < 0 && q != -ENOENT && r >= 0) {
+ r = q;
+ continue;
+ }
+
+ STRV_FOREACH(j, fs) {
+ _cleanup_free_ char *t = NULL;
+
+ t = strjoin(*i, "/", *j, NULL);
+ if (!t)
+ return -ENOMEM;
+
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, t, NULL);
+ }
+
+ unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, *i, NULL);
+
+ rp = skip_root(&paths, *i);
+ q = mark_symlink_for_removal(&remove_symlinks_to, rp ?: *i);
+ if (q < 0)
+ return q;
+ }
+
+ q = remove_marked_symlinks(remove_symlinks_to, paths.runtime_config, &paths, changes, n_changes);
+ if (r >= 0)
+ r = q;
+
+ q = remove_marked_symlinks(remove_symlinks_to, paths.persistent_config, &paths, changes, n_changes);
+ if (r >= 0)
+ r = q;
+
+ return r;
+}
+
int unit_file_add_dependency(
UnitFileScope scope,
bool runtime,
@@ -1715,8 +2129,8 @@ int unit_file_add_dependency(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
UnitFileInstallInfo *i, *target_info;
+ const char *config_path;
char **f;
int r;
@@ -1730,34 +2144,30 @@ int unit_file_add_dependency(
if (!unit_name_is_valid(target, UNIT_NAME_ANY))
return -EINVAL;
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
- r = get_config_path(scope, runtime, root_dir, &config_path);
+ r = install_info_discover(scope, &c, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
if (r < 0)
return r;
-
- r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info);
+ r = install_info_may_process(target_info, &paths, changes, n_changes);
if (r < 0)
return r;
- if (target_info->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
assert(target_info->type == UNIT_FILE_TYPE_REGULAR);
STRV_FOREACH(f, files) {
char ***l;
- r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, &c, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ if (r < 0)
+ return r;
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
assert(i->type == UNIT_FILE_TYPE_REGULAR);
@@ -1776,7 +2186,7 @@ int unit_file_add_dependency(
return -ENOMEM;
}
- return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
+ return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes);
}
int unit_file_enable(
@@ -1790,7 +2200,7 @@ int unit_file_enable(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
+ const char *config_path;
UnitFileInstallInfo *i;
char **f;
int r;
@@ -1798,24 +2208,19 @@ int unit_file_enable(
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(f, files) {
- r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i);
+ r = install_info_discover(scope, &c, &paths, *f, SEARCH_LOAD, &i);
+ if (r < 0)
+ return r;
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
assert(i->type == UNIT_FILE_TYPE_REGULAR);
}
@@ -1825,7 +2230,7 @@ int unit_file_enable(
is useful to determine whether the passed files had any
installation data at all. */
- return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
+ return install_context_apply(scope, &c, &paths, config_path, force, SEARCH_LOAD, changes, n_changes);
}
int unit_file_disable(
@@ -1838,25 +2243,19 @@ int unit_file_disable(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
+ const char *config_path;
char **i;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, runtime, root_dir, &config_path);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
STRV_FOREACH(i, files) {
if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
@@ -1867,11 +2266,11 @@ int unit_file_disable(
return r;
}
- r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir);
+ r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path);
if (r < 0)
return r;
- return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ return remove_marked_symlinks(remove_symlinks_to, config_path, &paths, changes, n_changes);
}
int unit_file_reenable(
@@ -1912,41 +2311,34 @@ int unit_file_set_default(
_cleanup_lookup_paths_free_ LookupPaths paths = {};
_cleanup_(install_context_done) InstallContext c = {};
- _cleanup_free_ char *config_path = NULL;
UnitFileInstallInfo *i;
- const char *path;
+ const char *new_path, *old_path;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- if (unit_name_to_type(name) != UNIT_TARGET)
+ if (unit_name_to_type(name) != UNIT_TARGET) /* this also validates the name */
return -EINVAL;
if (streq(name, SPECIAL_DEFAULT_TARGET))
return -EINVAL;
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = get_config_path(scope, false, root_dir, &config_path);
+ r = install_info_discover(scope, &c, &paths, name, 0, &i);
if (r < 0)
return r;
-
- r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i);
+ r = install_info_may_process(i, &paths, changes, n_changes);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
- path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET);
+ old_path = skip_root(&paths, i->path);
+ new_path = strjoina(paths.persistent_config, "/" SPECIAL_DEFAULT_TARGET);
- return create_symlink(i->path, path, force, changes, n_changes);
+ return create_symlink(old_path ?: i->path, new_path, force, changes, n_changes);
}
int unit_file_get_default(
@@ -1964,19 +2356,16 @@ int unit_file_get_default(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ r = install_info_discover(scope, &c, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
-
- r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_may_process(i, &paths, NULL, 0);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
n = strdup(i->name);
if (!n)
@@ -1986,9 +2375,8 @@ int unit_file_get_default(
return 0;
}
-int unit_file_lookup_state(
+static int unit_file_lookup_state(
UnitFileScope scope,
- const char *root_dir,
const LookupPaths *paths,
const char *name,
UnitFileState *ret) {
@@ -2004,11 +2392,7 @@ int unit_file_lookup_state(
if (!unit_name_is_valid(name, UNIT_NAME_ANY))
return -EINVAL;
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, &c, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
@@ -2019,11 +2403,31 @@ int unit_file_lookup_state(
switch (i->type) {
case UNIT_FILE_TYPE_MASKED:
- state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
+ r = path_is_runtime(paths, i->path);
+ if (r < 0)
+ return r;
+
+ state = r > 0 ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED;
break;
case UNIT_FILE_TYPE_REGULAR:
- r = find_symlinks_in_scope(scope, root_dir, i->name, &state);
+ r = path_is_generator(paths, i->path);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ state = UNIT_FILE_GENERATED;
+ break;
+ }
+
+ r = path_is_transient(paths, i->path);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ state = UNIT_FILE_TRANSIENT;
+ break;
+ }
+
+ r = find_symlinks_in_scope(scope, paths, i->name, &state);
if (r < 0)
return r;
if (r == 0) {
@@ -2058,32 +2462,42 @@ int unit_file_get_state(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(name);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
+ return unit_file_lookup_state(scope, &paths, name, ret);
+}
+
+int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name) {
+ _cleanup_(install_context_done) InstallContext c = {};
+ int r;
+
+ assert(paths);
+ assert(name);
+
+ if (!unit_name_is_valid(name, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ r = install_info_discover(scope, &c, paths, name, 0, NULL);
+ if (r == -ENOENT)
+ return 0;
if (r < 0)
return r;
- return unit_file_lookup_state(scope, root_dir, &paths, name, ret);
+ return 1;
}
-int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
+static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
+ _cleanup_(presets_freep) Presets ps = {};
+ size_t n_allocated = 0;
_cleanup_strv_free_ char **files = NULL;
char **p;
int r;
assert(scope >= 0);
assert(scope < _UNIT_FILE_SCOPE_MAX);
- assert(name);
-
- r = verify_root_dir(scope, &root_dir);
- if (r < 0)
- return r;
-
- if (!unit_name_is_valid(name, UNIT_NAME_ANY))
- return -EINVAL;
+ assert(presets);
if (scope == UNIT_FILE_SYSTEM)
r = conf_files_list(&files, ".preset", root_dir,
@@ -2100,8 +2514,11 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
"/usr/local/lib/systemd/user-preset",
"/usr/lib/systemd/user-preset",
NULL);
- else
- return 1; /* Default is "enable" */
+ else {
+ *presets = (Presets){};
+
+ return 0;
+ }
if (r < 0)
return r;
@@ -2109,6 +2526,7 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
STRV_FOREACH(p, files) {
_cleanup_fclose_ FILE *f;
char line[LINE_MAX];
+ int n = 0;
f = fopen(*p, "re");
if (!f) {
@@ -2119,10 +2537,12 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
}
FOREACH_LINE(line, f, return -errno) {
+ PresetRule rule = {};
const char *parameter;
char *l;
l = strstrip(line);
+ n++;
if (isempty(l))
continue;
@@ -2131,31 +2551,87 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char
parameter = first_word(l, "enable");
if (parameter) {
- if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
- log_debug("Preset file says enable %s.", name);
- return 1;
- }
+ char *pattern;
- continue;
+ pattern = strdup(parameter);
+ if (!pattern)
+ return -ENOMEM;
+
+ rule = (PresetRule) {
+ .pattern = pattern,
+ .action = PRESET_ENABLE,
+ };
}
parameter = first_word(l, "disable");
if (parameter) {
- if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) {
- log_debug("Preset file says disable %s.", name);
- return 0;
- }
+ char *pattern;
+
+ pattern = strdup(parameter);
+ if (!pattern)
+ return -ENOMEM;
+
+ rule = (PresetRule) {
+ .pattern = pattern,
+ .action = PRESET_DISABLE,
+ };
+ }
+
+ if (rule.action) {
+ if (!GREEDY_REALLOC(ps.rules, n_allocated, ps.n_rules + 1))
+ return -ENOMEM;
+ ps.rules[ps.n_rules++] = rule;
continue;
}
- log_debug("Couldn't parse line '%s'", l);
+ log_syntax(NULL, LOG_WARNING, *p, n, 0, "Couldn't parse line '%s'. Ignoring.", line);
}
}
- /* Default is "enable" */
- log_debug("Preset file doesn't say anything about %s, enabling.", name);
- return 1;
+ *presets = ps;
+ ps = (Presets){};
+
+ return 0;
+}
+
+static int query_presets(const char *name, const Presets presets) {
+ PresetAction action = PRESET_UNKNOWN;
+ size_t i;
+
+ if (!unit_name_is_valid(name, UNIT_NAME_ANY))
+ return -EINVAL;
+
+ for (i = 0; i < presets.n_rules; i++)
+ if (fnmatch(presets.rules[i].pattern, name, FNM_NOESCAPE) == 0) {
+ action = presets.rules[i].action;
+ break;
+ }
+
+ switch (action) {
+ case PRESET_UNKNOWN:
+ log_debug("Preset files don't specify rule for %s. Enabling.", name);
+ return 1;
+ case PRESET_ENABLE:
+ log_debug("Preset files say enable %s.", name);
+ return 1;
+ case PRESET_DISABLE:
+ log_debug("Preset files say disable %s.", name);
+ return 0;
+ default:
+ assert_not_reached("invalid preset action");
+ }
+}
+
+int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) {
+ _cleanup_(presets_freep) Presets presets = {};
+ int r;
+
+ r = read_presets(scope, root_dir, &presets);
+ if (r < 0)
+ return r;
+
+ return query_presets(name, presets);
}
static int execute_preset(
@@ -2164,7 +2640,6 @@ static int execute_preset(
InstallContext *minus,
const LookupPaths *paths,
const char *config_path,
- const char *root_dir,
char **files,
UnitFilePresetMode mode,
bool force,
@@ -2181,11 +2656,11 @@ static int execute_preset(
if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) {
_cleanup_set_free_free_ Set *remove_symlinks_to = NULL;
- r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, root_dir);
+ r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path);
if (r < 0)
return r;
- r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes);
+ r = remove_marked_symlinks(remove_symlinks_to, config_path, paths, changes, n_changes);
} else
r = 0;
@@ -2193,12 +2668,12 @@ static int execute_preset(
int q;
/* Returns number of symlinks that where supposed to be installed. */
- q = install_context_apply(scope, plus, paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes);
+ q = install_context_apply(scope, plus, paths, config_path, force, SEARCH_LOAD, changes, n_changes);
if (r >= 0) {
if (q < 0)
r = q;
else
- r+= q;
+ r += q;
}
}
@@ -2210,9 +2685,11 @@ static int preset_prepare_one(
InstallContext *plus,
InstallContext *minus,
LookupPaths *paths,
- const char *root_dir,
UnitFilePresetMode mode,
- const char *name) {
+ const char *name,
+ Presets presets,
+ UnitFileChange **changes,
+ unsigned *n_changes) {
UnitFileInstallInfo *i;
int r;
@@ -2221,19 +2698,20 @@ static int preset_prepare_one(
install_info_find(minus, name))
return 0;
- r = unit_file_query_preset(scope, root_dir, name);
+ r = query_presets(name, presets);
if (r < 0)
return r;
if (r > 0) {
- r = install_info_discover(scope, plus, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, plus, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
if (r < 0)
return r;
- if (i->type == UNIT_FILE_TYPE_MASKED)
- return -ESHUTDOWN;
+ r = install_info_may_process(i, paths, changes, n_changes);
+ if (r < 0)
+ return r;
} else
- r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
+ r = install_info_discover(scope, minus, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i);
return r;
}
@@ -2250,7 +2728,8 @@ int unit_file_preset(
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
+ _cleanup_(presets_freep) Presets presets = {};
+ const char *config_path;
char **i;
int r;
@@ -2258,28 +2737,23 @@ int unit_file_preset(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(mode < _UNIT_FILE_PRESET_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
- r = get_config_path(scope, runtime, root_dir, &config_path);
+ r = read_presets(scope, root_dir, &presets);
if (r < 0)
return r;
STRV_FOREACH(i, files) {
- if (!unit_name_is_valid(*i, UNIT_NAME_ANY))
- return -EINVAL;
-
- r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i);
+ r = preset_prepare_one(scope, &plus, &minus, &paths, mode, *i, presets, changes, n_changes);
if (r < 0)
return r;
}
- return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes);
+ return execute_preset(scope, &plus, &minus, &paths, config_path, files, mode, force, changes, n_changes);
}
int unit_file_preset_all(
@@ -2293,7 +2767,8 @@ int unit_file_preset_all(
_cleanup_(install_context_done) InstallContext plus = {}, minus = {};
_cleanup_lookup_paths_free_ LookupPaths paths = {};
- _cleanup_free_ char *config_path = NULL;
+ _cleanup_(presets_freep) Presets presets = {};
+ const char *config_path = NULL;
char **i;
int r;
@@ -2301,28 +2776,21 @@ int unit_file_preset_all(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(mode < _UNIT_FILE_PRESET_MAX);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
+ config_path = runtime ? paths.runtime_config : paths.persistent_config;
- r = get_config_path(scope, runtime, root_dir, &config_path);
+ r = read_presets(scope, root_dir, &presets);
if (r < 0)
return r;
- STRV_FOREACH(i, paths.unit_path) {
+ STRV_FOREACH(i, paths.search_path) {
_cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *units_dir;
struct dirent *de;
- units_dir = path_join(root_dir, *i, NULL);
- if (!units_dir)
- return -ENOMEM;
-
- d = opendir(units_dir);
+ d = opendir(*i);
if (!d) {
if (errno == ENOENT)
continue;
@@ -2340,13 +2808,20 @@ int unit_file_preset_all(
if (!IN_SET(de->d_type, DT_LNK, DT_REG))
continue;
- r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name);
+ /* we don't pass changes[] in, because we want to handle errors on our own */
+ r = preset_prepare_one(scope, &plus, &minus, &paths, mode, de->d_name, presets, NULL, 0);
+ if (r == -ERFKILL)
+ r = unit_file_changes_add(changes, n_changes,
+ UNIT_FILE_IS_MASKED, de->d_name, NULL);
+ else if (r == -ENOLINK)
+ r = unit_file_changes_add(changes, n_changes,
+ UNIT_FILE_IS_DANGLING, de->d_name, NULL);
if (r < 0)
return r;
}
}
- return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes);
+ return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, force, changes, n_changes);
}
static void unit_file_list_free_one(UnitFileList *f) {
@@ -2371,7 +2846,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
int unit_file_get_list(
UnitFileScope scope,
const char *root_dir,
- Hashmap *h) {
+ Hashmap *h,
+ char **states,
+ char **patterns) {
_cleanup_lookup_paths_free_ LookupPaths paths = {};
char **i;
@@ -2381,24 +2858,15 @@ int unit_file_get_list(
assert(scope < _UNIT_FILE_SCOPE_MAX);
assert(h);
- r = verify_root_dir(scope, &root_dir);
+ r = lookup_paths_init(&paths, scope, 0, root_dir);
if (r < 0)
return r;
- r = lookup_paths_init_from_scope(&paths, scope, root_dir);
- if (r < 0)
- return r;
-
- STRV_FOREACH(i, paths.unit_path) {
+ STRV_FOREACH(i, paths.search_path) {
_cleanup_closedir_ DIR *d = NULL;
- _cleanup_free_ char *units_dir;
struct dirent *de;
- units_dir = path_join(root_dir, *i, NULL);
- if (!units_dir)
- return -ENOMEM;
-
- d = opendir(units_dir);
+ d = opendir(*i);
if (!d) {
if (errno == ENOENT)
continue;
@@ -2412,6 +2880,9 @@ int unit_file_get_list(
if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY))
continue;
+ if (!strv_fnmatch_or_empty(patterns, de->d_name, FNM_NOESCAPE))
+ continue;
+
if (hashmap_get(h, de->d_name))
continue;
@@ -2424,14 +2895,18 @@ int unit_file_get_list(
if (!f)
return -ENOMEM;
- f->path = path_make_absolute(de->d_name, units_dir);
+ f->path = path_make_absolute(de->d_name, *i);
if (!f->path)
return -ENOMEM;
- r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state);
+ r = unit_file_lookup_state(scope, &paths, de->d_name, &f->state);
if (r < 0)
f->state = UNIT_FILE_BAD;
+ if (!strv_isempty(states) &&
+ !strv_contains(states, unit_file_state_to_string(f->state)))
+ continue;
+
r = hashmap_put(h, basename(f->path), f);
if (r < 0)
return r;
@@ -2453,6 +2928,8 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = {
[UNIT_FILE_STATIC] = "static",
[UNIT_FILE_DISABLED] = "disabled",
[UNIT_FILE_INDIRECT] = "indirect",
+ [UNIT_FILE_GENERATED] = "generated",
+ [UNIT_FILE_TRANSIENT] = "transient",
[UNIT_FILE_BAD] = "bad",
};
@@ -2461,6 +2938,8 @@ DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState);
static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] = {
[UNIT_FILE_SYMLINK] = "symlink",
[UNIT_FILE_UNLINK] = "unlink",
+ [UNIT_FILE_IS_MASKED] = "masked",
+ [UNIT_FILE_IS_DANGLING] = "dangling",
};
DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType);
diff --git a/src/libshared/install.h b/src/libshared/install.h
index c1a43e23e7..c6aa4f6ef1 100644
--- a/src/libshared/install.h
+++ b/src/libshared/install.h
@@ -54,6 +54,8 @@ enum UnitFileState {
UNIT_FILE_STATIC,
UNIT_FILE_DISABLED,
UNIT_FILE_INDIRECT,
+ UNIT_FILE_GENERATED,
+ UNIT_FILE_TRANSIENT,
UNIT_FILE_BAD,
_UNIT_FILE_STATE_MAX,
_UNIT_FILE_STATE_INVALID = -1
@@ -70,16 +72,30 @@ enum UnitFilePresetMode {
enum UnitFileChangeType {
UNIT_FILE_SYMLINK,
UNIT_FILE_UNLINK,
+ UNIT_FILE_IS_MASKED,
+ UNIT_FILE_IS_DANGLING,
_UNIT_FILE_CHANGE_TYPE_MAX,
- _UNIT_FILE_CHANGE_TYPE_INVALID = -1
+ _UNIT_FILE_CHANGE_INVALID = INT_MIN
};
+/* type can either one of the UnitFileChangeTypes listed above, or a negative error.
+ * If source is specified, it should be the contents of the path symlink.
+ * In case of an error, source should be the existing symlink contents or NULL
+ */
struct UnitFileChange {
- UnitFileChangeType type;
+ int type; /* UnitFileChangeType or bust */
char *path;
char *source;
};
+static inline bool unit_file_changes_have_modification(const UnitFileChange* changes, unsigned n_changes) {
+ unsigned i;
+ for (i = 0; i < n_changes; i++)
+ if (IN_SET(changes[i].type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK))
+ return true;
+ return false;
+}
+
struct UnitFileList {
char *path;
UnitFileState state;
@@ -123,31 +139,115 @@ static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) {
return !strv_isempty(i->also);
}
-int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_link(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_preset(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_preset_all(UnitFileScope scope, bool runtime, const char *root_dir, UnitFilePresetMode mode, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes);
-int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name);
-int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes);
-
-int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret);
+bool unit_type_may_alias(UnitType type) _const_;
+bool unit_type_may_template(UnitType type) _const_;
+
+int unit_file_enable(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_disable(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_reenable(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_preset(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ UnitFilePresetMode mode,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_preset_all(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ UnitFilePresetMode mode,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_mask(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_unmask(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_link(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_revert(
+ UnitFileScope scope,
+ const char *root_dir,
+ char **files,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_set_default(
+ UnitFileScope scope,
+ const char *root_dir,
+ const char *file,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+int unit_file_get_default(
+ UnitFileScope scope,
+ const char *root_dir,
+ char **name);
+int unit_file_add_dependency(
+ UnitFileScope scope,
+ bool runtime,
+ const char *root_dir,
+ char **files,
+ const char *target,
+ UnitDependency dep,
+ bool force,
+ UnitFileChange **changes,
+ unsigned *n_changes);
+
int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret);
+int unit_file_exists(UnitFileScope scope, const LookupPaths *paths, const char *name);
-int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h);
+int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h, char **states, char **patterns);
Hashmap* unit_file_list_free(Hashmap *h);
int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source);
void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes);
+void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *changes, unsigned n_changes, bool quiet);
int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name);
const char *unit_file_state_to_string(UnitFileState s) _const_;
UnitFileState unit_file_state_from_string(const char *s) _pure_;
+/* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */
const char *unit_file_change_type_to_string(UnitFileChangeType s) _const_;
UnitFileChangeType unit_file_change_type_from_string(const char *s) _pure_;
diff --git a/src/libshared/local-addresses.c b/src/libshared/local-addresses.c
index e6feb859cd..1abce75b01 100644
--- a/src/libshared/local-addresses.c
+++ b/src/libshared/local-addresses.c
@@ -155,8 +155,7 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre
n_list++;
};
- if (n_list > 0)
- qsort(list, n_list, sizeof(struct local_address), address_compare);
+ qsort_safe(list, n_list, sizeof(struct local_address), address_compare);
*ret = list;
list = NULL;
diff --git a/src/libshared/logs-show.c b/src/libshared/logs-show.c
index 7ac6d49549..294fa3bede 100644
--- a/src/libshared/logs-show.c
+++ b/src/libshared/logs-show.c
@@ -287,7 +287,10 @@ static int output_short(
if (r < 0)
return r;
}
-
+ if (r == -EBADMSG) {
+ log_debug_errno(r, "Skipping message we can't read: %m");
+ return 0;
+ }
if (r < 0)
return log_error_errno(r, "Failed to get journal fields: %m");
@@ -344,16 +347,22 @@ static int output_short(
t = (time_t) (x / USEC_PER_SEC);
- switch(mode) {
+ switch (mode) {
+
+ case OUTPUT_SHORT_UNIX:
+ r = snprintf(buf, sizeof(buf), "%10llu.%06llu", (unsigned long long) t, (unsigned long long) (x % USEC_PER_SEC));
+ break;
+
case OUTPUT_SHORT_ISO:
r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
break;
+
case OUTPUT_SHORT_PRECISE:
r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
if (r > 0)
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
break;
+
default:
r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
}
@@ -367,6 +376,12 @@ static int output_short(
n += strlen(buf);
}
+ if (hostname && (flags & OUTPUT_NO_HOSTNAME)) {
+ /* Suppress display of the hostname if this is requested. */
+ hostname = NULL;
+ hostname_len = 0;
+ }
+
if (hostname && shall_print(hostname, hostname_len, flags)) {
fprintf(f, " %.*s", (int) hostname_len, hostname);
n += hostname_len + 1;
@@ -894,6 +909,7 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(
[OUTPUT_SHORT_ISO] = output_short,
[OUTPUT_SHORT_PRECISE] = output_short,
[OUTPUT_SHORT_MONOTONIC] = output_short,
+ [OUTPUT_SHORT_UNIX] = output_short,
[OUTPUT_VERBOSE] = output_verbose,
[OUTPUT_EXPORT] = output_export,
[OUTPUT_JSON] = output_json,
@@ -997,7 +1013,7 @@ static int show_journal(FILE *f,
continue;
}
- line ++;
+ line++;
maybe_print_begin_newline(f, &flags);
r = output_journal(f, j, mode, n_columns, flags, ellipsized);
@@ -1040,8 +1056,8 @@ static int show_journal(FILE *f,
}
int add_matches_for_unit(sd_journal *j, const char *unit) {
+ const char *m1, *m2, *m3, *m4;
int r;
- char *m1, *m2, *m3, *m4;
assert(j);
assert(unit);
@@ -1073,7 +1089,9 @@ int add_matches_for_unit(sd_journal *j, const char *unit) {
);
if (r == 0 && endswith(unit, ".slice")) {
- char *m5 = strappend("_SYSTEMD_SLICE=", unit);
+ const char *m5;
+
+ m5 = strjoina("_SYSTEMD_SLICE=", unit);
/* Show all messages belonging to a slice */
(void)(
@@ -1123,7 +1141,9 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
);
if (r == 0 && endswith(unit, ".slice")) {
- char *m5 = strappend("_SYSTEMD_SLICE=", unit);
+ const char *m5;
+
+ m5 = strjoina("_SYSTEMD_SLICE=", unit);
/* Show all messages belonging to a slice */
(void)(
@@ -1288,18 +1308,3 @@ int show_journal_by_unit(
return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
}
-
-static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
- [OUTPUT_SHORT] = "short",
- [OUTPUT_SHORT_ISO] = "short-iso",
- [OUTPUT_SHORT_PRECISE] = "short-precise",
- [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
- [OUTPUT_VERBOSE] = "verbose",
- [OUTPUT_EXPORT] = "export",
- [OUTPUT_JSON] = "json",
- [OUTPUT_JSON_PRETTY] = "json-pretty",
- [OUTPUT_JSON_SSE] = "json-sse",
- [OUTPUT_CAT] = "cat"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
diff --git a/src/libshared/logs-show.h b/src/libshared/logs-show.h
index 682a4adc7b..15fe5b6e5c 100644
--- a/src/libshared/logs-show.h
+++ b/src/libshared/logs-show.h
@@ -68,6 +68,3 @@ void json_escape(
const char* p,
size_t l,
OutputFlags flags);
-
-const char* output_mode_to_string(OutputMode m) _const_;
-OutputMode output_mode_from_string(const char *s) _pure_;
diff --git a/src/libshared/machine-image.c b/src/libshared/machine-image.c
index ed8a29c575..529d89ee2a 100644
--- a/src/libshared/machine-image.c
+++ b/src/libshared/machine-image.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fs.h>
@@ -400,8 +401,7 @@ int image_remove(Image *i) {
assert(i);
- if (path_equal(i->path, "/") ||
- path_startswith(i->path, "/usr"))
+ if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
settings = image_settings_path(i);
@@ -423,7 +423,7 @@ int image_remove(Image *i) {
case IMAGE_DIRECTORY:
/* Allow deletion of read-only directories */
- (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
r = rm_rf(i->path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
if (r < 0)
return r;
@@ -473,8 +473,7 @@ int image_rename(Image *i, const char *new_name) {
if (!image_name_is_valid(new_name))
return -EINVAL;
- if (path_equal(i->path, "/") ||
- path_startswith(i->path, "/usr"))
+ if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
settings = image_settings_path(i);
@@ -488,7 +487,7 @@ int image_rename(Image *i, const char *new_name) {
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
- * time we take possesion of it */
+ * time we take possession of it */
r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
if (r < 0)
return r;
@@ -506,7 +505,7 @@ int image_rename(Image *i, const char *new_name) {
(void) read_attr_path(i->path, &file_attr);
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(i->path, false, FS_IMMUTABLE_FL);
+ (void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
/* fall through */
@@ -539,7 +538,7 @@ int image_rename(Image *i, const char *new_name) {
/* Restore the immutable bit, if it was set before */
if (file_attr & FS_IMMUTABLE_FL)
- (void) chattr_path(new_path, true, FS_IMMUTABLE_FL);
+ (void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
free(i->path);
i->path = new_path;
@@ -589,7 +588,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
/* Make sure nobody takes the new name, between the time we
* checked it is currently unused in all search paths, and the
- * time we take possesion of it */
+ * time we take possession of it */
r = image_name_lock(new_name, LOCK_EX|LOCK_NB, &name_lock);
if (r < 0)
return r;
@@ -604,13 +603,21 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_SUBVOLUME:
case IMAGE_DIRECTORY:
+ /* If we can we'll always try to create a new btrfs subvolume here, even if the source is a plain
+ * directory.*/
+
new_path = strjoina("/var/lib/machines/", new_name);
r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA);
+ if (r == -EOPNOTSUPP) {
+ /* No btrfs snapshots supported, create a normal directory then. */
- /* Enable "subtree" quotas for the copy, if we didn't
- * copy any quota from the source. */
- (void) btrfs_subvol_auto_qgroup(i->path, 0, true);
+ r = copy_directory(i->path, new_path, false);
+ if (r >= 0)
+ (void) chattr_path(new_path, read_only ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
+ } else if (r >= 0)
+ /* Enable "subtree" quotas for the copy, if we didn't copy any quota from the source. */
+ (void) btrfs_subvol_auto_qgroup(new_path, 0, true);
break;
@@ -641,8 +648,7 @@ int image_read_only(Image *i, bool b) {
int r;
assert(i);
- if (path_equal(i->path, "/") ||
- path_startswith(i->path, "/usr"))
+ if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
/* Make sure we don't interfere with a running nspawn */
@@ -672,7 +678,7 @@ int image_read_only(Image *i, bool b) {
a read-only subvolume, but at least something, and
we can read the value back.*/
- r = chattr_path(i->path, b, FS_IMMUTABLE_FL);
+ r = chattr_path(i->path, b ? FS_IMMUTABLE_FL : 0, FS_IMMUTABLE_FL);
if (r < 0)
return r;
@@ -750,8 +756,7 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
int image_set_limit(Image *i, uint64_t referenced_max) {
assert(i);
- if (path_equal(i->path, "/") ||
- path_startswith(i->path, "/usr"))
+ if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
return -EROFS;
if (i->type != IMAGE_SUBVOLUME)
diff --git a/src/libshared/machine-image.h b/src/libshared/machine-image.h
index 31b720d50c..7410168c4f 100644
--- a/src/libshared/machine-image.h
+++ b/src/libshared/machine-image.h
@@ -25,6 +25,8 @@
#include "hashmap.h"
#include "lockfile-util.h"
#include "macro.h"
+#include "path-util.h"
+#include "string-util.h"
#include "time-util.h"
typedef enum ImageType {
@@ -75,3 +77,27 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
int image_name_lock(const char *name, int operation, LockFile *ret);
int image_set_limit(Image *i, uint64_t referenced_max);
+
+static inline bool IMAGE_IS_HIDDEN(const struct Image *i) {
+ assert(i);
+
+ return i->name && i->name[0] == '.';
+}
+
+static inline bool IMAGE_IS_VENDOR(const struct Image *i) {
+ assert(i);
+
+ return i->path && path_startswith(i->path, "/usr");
+}
+
+static inline bool IMAGE_IS_HOST(const struct Image *i) {
+ assert(i);
+
+ if (i->name && streq(i->name, ".host"))
+ return true;
+
+ if (i->path && path_equal(i->path, "/"))
+ return true;
+
+ return false;
+}
diff --git a/src/libshared/machine-pool.c b/src/libshared/machine-pool.c
index 056b5bfae5..c36efa0102 100644
--- a/src/libshared/machine-pool.c
+++ b/src/libshared/machine-pool.c
@@ -24,6 +24,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/prctl.h>
@@ -138,7 +139,7 @@ static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
if (errno == ENOENT)
- return 99;
+ _exit(99);
_exit(EXIT_FAILURE);
}
@@ -238,10 +239,8 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) {
}
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 sd_bus_error_set_errnof(error, ENOENT, "Cannot set up /var/lib/machines, mkfs.btrfs is missing");
if (r < 0)
return r;
diff --git a/src/libshared/output-mode.c b/src/libshared/output-mode.c
new file mode 100644
index 0000000000..bec53ee0ae
--- /dev/null
+++ b/src/libshared/output-mode.c
@@ -0,0 +1,37 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2012 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "output-mode.h"
+#include "string-table.h"
+
+static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
+ [OUTPUT_SHORT] = "short",
+ [OUTPUT_SHORT_ISO] = "short-iso",
+ [OUTPUT_SHORT_PRECISE] = "short-precise",
+ [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
+ [OUTPUT_SHORT_UNIX] = "short-unix",
+ [OUTPUT_VERBOSE] = "verbose",
+ [OUTPUT_EXPORT] = "export",
+ [OUTPUT_JSON] = "json",
+ [OUTPUT_JSON_PRETTY] = "json-pretty",
+ [OUTPUT_JSON_SSE] = "json-sse",
+ [OUTPUT_CAT] = "cat"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);
diff --git a/src/libshared/output-mode.h b/src/libshared/output-mode.h
index c5470e7c1b..f37189e57f 100644
--- a/src/libshared/output-mode.h
+++ b/src/libshared/output-mode.h
@@ -19,11 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "macro.h"
+
typedef enum OutputMode {
OUTPUT_SHORT,
OUTPUT_SHORT_ISO,
OUTPUT_SHORT_PRECISE,
OUTPUT_SHORT_MONOTONIC,
+ OUTPUT_SHORT_UNIX,
OUTPUT_VERBOSE,
OUTPUT_EXPORT,
OUTPUT_JSON,
@@ -34,6 +37,9 @@ typedef enum OutputMode {
_OUTPUT_MODE_INVALID = -1
} OutputMode;
+/* The output flags definitions are shared by the logs and process tree output. Some apply to both, some only to the
+ * logs output, others only to the process tree output. */
+
typedef enum OutputFlags {
OUTPUT_SHOW_ALL = 1 << 0,
OUTPUT_FOLLOW = 1 << 1,
@@ -43,4 +49,9 @@ typedef enum OutputFlags {
OUTPUT_CATALOG = 1 << 5,
OUTPUT_BEGIN_NEWLINE = 1 << 6,
OUTPUT_UTC = 1 << 7,
+ OUTPUT_KERNEL_THREADS = 1 << 8,
+ OUTPUT_NO_HOSTNAME = 1 << 9,
} OutputFlags;
+
+const char* output_mode_to_string(OutputMode m) _const_;
+OutputMode output_mode_from_string(const char *s) _pure_;
diff --git a/src/libshared/pager.c b/src/libshared/pager.c
index 05b2b15e40..c16bc027be 100644
--- a/src/libshared/pager.c
+++ b/src/libshared/pager.c
@@ -52,11 +52,14 @@ noreturn static void pager_fallback(void) {
_exit(EXIT_SUCCESS);
}
-int pager_open(bool jump_to_end) {
+int pager_open(bool no_pager, bool jump_to_end) {
_cleanup_close_pair_ int fd[2] = { -1, -1 };
const char *pager;
pid_t parent_pid;
+ if (no_pager)
+ return 0;
+
if (pager_pid > 0)
return 1;
diff --git a/src/libshared/pager.h b/src/libshared/pager.h
index 9fb05796bb..893e1d2bb6 100644
--- a/src/libshared/pager.h
+++ b/src/libshared/pager.h
@@ -23,7 +23,7 @@
#include "macro.h"
-int pager_open(bool jump_to_end);
+int pager_open(bool no_pager, bool jump_to_end);
void pager_close(void);
bool pager_have(void) _pure_;
diff --git a/src/libshared/path-lookup.c b/src/libshared/path-lookup.c
index 5410620725..ca593b6963 100644
--- a/src/libshared/path-lookup.c
+++ b/src/libshared/path-lookup.c
@@ -26,61 +26,66 @@
#include "install.h"
#include "log.h"
#include "macro.h"
+#include "mkdir.h"
#include "path-lookup.h"
#include "path-util.h"
+#include "rm-rf.h"
+#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
-int user_config_home(char **config_home) {
+static int user_runtime_dir(char **ret, const char *suffix) {
const char *e;
- char *r;
+ char *j;
- e = getenv("XDG_CONFIG_HOME");
- if (e) {
- r = strappend(e, "/systemd/user");
- if (!r)
- return -ENOMEM;
-
- *config_home = r;
- return 1;
- } else {
- const char *home;
+ assert(ret);
+ assert(suffix);
- home = getenv("HOME");
- if (home) {
- r = strappend(home, "/.config/systemd/user");
- if (!r)
- return -ENOMEM;
+ e = getenv("XDG_RUNTIME_DIR");
+ if (!e)
+ return -ENXIO;
- *config_home = r;
- return 1;
- }
- }
+ j = strappend(e, suffix);
+ if (!j)
+ return -ENOMEM;
+ *ret = j;
return 0;
}
-int user_runtime_dir(char **runtime_dir) {
+static int user_config_dir(char **ret, const char *suffix) {
const char *e;
- char *r;
+ char *j;
- e = getenv("XDG_RUNTIME_DIR");
- if (e) {
- r = strappend(e, "/systemd/user");
- if (!r)
- return -ENOMEM;
+ assert(ret);
+
+ e = getenv("XDG_CONFIG_HOME");
+ if (e)
+ j = strappend(e, suffix);
+ else {
+ const char *home;
- *runtime_dir = r;
- return 1;
+ home = getenv("HOME");
+ if (!home)
+ return -ENXIO;
+
+ j = strjoin(home, "/.config", suffix, NULL);
}
+ if (!j)
+ return -ENOMEM;
+
+ *ret = j;
return 0;
}
-static int user_data_home_dir(char **dir, const char *suffix) {
+static int user_data_dir(char **ret, const char *suffix) {
const char *e;
- char *res;
+ char *j;
+
+ assert(ret);
+ assert(suffix);
/* We don't treat /etc/xdg/systemd here as the spec
* suggests because we assume that that is a link to
@@ -88,27 +93,33 @@ static int user_data_home_dir(char **dir, const char *suffix) {
e = getenv("XDG_DATA_HOME");
if (e)
- res = strappend(e, suffix);
+ j = strappend(e, suffix);
else {
const char *home;
home = getenv("HOME");
- if (home)
- res = strjoin(home, "/.local/share", suffix, NULL);
- else
- return 0;
+ if (!home)
+ return -ENXIO;
+
+
+ j = strjoin(home, "/.local/share", suffix, NULL);
}
- if (!res)
+ if (!j)
return -ENOMEM;
- *dir = res;
- return 0;
+ *ret = j;
+ return 1;
}
static char** user_dirs(
+ const char *persistent_config,
+ const char *runtime_config,
const char *generator,
const char *generator_early,
- const char *generator_late) {
+ const char *generator_late,
+ const char *transient,
+ const char *persistent_control,
+ const char *runtime_control) {
const char * const config_unit_paths[] = {
USER_CONFIG_UNIT_PATH,
@@ -116,8 +127,6 @@ static char** user_dirs(
NULL
};
- const char * const runtime_unit_path = "/run/systemd/user";
-
const char * const data_unit_paths[] = {
"/usr/local/lib/systemd/user",
"/usr/local/share/systemd/user",
@@ -128,8 +137,8 @@ static char** user_dirs(
};
const char *e;
- _cleanup_free_ char *config_home = NULL, *runtime_dir = NULL, *data_home = NULL;
_cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
+ _cleanup_free_ char *data_home = NULL;
_cleanup_free_ char **res = NULL;
char **tmp;
int r;
@@ -143,12 +152,6 @@ static char** user_dirs(
* as data, and allow overriding as configuration.
*/
- if (user_config_home(&config_home) < 0)
- return NULL;
-
- if (user_runtime_dir(&runtime_dir) < 0)
- return NULL;
-
e = getenv("XDG_CONFIG_DIRS");
if (e) {
config_dirs = strv_split(e, ":");
@@ -156,8 +159,8 @@ static char** user_dirs(
return NULL;
}
- r = user_data_home_dir(&data_home, "/systemd/user");
- if (r < 0)
+ r = user_data_dir(&data_home, "/systemd/user");
+ if (r < 0 && r != -ENXIO)
return NULL;
e = getenv("XDG_DATA_DIRS");
@@ -171,35 +174,36 @@ static char** user_dirs(
return NULL;
/* Now merge everything we found. */
- if (generator_early)
- if (strv_extend(&res, generator_early) < 0)
- return NULL;
+ if (strv_extend(&res, persistent_control) < 0)
+ return NULL;
- if (config_home)
- if (strv_extend(&res, config_home) < 0)
- return NULL;
+ if (strv_extend(&res, runtime_control) < 0)
+ return NULL;
+
+ if (strv_extend(&res, transient) < 0)
+ return NULL;
+
+ if (strv_extend(&res, generator_early) < 0)
+ return NULL;
if (!strv_isempty(config_dirs))
if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0)
return NULL;
- if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
+ if (strv_extend(&res, persistent_config) < 0)
return NULL;
- if (runtime_dir)
- if (strv_extend(&res, runtime_dir) < 0)
- return NULL;
+ if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0)
+ return NULL;
- if (strv_extend(&res, runtime_unit_path) < 0)
+ if (strv_extend(&res, runtime_config) < 0)
return NULL;
- if (generator)
- if (strv_extend(&res, generator) < 0)
- return NULL;
+ if (strv_extend(&res, generator) < 0)
+ return NULL;
- if (data_home)
- if (strv_extend(&res, data_home) < 0)
- return NULL;
+ if (strv_extend(&res, data_home) < 0)
+ return NULL;
if (!strv_isempty(data_dirs))
if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0)
@@ -208,9 +212,8 @@ static char** user_dirs(
if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0)
return NULL;
- if (generator_late)
- if (strv_extend(&res, generator_late) < 0)
- return NULL;
+ if (strv_extend(&res, generator_late) < 0)
+ return NULL;
if (path_strv_make_absolute_cwd(res) < 0)
return NULL;
@@ -220,58 +223,298 @@ static char** user_dirs(
return tmp;
}
-char **generator_paths(ManagerRunningAs running_as) {
- if (running_as == MANAGER_USER)
- return strv_new("/run/systemd/user-generators",
- "/etc/systemd/user-generators",
- "/usr/local/lib/systemd/user-generators",
- USER_GENERATOR_PATH,
- NULL);
- else
- return strv_new("/run/systemd/system-generators",
- "/etc/systemd/system-generators",
- "/usr/local/lib/systemd/system-generators",
- SYSTEM_GENERATOR_PATH,
- NULL);
+static int acquire_generator_dirs(
+ UnitFileScope scope,
+ char **generator,
+ char **generator_early,
+ char **generator_late) {
+
+ _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
+ const char *prefix;
+
+ assert(generator);
+ assert(generator_early);
+ assert(generator_late);
+
+ switch (scope) {
+
+ case UNIT_FILE_SYSTEM:
+ prefix = "/run/systemd/";
+ break;
+
+ case UNIT_FILE_USER: {
+ const char *e;
+
+ e = getenv("XDG_RUNTIME_DIR");
+ if (!e)
+ return -ENXIO;
+
+ prefix = strjoina(e, "/systemd/");
+ break;
+ }
+
+ case UNIT_FILE_GLOBAL:
+ return -EOPNOTSUPP;
+
+ default:
+ assert_not_reached("Hmm, unexpected scope value.");
+ }
+
+ x = strappend(prefix, "generator");
+ if (!x)
+ return -ENOMEM;
+
+ y = strappend(prefix, "generator.early");
+ if (!y)
+ return -ENOMEM;
+
+ z = strappend(prefix, "generator.late");
+ if (!z)
+ return -ENOMEM;
+
+ *generator = x;
+ *generator_early = y;
+ *generator_late = z;
+
+ x = y = z = NULL;
+ return 0;
+}
+
+static int acquire_transient_dir(UnitFileScope scope, char **ret) {
+ assert(ret);
+
+ switch (scope) {
+
+ case UNIT_FILE_SYSTEM: {
+ char *transient;
+
+ transient = strdup("/run/systemd/transient");
+ if (!transient)
+ return -ENOMEM;
+
+ *ret = transient;
+ return 0;
+ }
+
+ case UNIT_FILE_USER:
+ return user_runtime_dir(ret, "/systemd/transient");
+
+ case UNIT_FILE_GLOBAL:
+ return -EOPNOTSUPP;
+
+ default:
+ assert_not_reached("Hmm, unexpected scope value.");
+ }
+}
+
+static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **runtime) {
+ _cleanup_free_ char *a = NULL, *b = NULL;
+ int r;
+
+ assert(persistent);
+ assert(runtime);
+
+ switch (scope) {
+
+ case UNIT_FILE_SYSTEM:
+ a = strdup(SYSTEM_CONFIG_UNIT_PATH);
+ b = strdup("/run/systemd/system");
+ break;
+
+ case UNIT_FILE_GLOBAL:
+ a = strdup(USER_CONFIG_UNIT_PATH);
+ b = strdup("/run/systemd/user");
+ break;
+
+ case UNIT_FILE_USER:
+ r = user_config_dir(&a, "/systemd/user");
+ if (r < 0)
+ return r;
+
+ r = user_runtime_dir(runtime, "/systemd/user");
+ if (r < 0)
+ return r;
+
+ *persistent = a;
+ a = NULL;
+
+ return 0;
+
+ default:
+ assert_not_reached("Hmm, unexpected scope value.");
+ }
+
+ if (!a || !b)
+ return -ENOMEM;
+
+ *persistent = a;
+ *runtime = b;
+ a = b = NULL;
+
+ return 0;
+}
+
+static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **runtime) {
+ _cleanup_free_ char *a = NULL;
+ int r;
+
+ assert(persistent);
+ assert(runtime);
+
+ switch (scope) {
+
+ case UNIT_FILE_SYSTEM: {
+ _cleanup_free_ char *b = NULL;
+
+ a = strdup("/etc/systemd/system.control");
+ if (!a)
+ return -ENOMEM;
+
+ b = strdup("/run/systemd/system.control");
+ if (!b)
+ return -ENOMEM;
+
+ *runtime = b;
+ b = NULL;
+
+ break;
+ }
+
+ case UNIT_FILE_USER:
+ r = user_config_dir(&a, "/systemd/system.control");
+ if (r < 0)
+ return r;
+
+ r = user_runtime_dir(runtime, "/systemd/system.control");
+ if (r < 0)
+ return r;
+
+ break;
+
+ case UNIT_FILE_GLOBAL:
+ return -EOPNOTSUPP;
+
+ default:
+ assert_not_reached("Hmm, unexpected scope value.");
+ }
+
+ *persistent = a;
+ a = NULL;
+
+ return 0;
+}
+
+static int patch_root_prefix(char **p, const char *root_dir) {
+ char *c;
+
+ assert(p);
+
+ if (!*p)
+ return 0;
+
+ c = prefix_root(root_dir, *p);
+ if (!c)
+ return -ENOMEM;
+
+ free(*p);
+ *p = c;
+
+ return 0;
+}
+
+static int patch_root_prefix_strv(char **l, const char *root_dir) {
+ char **i;
+ int r;
+
+ if (!root_dir)
+ return 0;
+
+ STRV_FOREACH(i, l) {
+ r = patch_root_prefix(i, root_dir);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
}
int lookup_paths_init(
LookupPaths *p,
- ManagerRunningAs running_as,
- bool personal,
- const char *root_dir,
- const char *generator,
- const char *generator_early,
- const char *generator_late) {
-
- const char *e;
+ UnitFileScope scope,
+ LookupPathsFlags flags,
+ const char *root_dir) {
+
+ _cleanup_free_ char
+ *root = NULL,
+ *persistent_config = NULL, *runtime_config = NULL,
+ *generator = NULL, *generator_early = NULL, *generator_late = NULL,
+ *transient = NULL,
+ *persistent_control = NULL, *runtime_control = NULL;
bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */
+ _cleanup_strv_free_ char **paths = NULL;
+ const char *e;
int r;
assert(p);
+ assert(scope >= 0);
+ assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+ if (!isempty(root_dir) && !path_equal(root_dir, "/")) {
+ if (scope == UNIT_FILE_USER)
+ return -EINVAL;
+
+ r = is_dir(root_dir, true);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOTDIR;
- /* First priority is whatever has been passed to us via env
- * vars */
+ root = strdup(root_dir);
+ if (!root)
+ return -ENOMEM;
+ }
+
+ r = acquire_config_dirs(scope, &persistent_config, &runtime_config);
+ if (r < 0 && r != -ENXIO)
+ return r;
+
+ if ((flags & LOOKUP_PATHS_EXCLUDE_GENERATED) == 0) {
+ r = acquire_generator_dirs(scope, &generator, &generator_early, &generator_late);
+ if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+ return r;
+ }
+
+ r = acquire_transient_dir(scope, &transient);
+ if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+ return r;
+
+ r = acquire_control_dirs(scope, &persistent_control, &runtime_control);
+ if (r < 0 && r != -EOPNOTSUPP && r != -ENXIO)
+ return r;
+
+ /* First priority is whatever has been passed to us via env vars */
e = getenv("SYSTEMD_UNIT_PATH");
if (e) {
- if (endswith(e, ":")) {
- e = strndupa(e, strlen(e) - 1);
+ const char *k;
+
+ k = endswith(e, ":");
+ if (k) {
+ e = strndupa(e, k - e);
append = true;
}
/* FIXME: empty components in other places should be
* rejected. */
- r = path_split_and_make_absolute(e, &p->unit_path);
+ r = path_split_and_make_absolute(e, &paths);
if (r < 0)
return r;
- } else
- p->unit_path = NULL;
+ }
- if (!p->unit_path || append) {
+ if (!paths || append) {
/* Let's figure something out. */
- _cleanup_strv_free_ char **unit_path;
+ _cleanup_strv_free_ char **add = NULL;
/* For the user units we include share/ in the search
* path in order to comply with the XDG basedir spec.
@@ -279,17 +522,45 @@ int lookup_paths_init(
* we include /lib in the search path for the system
* stuff but avoid it for user stuff. */
- if (running_as == MANAGER_USER) {
- if (personal)
- unit_path = user_dirs(generator, generator_early, generator_late);
- else
- unit_path = strv_new(
+ switch (scope) {
+
+ case UNIT_FILE_SYSTEM:
+ add = strv_new(
+ /* If you modify this you also want to modify
+ * systemdsystemunitpath= in systemd.pc.in! */
+ STRV_IFNOTNULL(persistent_control),
+ STRV_IFNOTNULL(runtime_control),
+ STRV_IFNOTNULL(transient),
+ STRV_IFNOTNULL(generator_early),
+ persistent_config,
+ SYSTEM_CONFIG_UNIT_PATH,
+ "/etc/systemd/system",
+ runtime_config,
+ "/run/systemd/system",
+ STRV_IFNOTNULL(generator),
+ "/usr/local/lib/systemd/system",
+ SYSTEM_DATA_UNIT_PATH,
+ "/usr/lib/systemd/system",
+#ifdef HAVE_SPLIT_USR
+ "/lib/systemd/system",
+#endif
+ STRV_IFNOTNULL(generator_late),
+ NULL);
+ break;
+
+ case UNIT_FILE_GLOBAL:
+ add = strv_new(
/* If you modify this you also want to modify
* systemduserunitpath= in systemd.pc.in, and
* the arrays in user_dirs() above! */
+ STRV_IFNOTNULL(persistent_control),
+ STRV_IFNOTNULL(runtime_control),
+ STRV_IFNOTNULL(transient),
STRV_IFNOTNULL(generator_early),
+ persistent_config,
USER_CONFIG_UNIT_PATH,
"/etc/systemd/user",
+ runtime_config,
"/run/systemd/user",
STRV_IFNOTNULL(generator),
"/usr/local/lib/systemd/user",
@@ -299,143 +570,253 @@ int lookup_paths_init(
"/usr/share/systemd/user",
STRV_IFNOTNULL(generator_late),
NULL);
- } else
- unit_path = strv_new(
- /* If you modify this you also want to modify
- * systemdsystemunitpath= in systemd.pc.in! */
- STRV_IFNOTNULL(generator_early),
- SYSTEM_CONFIG_UNIT_PATH,
- "/etc/systemd/system",
- "/run/systemd/system",
- STRV_IFNOTNULL(generator),
- "/usr/local/lib/systemd/system",
- SYSTEM_DATA_UNIT_PATH,
- "/usr/lib/systemd/system",
-#ifdef HAVE_SPLIT_USR
- "/lib/systemd/system",
-#endif
- STRV_IFNOTNULL(generator_late),
- NULL);
+ break;
+
+ case UNIT_FILE_USER:
+ add = user_dirs(persistent_config, runtime_config,
+ generator, generator_early, generator_late,
+ transient,
+ persistent_config, runtime_control);
+ break;
- if (!unit_path)
+ default:
+ assert_not_reached("Hmm, unexpected scope?");
+ }
+
+ if (!add)
return -ENOMEM;
- r = strv_extend_strv(&p->unit_path, unit_path, false);
- if (r < 0)
- return r;
+ if (paths) {
+ r = strv_extend_strv(&paths, add, true);
+ if (r < 0)
+ return r;
+ } else {
+ /* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
+ * and don't have to copy anything */
+ paths = add;
+ add = NULL;
+ }
}
- if (!path_strv_resolve_uniq(p->unit_path, root_dir))
+ r = patch_root_prefix(&persistent_config, root);
+ if (r < 0)
+ return r;
+ r = patch_root_prefix(&runtime_config, root);
+ if (r < 0)
+ return r;
+
+ r = patch_root_prefix(&generator, root);
+ if (r < 0)
+ return r;
+ r = patch_root_prefix(&generator_early, root);
+ if (r < 0)
+ return r;
+ r = patch_root_prefix(&generator_late, root);
+ if (r < 0)
+ return r;
+
+ r = patch_root_prefix(&transient, root);
+ if (r < 0)
+ return r;
+
+ r = patch_root_prefix(&persistent_control, root);
+ if (r < 0)
+ return r;
+
+ r = patch_root_prefix(&runtime_control, root);
+ if (r < 0)
+ return r;
+
+ r = patch_root_prefix_strv(paths, root);
+ if (r < 0)
return -ENOMEM;
- if (!strv_isempty(p->unit_path)) {
- _cleanup_free_ char *t = strv_join(p->unit_path, "\n\t");
- if (!t)
- return -ENOMEM;
- log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
- } else {
- log_debug("Ignoring unit files.");
- p->unit_path = strv_free(p->unit_path);
- }
+ p->search_path = strv_uniq(paths);
+ paths = NULL;
- if (running_as == MANAGER_SYSTEM) {
-#ifdef HAVE_SYSV_COMPAT
- /* /etc/init.d/ compatibility does not matter to users */
+ p->persistent_config = persistent_config;
+ p->runtime_config = runtime_config;
+ persistent_config = runtime_config = NULL;
- e = getenv("SYSTEMD_SYSVINIT_PATH");
- if (e) {
- r = path_split_and_make_absolute(e, &p->sysvinit_path);
- if (r < 0)
- return r;
- } else
- p->sysvinit_path = NULL;
+ p->generator = generator;
+ p->generator_early = generator_early;
+ p->generator_late = generator_late;
+ generator = generator_early = generator_late = NULL;
- if (strv_isempty(p->sysvinit_path)) {
- strv_free(p->sysvinit_path);
+ p->transient = transient;
+ transient = NULL;
- p->sysvinit_path = strv_new(
- SYSTEM_SYSVINIT_PATH, /* /etc/init.d/ */
- NULL);
- if (!p->sysvinit_path)
- return -ENOMEM;
- }
+ p->persistent_control = persistent_control;
+ p->runtime_control = runtime_control;
+ persistent_control = runtime_control = NULL;
- e = getenv("SYSTEMD_SYSVRCND_PATH");
- if (e) {
- r = path_split_and_make_absolute(e, &p->sysvrcnd_path);
- if (r < 0)
- return r;
- } else
- p->sysvrcnd_path = NULL;
+ p->root_dir = root;
+ root = NULL;
- if (strv_isempty(p->sysvrcnd_path)) {
- strv_free(p->sysvrcnd_path);
+ return 0;
+}
- p->sysvrcnd_path = strv_new(
- SYSTEM_SYSVRCND_PATH, /* /etc/rcN.d/ */
- NULL);
- if (!p->sysvrcnd_path)
- return -ENOMEM;
+void lookup_paths_free(LookupPaths *p) {
+ if (!p)
+ return;
+
+ p->search_path = strv_free(p->search_path);
+
+ p->persistent_config = mfree(p->persistent_config);
+ p->runtime_config = mfree(p->runtime_config);
+
+ p->generator = mfree(p->generator);
+ p->generator_early = mfree(p->generator_early);
+ p->generator_late = mfree(p->generator_late);
+
+ p->transient = mfree(p->transient);
+
+ p->persistent_control = mfree(p->persistent_control);
+ p->runtime_control = mfree(p->runtime_control);
+
+ p->root_dir = mfree(p->root_dir);
+}
+
+int lookup_paths_reduce(LookupPaths *p) {
+ _cleanup_free_ struct stat *stats = NULL;
+ size_t n_stats = 0, allocated = 0;
+ unsigned c = 0;
+ int r;
+
+ assert(p);
+
+ /* Drop duplicates and non-existing directories from the search path. We figure out whether two directories are
+ * the same by comparing their device and inode numbers. Note one special tweak: when we have a root path set,
+ * we do not follow symlinks when retrieving them, because the kernel wouldn't take the root prefix into
+ * account when following symlinks. When we have no root path set this restriction does not apply however. */
+
+ if (!p->search_path)
+ return 0;
+
+ while (p->search_path[c]) {
+ struct stat st;
+ unsigned k;
+
+ if (p->root_dir)
+ r = lstat(p->search_path[c], &st);
+ else
+ r = stat(p->search_path[c], &st);
+ if (r < 0) {
+ if (errno == ENOENT)
+ goto remove_item;
+
+ /* If something we don't grok happened, let's better leave it in. */
+ log_debug_errno(errno, "Failed to stat %s: %m", p->search_path[c]);
+ c++;
+ continue;
}
- if (!path_strv_resolve_uniq(p->sysvinit_path, root_dir))
- return -ENOMEM;
+ for (k = 0; k < n_stats; k++) {
+ if (stats[k].st_dev == st.st_dev &&
+ stats[k].st_ino == st.st_ino)
+ break;
+ }
+
+ if (k < n_stats) /* Is there already an entry with the same device/inode? */
+ goto remove_item;
- if (!path_strv_resolve_uniq(p->sysvrcnd_path, root_dir))
+ if (!GREEDY_REALLOC(stats, allocated, n_stats+1))
return -ENOMEM;
- if (!strv_isempty(p->sysvinit_path)) {
- _cleanup_free_ char *t = strv_join(p->sysvinit_path, "\n\t");
- if (!t)
- return -ENOMEM;
- log_debug("Looking for SysV init scripts in:\n\t%s", t);
- } else {
- log_debug("Ignoring SysV init scripts.");
- p->sysvinit_path = strv_free(p->sysvinit_path);
- }
+ stats[n_stats++] = st;
+ c++;
+ continue;
- if (!strv_isempty(p->sysvrcnd_path)) {
- _cleanup_free_ char *t =
- strv_join(p->sysvrcnd_path, "\n\t");
- if (!t)
- return -ENOMEM;
+ remove_item:
+ free(p->search_path[c]);
+ memmove(p->search_path + c,
+ p->search_path + c + 1,
+ (strv_length(p->search_path + c + 1) + 1) * sizeof(char*));
+ }
- log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
- } else {
- log_debug("Ignoring SysV rcN.d links.");
- p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
- }
-#else
- log_debug("SysV init scripts and rcN.d links support disabled");
-#endif
+ if (strv_isempty(p->search_path)) {
+ log_debug("Ignoring unit files.");
+ p->search_path = strv_free(p->search_path);
+ } else {
+ _cleanup_free_ char *t;
+
+ t = strv_join(p->search_path, "\n\t");
+ if (!t)
+ return -ENOMEM;
+
+ log_debug("Looking for unit files in (higher priority first):\n\t%s", t);
}
return 0;
}
-void lookup_paths_free(LookupPaths *p) {
+int lookup_paths_mkdir_generator(LookupPaths *p) {
+ int r, q;
+
assert(p);
- p->unit_path = strv_free(p->unit_path);
+ if (!p->generator || !p->generator_early || !p->generator_late)
+ return -EINVAL;
-#ifdef HAVE_SYSV_COMPAT
- p->sysvinit_path = strv_free(p->sysvinit_path);
- p->sysvrcnd_path = strv_free(p->sysvrcnd_path);
-#endif
+ r = mkdir_p_label(p->generator, 0755);
+
+ q = mkdir_p_label(p->generator_early, 0755);
+ if (q < 0 && r >= 0)
+ r = q;
+
+ q = mkdir_p_label(p->generator_late, 0755);
+ if (q < 0 && r >= 0)
+ r = q;
+
+ return r;
}
-int lookup_paths_init_from_scope(LookupPaths *paths,
- UnitFileScope scope,
- const char *root_dir) {
- assert(paths);
- assert(scope >= 0);
- assert(scope < _UNIT_FILE_SCOPE_MAX);
+void lookup_paths_trim_generator(LookupPaths *p) {
+ assert(p);
- zero(*paths);
+ /* Trim empty dirs */
+
+ if (p->generator)
+ (void) rmdir(p->generator);
+ if (p->generator_early)
+ (void) rmdir(p->generator_early);
+ if (p->generator_late)
+ (void) rmdir(p->generator_late);
+}
+
+void lookup_paths_flush_generator(LookupPaths *p) {
+ assert(p);
- return lookup_paths_init(paths,
- scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
- scope == UNIT_FILE_USER,
- root_dir,
- NULL, NULL, NULL);
+ /* Flush the generated unit files in full */
+
+ if (p->generator)
+ (void) rm_rf(p->generator, REMOVE_ROOT);
+ if (p->generator_early)
+ (void) rm_rf(p->generator_early, REMOVE_ROOT);
+ if (p->generator_late)
+ (void) rm_rf(p->generator_late, REMOVE_ROOT);
+}
+
+char **generator_binary_paths(UnitFileScope scope) {
+
+ switch (scope) {
+
+ case UNIT_FILE_SYSTEM:
+ return strv_new("/run/systemd/system-generators",
+ "/etc/systemd/system-generators",
+ "/usr/local/lib/systemd/system-generators",
+ SYSTEM_GENERATOR_PATH,
+ NULL);
+
+ case UNIT_FILE_GLOBAL:
+ case UNIT_FILE_USER:
+ return strv_new("/run/systemd/user-generators",
+ "/etc/systemd/user-generators",
+ "/usr/local/lib/systemd/user-generators",
+ USER_GENERATOR_PATH,
+ NULL);
+
+ default:
+ assert_not_reached("Hmm, unexpected scope.");
+ }
}
diff --git a/src/libshared/path-lookup.h b/src/libshared/path-lookup.h
index 26c83d6111..f9bb2fe237 100644
--- a/src/libshared/path-lookup.h
+++ b/src/libshared/path-lookup.h
@@ -20,41 +20,57 @@
***/
#include <stdbool.h>
-#include "macro.h"
-typedef struct LookupPaths {
- char **unit_path;
-#ifdef HAVE_SYSV_COMPAT
- char **sysvinit_path;
- char **sysvrcnd_path;
-#endif
-} LookupPaths;
-
-typedef enum ManagerRunningAs {
- MANAGER_SYSTEM,
- MANAGER_USER,
- _MANAGER_RUNNING_AS_MAX,
- _MANAGER_RUNNING_AS_INVALID = -1
-} ManagerRunningAs;
-
-int user_config_home(char **config_home);
-int user_runtime_dir(char **runtime_dir);
-
-char **generator_paths(ManagerRunningAs running_as);
-
-int lookup_paths_init(LookupPaths *p,
- ManagerRunningAs running_as,
- bool personal,
- const char *root_dir,
- const char *generator,
- const char *generator_early,
- const char *generator_late);
+typedef struct LookupPaths LookupPaths;
#include "install.h"
+#include "macro.h"
+
+typedef enum LookupPathsFlags {
+ LOOKUP_PATHS_EXCLUDE_GENERATED = 1,
+} LookupPathsFlags;
+
+struct LookupPaths {
+ /* Where we look for unit files. This includes the individual special paths below, but also any vendor
+ * supplied, static unit file paths. */
+ char **search_path;
+
+ /* Where we shall create or remove our installation symlinks, aka "configuration", and where the user/admin
+ * shall place his own unit files. */
+ char *persistent_config;
+ char *runtime_config;
+
+ /* Where to place generated unit files (i.e. those a "generator" tool generated). Note the special semantics of
+ * this directory: the generators are flushed each time a "systemctl daemon-reload" is issued. The user should
+ * not alter these directories directly. */
+ char *generator;
+ char *generator_early;
+ char *generator_late;
-int lookup_paths_init_from_scope(LookupPaths *paths,
- UnitFileScope scope,
- const char *root_dir);
+ /* Where to place transient unit files (i.e. those created dynamically via the bus API). Note the special
+ * semantics of this directory: all units created transiently have their unit files removed as the transient
+ * unit is unloaded. The user should not alter this directory directly. */
+ char *transient;
+
+ /* Where the snippets created by "systemctl set-property" are placed. Note that for transient units, the
+ * snippets are placed in the transient directory though (see above). The user should not alter this directory
+ * directly. */
+ char *persistent_control;
+ char *runtime_control;
+
+ /* The root directory prepended to all items above, or NULL */
+ char *root_dir;
+};
+
+int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir);
+
+int lookup_paths_reduce(LookupPaths *p);
+
+int lookup_paths_mkdir_generator(LookupPaths *p);
+void lookup_paths_trim_generator(LookupPaths *p);
+void lookup_paths_flush_generator(LookupPaths *p);
void lookup_paths_free(LookupPaths *p);
#define _cleanup_lookup_paths_free_ _cleanup_(lookup_paths_free)
+
+char **generator_binary_paths(UnitFileScope scope);
diff --git a/src/libshared/ptyfwd.c b/src/libshared/ptyfwd.c
index a97e0d5143..9629b50ed9 100644
--- a/src/libshared/ptyfwd.c
+++ b/src/libshared/ptyfwd.c
@@ -461,10 +461,7 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) {
if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b)
return 0;
- if (b)
- f->flags |= PTY_FORWARD_IGNORE_VHANGUP;
- else
- f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP;
+ SET_FLAG(f->flags, PTY_FORWARD_IGNORE_VHANGUP, b);
if (!ignore_vhangup(f)) {
diff --git a/src/libshared/sleep-config.c b/src/libshared/sleep-config.c
index a0aef66bc8..f00624d0f2 100644
--- a/src/libshared/sleep-config.c
+++ b/src/libshared/sleep-config.c
@@ -28,6 +28,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
#include "def.h"
+#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "log.h"
@@ -37,7 +38,7 @@
#include "string-util.h"
#include "strv.h"
-#define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0)
+#define USE(x, y) do { (x) = (y); (y) = NULL; } while (0)
int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
@@ -231,6 +232,9 @@ static bool enough_memory_for_hibernation(void) {
size_t size = 0, used = 0;
int r;
+ if (getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0)
+ return true;
+
r = hibernation_partition_size(&size, &used);
if (r < 0)
return false;
diff --git a/src/libshared/sleep-config.h b/src/libshared/sleep-config.h
index 51f4621844..ad10039ff4 100644
--- a/src/libshared/sleep-config.h
+++ b/src/libshared/sleep-config.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
int parse_sleep_config(const char *verb, char ***modes, char ***states);
int can_sleep(const char *verb);
diff --git a/src/libshared/spawn-polkit-agent.c b/src/libshared/spawn-polkit-agent.c
index cf3c8ad5a3..7dae4d14fe 100644
--- a/src/libshared/spawn-polkit-agent.c
+++ b/src/libshared/spawn-polkit-agent.c
@@ -44,6 +44,10 @@ int polkit_agent_open(void) {
if (agent_pid > 0)
return 0;
+ /* Clients that run as root don't need to activate/query polkit */
+ if (geteuid() == 0)
+ return 0;
+
/* We check STDIN here, not STDOUT, since this is about input,
* not output */
if (!isatty(STDIN_FILENO))
diff --git a/src/systemd-bootchart/store.h b/src/libshared/tests.c
index 6e9acf2a6f..409116290d 100644
--- a/src/systemd-bootchart/store.h
+++ b/src/libshared/tests.c
@@ -1,12 +1,7 @@
-#pragma once
-
/***
This file is part of systemd.
- Copyright (C) 2009-2013 Intel Corporation
-
- Authors:
- Auke Kok <auke-jan.h.kok@intel.com>
+ Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -22,15 +17,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <dirent.h>
+#include <stdlib.h>
+#include <util.h>
+
+#include "tests.h"
+
+char* setup_fake_runtime_dir(void) {
+ char t[] = "/tmp/fake-xdg-runtime-XXXXXX", *p;
-#include "bootchart.h"
+ assert_se(mkdtemp(t));
+ assert_se(setenv("XDG_RUNTIME_DIR", t, 1) >= 0);
+ assert_se(p = strdup(t));
-double gettime_ns(void);
-void log_uptime(void);
-int log_sample(DIR *proc,
- int sample,
- struct ps_struct *ps_first,
- struct list_sample_data **ptr,
- int *pscount,
- int *cpus);
+ return p;
+}
diff --git a/src/import/aufs-util.h b/src/libshared/tests.h
index e474a50897..93f09013a1 100644
--- a/src/import/aufs-util.h
+++ b/src/libshared/tests.h
@@ -3,7 +3,7 @@
/***
This file is part of systemd.
- Copyright 2014 Lennart Poettering
+ Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -19,4 +19,4 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int aufs_resolve(const char *path);
+char* setup_fake_runtime_dir(void);
diff --git a/src/libshared/uid-range.c b/src/libshared/uid-range.c
index eb251492c3..b6ec474390 100644
--- a/src/libshared/uid-range.c
+++ b/src/libshared/uid-range.c
@@ -54,7 +54,7 @@ static void uid_range_coalesce(UidRange **p, unsigned *n) {
if (*n > j+1)
memmove(y, y+1, sizeof(UidRange) * (*n - j -1));
- (*n) --;
+ (*n)--;
j--;
}
}
diff --git a/src/libsystemd-network/Makefile b/src/libsystemd-network/Makefile
index 45f782b184..6b16906c17 100644
--- a/src/libsystemd-network/Makefile
+++ b/src/libsystemd-network/Makefile
@@ -68,15 +68,11 @@ libsystemd_network_la_SOURCES = \
src/libsystemd-network/sd-dhcp6-lease.c \
src/libsystemd-network/dhcp-identifier.h \
src/libsystemd-network/dhcp-identifier.c \
- src/libsystemd-network/lldp.h \
- src/libsystemd-network/lldp-tlv.h \
- src/libsystemd-network/lldp-tlv.c \
+ src/libsystemd-network/lldp-internal.h \
src/libsystemd-network/lldp-network.h \
src/libsystemd-network/lldp-network.c \
- src/libsystemd-network/lldp-port.h \
- src/libsystemd-network/lldp-port.c \
- src/libsystemd-network/lldp-internal.h \
- src/libsystemd-network/lldp-internal.c \
+ src/libsystemd-network/lldp-neighbor.h \
+ src/libsystemd-network/lldp-neighbor.c \
src/libsystemd-network/sd-lldp.c
libsystemd_network_la_LIBADD = \
@@ -159,9 +155,6 @@ test_dhcp6_client_LDADD = \
libshared.la
test_lldp_SOURCES = \
- src/libsystemd-network/lldp.h \
- src/libsystemd-network/lldp-tlv.h \
- src/libsystemd-network/lldp-tlv.c \
src/libsystemd-network/test-lldp.c
test_lldp_LDADD = \
diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c
index d58f9029cc..906d960171 100644
--- a/src/libsystemd-network/dhcp-identifier.c
+++ b/src/libsystemd-network/dhcp-identifier.c
@@ -31,6 +31,37 @@
#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)
+int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len) {
+ struct duid d;
+
+ assert_cc(sizeof(d.raw) >= MAX_DUID_LEN);
+ if (duid_len > MAX_DUID_LEN)
+ return -EINVAL;
+
+ switch (duid_type) {
+ case DUID_TYPE_LLT:
+ if (duid_len <= sizeof(d.llt))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_EN:
+ if (duid_len != sizeof(d.en))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_LL:
+ if (duid_len <= sizeof(d.ll))
+ return -EINVAL;
+ break;
+ case DUID_TYPE_UUID:
+ if (duid_len != sizeof(d.uuid))
+ return -EINVAL;
+ break;
+ default:
+ /* accept unknown type in order to be forward compatible */
+ break;
+ }
+ return 0;
+}
+
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
sd_id128_t machine_id;
uint64_t hash;
@@ -43,7 +74,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) {
if (r < 0)
return r;
- unaligned_write_be16(&duid->type, DHCP6_DUID_EN);
+ unaligned_write_be16(&duid->type, DUID_TYPE_EN);
unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN);
*len = sizeof(duid->type) + sizeof(duid->en);
diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h
index 31f461abd1..802a0d6bc2 100644
--- a/src/libsystemd-network/dhcp-identifier.h
+++ b/src/libsystemd-network/dhcp-identifier.h
@@ -25,32 +25,42 @@
#include "sparse-endian.h"
#include "unaligned.h"
+typedef enum DUIDType {
+ DUID_TYPE_LLT = 1,
+ DUID_TYPE_EN = 2,
+ DUID_TYPE_LL = 3,
+ DUID_TYPE_UUID = 4,
+ _DUID_TYPE_MAX,
+ _DUID_TYPE_INVALID = -1,
+} DUIDType;
+
/* RFC 3315 section 9.1:
* A DUID can be no more than 128 octets long (not including the type code).
*/
#define MAX_DUID_LEN 128
+/* https://tools.ietf.org/html/rfc3315#section-9.1 */
struct duid {
- uint16_t type;
+ be16_t type;
union {
struct {
- /* DHCP6_DUID_LLT */
+ /* DUID_TYPE_LLT */
uint16_t htype;
uint32_t time;
uint8_t haddr[0];
} _packed_ llt;
struct {
- /* DHCP6_DUID_EN */
+ /* DUID_TYPE_EN */
uint32_t pen;
uint8_t id[8];
} _packed_ en;
struct {
- /* DHCP6_DUID_LL */
+ /* DUID_TYPE_LL */
int16_t htype;
uint8_t haddr[0];
} _packed_ ll;
struct {
- /* DHCP6_DUID_UUID */
+ /* DUID_TYPE_UUID */
sd_id128_t uuid;
} _packed_ uuid;
struct {
@@ -59,5 +69,6 @@ struct duid {
};
} _packed_;
+int dhcp_validate_duid_len(uint16_t duid_type, size_t duid_len);
int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len);
int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id);
diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h
index 51cb193847..dda4c13919 100644
--- a/src/libsystemd-network/dhcp-internal.h
+++ b/src/libsystemd-network/dhcp-internal.h
@@ -42,10 +42,10 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload,
uint8_t code, size_t optlen, const void *optval);
-typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len,
+typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len,
const void *option, void *userdata);
-int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message);
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message);
int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid,
uint8_t type, uint16_t arp_type, size_t optlen,
diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c
index df1996c8ce..c105196334 100644
--- a/src/libsystemd-network/dhcp-option.c
+++ b/src/libsystemd-network/dhcp-option.c
@@ -34,7 +34,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
if (code != SD_DHCP_OPTION_END)
/* always make sure there is space for an END option */
- size --;
+ size--;
switch (code) {
@@ -54,12 +54,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset,
options[*offset] = code;
options[*offset + 1] = optlen;
- if (optlen) {
- assert(optval);
-
- memcpy(&options[*offset + 2], optval, optlen);
- }
-
+ memcpy_safe(&options[*offset + 2], optval, optlen);
*offset += optlen + 2;
break;
@@ -140,7 +135,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset,
}
static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload,
- uint8_t *message_type, char **error_message, dhcp_option_cb_t cb,
+ uint8_t *message_type, char **error_message, dhcp_option_callback_t cb,
void *userdata) {
uint8_t code, len;
const uint8_t *option;
@@ -226,7 +221,7 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo
return 0;
}
-int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) {
+int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) {
_cleanup_free_ char *error_message = NULL;
uint8_t overload = 0;
uint8_t message_type = 0;
diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c
index 8d75d49691..8be774061d 100644
--- a/src/libsystemd-network/dhcp-packet.c
+++ b/src/libsystemd-network/dhcp-packet.c
@@ -66,7 +66,7 @@ uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) {
/* wrap around in one's complement */
sum++;
- buf_64 ++;
+ buf_64++;
}
if (len % sizeof(uint64_t)) {
diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h
index a5306b2907..7ba1e72155 100644
--- a/src/libsystemd-network/dhcp-server-internal.h
+++ b/src/libsystemd-network/dhcp-server-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <systemd/sd-dhcp-server.h>
#include <systemd/sd-event.h>
@@ -63,6 +63,8 @@ struct sd_dhcp_server {
struct in_addr *ntp, *dns;
unsigned n_ntp, n_dns;
+ bool emit_router;
+
Hashmap *leases_by_client_id;
DHCPLease **bound_leases;
DHCPLease invalid_lease;
diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h
index 228feb49d8..4228053ade 100644
--- a/src/libsystemd-network/dhcp6-internal.h
+++ b/src/libsystemd-network/dhcp6-internal.h
@@ -55,7 +55,8 @@ struct DHCP6IA {
typedef struct DHCP6IA DHCP6IA;
-#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#define log_dhcp6_client_errno(p, error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__)
+#define log_dhcp6_client(p, fmt, ...) log_dhcp6_client_errno(p, 0, fmt, ##__VA_ARGS__)
int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
size_t optlen, const void *optval);
diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c
index 91d7f8a7da..0ae381ad22 100644
--- a/src/libsystemd-network/dhcp6-option.c
+++ b/src/libsystemd-network/dhcp6-option.c
@@ -71,8 +71,7 @@ int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code,
if (r < 0)
return r;
- if (optval)
- memcpy(*buf, optval, optlen);
+ memcpy_safe(*buf, optval, optlen);
*buf += optlen;
*buflen -= optlen;
diff --git a/src/libsystemd-network/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h
index ee4bdfb07f..2487c470ab 100644
--- a/src/libsystemd-network/dhcp6-protocol.h
+++ b/src/libsystemd-network/dhcp6-protocol.h
@@ -62,13 +62,6 @@ enum {
#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC
#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC
-enum {
- DHCP6_DUID_LLT = 1,
- DHCP6_DUID_EN = 2,
- DHCP6_DUID_LL = 3,
- DHCP6_DUID_UUID = 4,
-};
-
enum DHCP6State {
DHCP6_STATE_STOPPED = 0,
DHCP6_STATE_INFORMATION_REQUEST = 1,
diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c
deleted file mode 100644
index 902a262f39..0000000000
--- a/src/libsystemd-network/lldp-internal.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 <systemd/sd-lldp.h>
-
-#include "alloc-util.h"
-#include "lldp-internal.h"
-
-/* We store maximum 1K chassis entries */
-#define LLDP_MIB_MAX_CHASSIS 1024
-
-/* Maximum Ports can be attached to any chassis */
-#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32
-
-/* 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
- * indicated by the LLDP remote systems update process defined in 10.3.5 */
-
-int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) {
- lldp_neighbour_port *p;
- uint16_t length, ttl;
- uint8_t *data;
- uint8_t type;
- int r;
-
- assert_return(c, -EINVAL);
- assert_return(tlv, -EINVAL);
-
- r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- /* Update the packet if we already have */
- LIST_FOREACH(port, p, c->ports) {
-
- if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) {
-
- r = sd_lldp_packet_read_ttl(tlv, &ttl);
- if (r < 0)
- return r;
-
- p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
-
- sd_lldp_packet_unref(p->packet);
- p->packet = tlv;
-
- prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx);
-
- return 0;
- }
- }
-
- return -1;
-}
-
-int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) {
- lldp_neighbour_port *p, *q;
- uint8_t *data;
- uint16_t length;
- uint8_t type;
- int r;
-
- assert_return(c, -EINVAL);
- assert_return(tlv, -EINVAL);
-
- r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- LIST_FOREACH_SAFE(port, p, q, c->ports) {
-
- /* Find the port */
- if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) {
- lldp_neighbour_port_remove_and_free(p);
- break;
- }
- }
-
- return 0;
-}
-
-int lldp_mib_add_objects(Prioq *by_expiry,
- Hashmap *neighbour_mib,
- tlv_packet *tlv) {
- _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
- _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
- lldp_chassis_id chassis_id;
- bool new_chassis = false;
- uint8_t subtype, *data;
- uint16_t ttl, length;
- int r;
-
- assert_return(by_expiry, -EINVAL);
- assert_return(neighbour_mib, -EINVAL);
- assert_return(tlv, -EINVAL);
-
- r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length);
- if (r < 0)
- goto drop;
-
- r = sd_lldp_packet_read_ttl(tlv, &ttl);
- if (r < 0)
- goto drop;
-
- /* Make hash key */
- chassis_id.type = subtype;
- chassis_id.length = length;
- chassis_id.data = data;
-
- /* Try to find the Chassis */
- c = hashmap_get(neighbour_mib, &chassis_id);
- if (!c) {
-
- /* Don't create chassis if ttl 0 is received . Silently drop it */
- if (ttl == 0) {
- log_lldp("TTL value 0 received. Skiping Chassis creation.");
- goto drop;
- }
-
- /* Admission Control: Can we store this packet ? */
- if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) {
-
- log_lldp("Exceeding number of chassie: %d. Dropping ...",
- hashmap_size(neighbour_mib));
- goto drop;
- }
-
- r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c);
- if (r < 0)
- goto drop;
-
- new_chassis = true;
-
- r = hashmap_put(neighbour_mib, &c->chassis_id, c);
- if (r < 0)
- goto drop;
-
- } else {
-
- /* When the TTL field is set to zero, the receiving LLDP agent is notified all
- * system information associated with the LLDP agent/port is to be deleted */
- if (ttl == 0) {
- log_lldp("TTL value 0 received . Deleting associated Port ...");
-
- lldp_mib_remove_objects(c, tlv);
-
- c = NULL;
- goto drop;
- }
-
- /* if we already have this port just update it */
- r = lldp_mib_update_objects(c, tlv);
- if (r >= 0) {
- c = NULL;
- return r;
- }
-
- /* Admission Control: Can this port attached to the existing chassis ? */
- if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) {
- log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref);
-
- c = NULL;
- goto drop;
- }
- }
-
- /* This is a new port */
- r = lldp_neighbour_port_new(c, tlv, &p);
- if (r < 0)
- goto drop;
-
- r = prioq_put(c->by_expiry, p, &p->prioq_idx);
- if (r < 0)
- goto drop;
-
- /* Attach new port to chassis */
- LIST_PREPEND(port, c->ports, p);
- c->n_ref ++;
-
- p = NULL;
- c = NULL;
-
- return 0;
-
- drop:
- sd_lldp_packet_unref(tlv);
-
- if (new_chassis)
- hashmap_remove(neighbour_mib, &c->chassis_id);
-
- return r;
-}
-
-void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) {
- lldp_chassis *c;
-
- assert(p);
- assert(p->c);
-
- c = p->c;
-
- prioq_remove(c->by_expiry, p, &p->prioq_idx);
-
- LIST_REMOVE(port, c->ports, p);
- lldp_neighbour_port_free(p);
-
- /* Drop the Chassis if no port is attached */
- c->n_ref --;
- if (c->n_ref <= 1) {
- hashmap_remove(c->neighbour_mib, &c->chassis_id);
- lldp_chassis_free(c);
- }
-}
-
-void lldp_neighbour_port_free(lldp_neighbour_port *p) {
-
- if(!p)
- return;
-
- sd_lldp_packet_unref(p->packet);
-
- free(p->data);
- free(p);
-}
-
-int lldp_neighbour_port_new(lldp_chassis *c,
- tlv_packet *tlv,
- lldp_neighbour_port **ret) {
- _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL;
- uint16_t length, ttl;
- uint8_t *data;
- uint8_t type;
- int r;
-
- assert(tlv);
-
- r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- r = sd_lldp_packet_read_ttl(tlv, &ttl);
- if (r < 0)
- return r;
-
- p = new0(lldp_neighbour_port, 1);
- if (!p)
- return -ENOMEM;
-
- p->c = c;
- p->type = type;
- p->length = length;
- p->packet = tlv;
- p->prioq_idx = PRIOQ_IDX_NULL;
- p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic());
-
- p->data = memdup(data, length);
- if (!p->data)
- return -ENOMEM;
-
- *ret = p;
- p = NULL;
-
- return 0;
-}
-
-void lldp_chassis_free(lldp_chassis *c) {
-
- if (!c)
- return;
-
- if (c->n_ref > 1)
- return;
-
- free(c->chassis_id.data);
- free(c);
-}
-
-int lldp_chassis_new(tlv_packet *tlv,
- Prioq *by_expiry,
- Hashmap *neighbour_mib,
- lldp_chassis **ret) {
- _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL;
- uint16_t length;
- uint8_t *data;
- uint8_t type;
- int r;
-
- assert(tlv);
-
- r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length);
- if (r < 0)
- return r;
-
- c = new0(lldp_chassis, 1);
- if (!c)
- return -ENOMEM;
-
- c->n_ref = 1;
- c->chassis_id.type = type;
- c->chassis_id.length = length;
-
- c->chassis_id.data = memdup(data, length);
- if (!c->chassis_id.data)
- return -ENOMEM;
-
- LIST_HEAD_INIT(c->ports);
-
- c->by_expiry = by_expiry;
- c->neighbour_mib = neighbour_mib;
-
- *ret = c;
- c = NULL;
-
- return 0;
-}
-
-int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- _cleanup_(sd_lldp_packet_unrefp) 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 565149fbcf..a6be995e3b 100644
--- a/src/libsystemd-network/lldp-internal.h
+++ b/src/libsystemd-network/lldp-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,74 +20,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <systemd/sd-event.h>
+#include <systemd/sd-lldp.h>
-#include "list.h"
-#include "lldp-tlv.h"
+#include "hashmap.h"
#include "log.h"
#include "prioq.h"
-typedef struct lldp_neighbour_port lldp_neighbour_port;
-typedef struct lldp_chassis lldp_chassis;
-typedef struct lldp_chassis_id lldp_chassis_id;
-typedef struct lldp_agent_statistics lldp_agent_statistics;
+struct sd_lldp {
+ int ifindex;
+ int fd;
-struct lldp_neighbour_port {
- uint8_t type;
- uint8_t *data;
+ sd_event *event;
+ int64_t event_priority;
+ sd_event_source *io_event_source;
+ sd_event_source *timer_event_source;
- uint16_t length;
- usec_t until;
+ Prioq *neighbor_by_expiry;
+ Hashmap *neighbor_by_id;
- unsigned prioq_idx;
+ uint64_t neighbors_max;
- lldp_chassis *c;
- tlv_packet *packet;
+ sd_lldp_callback_t callback;
+ void *userdata;
- LIST_FIELDS(lldp_neighbour_port, port);
-};
+ uint16_t capability_mask;
-int lldp_neighbour_port_new(lldp_chassis *c, tlv_packet *tlv, lldp_neighbour_port **ret);
-void lldp_neighbour_port_free(lldp_neighbour_port *p);
-void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_neighbour_port *, lldp_neighbour_port_free);
-#define _cleanup_lldp_neighbour_port_free_ _cleanup_(lldp_neighbour_port_freep)
-
-struct lldp_chassis_id {
- uint8_t type;
- uint16_t length;
-
- uint8_t *data;
+ struct ether_addr filter_address;
};
-struct lldp_chassis {
- unsigned n_ref;
-
- lldp_chassis_id chassis_id;
-
- Prioq *by_expiry;
- Hashmap *neighbour_mib;
-
- LIST_HEAD(lldp_neighbour_port, ports);
-};
-
-int lldp_chassis_new(tlv_packet *tlv,
- Prioq *by_expiry,
- Hashmap *neighbour_mib,
- lldp_chassis **ret);
-
-void lldp_chassis_free(lldp_chassis *c);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_chassis *, lldp_chassis_free);
-#define _cleanup_lldp_chassis_free_ _cleanup_(lldp_chassis_freep)
-
-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_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__)
+#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__)
+#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__)
diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c
new file mode 100644
index 0000000000..6a716430e3
--- /dev/null
+++ b/src/libsystemd-network/lldp-neighbor.c
@@ -0,0 +1,794 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "ether-addr-util.h"
+#include "hexdecoct.h"
+#include "in-addr-util.h"
+#include "lldp-internal.h"
+#include "lldp-neighbor.h"
+#include "unaligned.h"
+
+static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) {
+ const LLDPNeighborID *id = p;
+
+ siphash24_compress(id->chassis_id, id->chassis_id_size, state);
+ siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state);
+ siphash24_compress(id->port_id, id->port_id_size, state);
+ siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state);
+}
+
+static int lldp_neighbor_id_compare_func(const void *a, const void *b) {
+ const LLDPNeighborID *x = a, *y = b;
+ int r;
+
+ r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size));
+ if (r != 0)
+ return r;
+
+ if (x->chassis_id_size < y->chassis_id_size)
+ return -1;
+
+ if (x->chassis_id_size > y->chassis_id_size)
+ return 1;
+
+ r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size));
+ if (r != 0)
+ return r;
+
+ if (x->port_id_size < y->port_id_size)
+ return -1;
+ if (x->port_id_size > y->port_id_size)
+ return 1;
+
+ return 0;
+}
+
+const struct hash_ops lldp_neighbor_id_hash_ops = {
+ .hash = lldp_neighbor_id_hash_func,
+ .compare = lldp_neighbor_id_compare_func
+};
+
+int lldp_neighbor_prioq_compare_func(const void *a, const void *b) {
+ const sd_lldp_neighbor *x = a, *y = b;
+
+ if (x->until < y->until)
+ return -1;
+
+ if (x->until > y->until)
+ return 1;
+
+ return 0;
+}
+
+_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) {
+ if (!n)
+ return NULL;
+
+ assert(n->n_ref > 0 || n->lldp);
+ n->n_ref++;
+
+ return n;
+}
+
+static void lldp_neighbor_free(sd_lldp_neighbor *n) {
+ assert(n);
+
+ free(n->id.port_id);
+ free(n->id.chassis_id);
+ free(n->port_description);
+ free(n->system_name);
+ free(n->system_description);
+ free(n->chassis_id_as_string);
+ free(n->port_id_as_string);
+ free(n);
+}
+
+_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) {
+
+ /* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from
+ * the sd_lldp object. */
+
+ if (!n)
+ return NULL;
+
+ assert(n->n_ref > 0);
+ n->n_ref--;
+
+ if (n->n_ref <= 0 && !n->lldp)
+ lldp_neighbor_free(n);
+
+ return NULL;
+}
+
+sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) {
+
+ /* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */
+
+ if (!n)
+ return NULL;
+
+ if (!n->lldp)
+ return NULL;
+
+ assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n);
+ assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0);
+
+ n->lldp = NULL;
+
+ if (n->n_ref <= 0)
+ lldp_neighbor_free(n);
+
+ return NULL;
+}
+
+sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) {
+ sd_lldp_neighbor *n;
+
+ n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size);
+ if (!n)
+ return NULL;
+
+ n->raw_size = raw_size;
+ n->n_ref = 1;
+
+ return n;
+}
+
+static int parse_string(char **s, const void *q, size_t n) {
+ const char *p = q;
+ char *k;
+
+ assert(s);
+ assert(p || n == 0);
+
+ if (*s) {
+ log_lldp("Found duplicate string, ignoring field.");
+ return 0;
+ }
+
+ /* Strip trailing NULs, just to be nice */
+ while (n > 0 && p[n-1] == 0)
+ n--;
+
+ if (n <= 0) /* Ignore empty strings */
+ return 0;
+
+ /* Look for inner NULs */
+ if (memchr(p, 0, n)) {
+ log_lldp("Found inner NUL in string, ignoring field.");
+ return 0;
+ }
+
+ /* Let's escape weird chars, for security reasons */
+ k = cescape_length(p, n);
+ if (!k)
+ return -ENOMEM;
+
+ free(*s);
+ *s = k;
+
+ return 1;
+}
+
+int lldp_neighbor_parse(sd_lldp_neighbor *n) {
+ struct ether_header h;
+ const uint8_t *p;
+ size_t left;
+ int r;
+
+ assert(n);
+
+ if (n->raw_size < sizeof(struct ether_header)) {
+ log_lldp("Recieved truncated packet, ignoring.");
+ return -EBADMSG;
+ }
+
+ memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h));
+
+ if (h.ether_type != htobe16(ETHERTYPE_LLDP)) {
+ log_lldp("Received packet with wrong type, ignoring.");
+ return -EBADMSG;
+ }
+
+ if (h.ether_dhost[0] != 0x01 ||
+ h.ether_dhost[1] != 0x80 ||
+ h.ether_dhost[2] != 0xc2 ||
+ h.ether_dhost[3] != 0x00 ||
+ h.ether_dhost[4] != 0x00 ||
+ !IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) {
+ log_lldp("Received packet with wrong destination address, ignoring.");
+ return -EBADMSG;
+ }
+
+ memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr));
+ memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr));
+
+ p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header);
+ left = n->raw_size - sizeof(struct ether_header);
+
+ for (;;) {
+ uint8_t type;
+ uint16_t length;
+
+ if (left < 2) {
+ log_lldp("TLV lacks header, ignoring.");
+ return -EBADMSG;
+ }
+
+ type = p[0] >> 1;
+ length = p[1] + (((uint16_t) (p[0] & 1)) << 8);
+ p += 2, left -= 2;
+
+ if (left < length) {
+ log_lldp("TLV truncated, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ switch (type) {
+
+ case SD_LLDP_TYPE_END:
+ if (length != 0) {
+ log_lldp("End marker TLV not zero-sized, ignoring datagram.");
+ return -EBADMSG;
+ }
+ if (left != 0) {
+ log_lldp("Trailing garbage in datagram, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ goto end_marker;
+
+ case SD_LLDP_TYPE_CHASSIS_ID:
+ if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */
+ log_lldp("Chassis ID field size out of range, ignoring datagram.");
+ return -EBADMSG;
+ }
+ if (n->id.chassis_id) {
+ log_lldp("Duplicate chassis ID field, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ n->id.chassis_id = memdup(p, length);
+ if (!n->id.chassis_id)
+ return -ENOMEM;
+
+ n->id.chassis_id_size = length;
+ break;
+
+ case SD_LLDP_TYPE_PORT_ID:
+ if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */
+ log_lldp("Port ID field size out of range, ignoring datagram.");
+ return -EBADMSG;
+ }
+ if (n->id.port_id) {
+ log_lldp("Duplicate port ID field, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ n->id.port_id = memdup(p, length);
+ if (!n->id.port_id)
+ return -ENOMEM;
+
+ n->id.port_id_size = length;
+ break;
+
+ case SD_LLDP_TYPE_TTL:
+ if (length != 2) {
+ log_lldp("TTL field has wrong size, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ if (n->has_ttl) {
+ log_lldp("Duplicate TTL field, ignoring datagram.");
+ return -EBADMSG;
+ }
+
+ n->ttl = unaligned_read_be16(p);
+ n->has_ttl = true;
+ break;
+
+ case SD_LLDP_TYPE_PORT_DESCRIPTION:
+ r = parse_string(&n->port_description, p, length);
+ if (r < 0)
+ return r;
+ break;
+
+ case SD_LLDP_TYPE_SYSTEM_NAME:
+ r = parse_string(&n->system_name, p, length);
+ if (r < 0)
+ return r;
+ break;
+
+ case SD_LLDP_TYPE_SYSTEM_DESCRIPTION:
+ r = parse_string(&n->system_description, p, length);
+ if (r < 0)
+ return r;
+ break;
+
+ case SD_LLDP_TYPE_SYSTEM_CAPABILITIES:
+ if (length != 4)
+ log_lldp("System capabilities field has wrong size, ignoring.");
+ else {
+ n->system_capabilities = unaligned_read_be16(p);
+ n->enabled_capabilities = unaligned_read_be16(p + 2);
+ n->has_capabilities = true;
+ }
+
+ break;
+
+ case SD_LLDP_TYPE_PRIVATE:
+ if (length < 4)
+ log_lldp("Found private TLV that is too short, ignoring.");
+
+ break;
+ }
+
+
+ p += length, left -= length;
+ }
+
+end_marker:
+ if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) {
+ log_lldp("One or more mandatory TLV missing in datagram. Ignoring.");
+ return -EBADMSG;
+
+ }
+
+ n->rindex = sizeof(struct ether_header);
+
+ return 0;
+}
+
+void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) {
+ assert(n);
+
+ if (n->ttl > 0)
+ n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC);
+ else
+ n->until = 0;
+
+ if (n->lldp)
+ prioq_reshuffle(n->lldp->neighbor_by_expiry, n, &n->prioq_idx);
+}
+
+bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) {
+ if (a == b)
+ return true;
+
+ if (!a || !b)
+ return false;
+
+ if (a->raw_size != b->raw_size)
+ return false;
+
+ return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0;
+}
+
+_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) {
+ assert_return(n, -EINVAL);
+ assert_return(address, -EINVAL);
+
+ *address = n->source_address;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) {
+ assert_return(n, -EINVAL);
+ assert_return(address, -EINVAL);
+
+ *address = n->destination_address;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+ assert_return(size, -EINVAL);
+
+ *ret = LLDP_NEIGHBOR_RAW(n);
+ *size = n->raw_size;
+
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
+ assert_return(n, -EINVAL);
+ assert_return(type, -EINVAL);
+ assert_return(ret, -EINVAL);
+ assert_return(size, -EINVAL);
+
+ assert(n->id.chassis_id_size > 0);
+
+ *type = *(uint8_t*) n->id.chassis_id;
+ *ret = (uint8_t*) n->id.chassis_id + 1;
+ *size = n->id.chassis_id_size - 1;
+
+ return 0;
+}
+
+static int format_mac_address(const void *data, size_t sz, char **ret) {
+ struct ether_addr a;
+ char *k;
+
+ assert(data || sz <= 0);
+
+ if (sz != 7)
+ return 0;
+
+ memcpy(&a, (uint8_t*) data + 1, sizeof(a));
+
+ k = new(char, ETHER_ADDR_TO_STRING_MAX);
+ if (!k)
+ return -ENOMEM;
+
+ *ret = ether_addr_to_string(&a, k);
+ return 1;
+}
+
+static int format_network_address(const void *data, size_t sz, char **ret) {
+ union in_addr_union a;
+ int family, r;
+
+ if (sz == 6 && ((uint8_t*) data)[1] == 1) {
+ memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in));
+ family = AF_INET;
+ } else if (sz == 18 && ((uint8_t*) data)[1] == 2) {
+ memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6));
+ family = AF_INET6;
+ } else
+ return 0;
+
+ r = in_addr_to_string(family, &a, ret);
+ if (r < 0)
+ return r;
+ return 1;
+}
+
+_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) {
+ char *k;
+ int r;
+
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (n->chassis_id_as_string) {
+ *ret = n->chassis_id_as_string;
+ return 0;
+ }
+
+ assert(n->id.chassis_id_size > 0);
+
+ switch (*(uint8_t*) n->id.chassis_id) {
+
+ case SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT:
+ case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS:
+ case SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT:
+ case SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME:
+ case SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED:
+ k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1);
+ if (!k)
+ return -ENOMEM;
+
+ goto done;
+
+ case SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
+ r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ goto done;
+
+ break;
+
+ case SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS:
+ r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ goto done;
+
+ break;
+ }
+
+ /* Generic fallback */
+ k = hexmem(n->id.chassis_id, n->id.chassis_id_size);
+ if (!k)
+ return -ENOMEM;
+
+done:
+ *ret = n->chassis_id_as_string = k;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) {
+ assert_return(n, -EINVAL);
+ assert_return(type, -EINVAL);
+ assert_return(ret, -EINVAL);
+ assert_return(size, -EINVAL);
+
+ assert(n->id.port_id_size > 0);
+
+ *type = *(uint8_t*) n->id.port_id;
+ *ret = (uint8_t*) n->id.port_id + 1;
+ *size = n->id.port_id_size - 1;
+
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) {
+ char *k;
+ int r;
+
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (n->port_id_as_string) {
+ *ret = n->port_id_as_string;
+ return 0;
+ }
+
+ assert(n->id.port_id_size > 0);
+
+ switch (*(uint8_t*) n->id.port_id) {
+
+ case SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS:
+ case SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT:
+ case SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME:
+ case SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED:
+ k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1);
+ if (!k)
+ return -ENOMEM;
+
+ goto done;
+
+ case SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS:
+ r = format_mac_address(n->id.port_id, n->id.port_id_size, &k);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ goto done;
+
+ break;
+
+ case SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS:
+ r = format_network_address(n->id.port_id, n->id.port_id_size, &k);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ goto done;
+
+ break;
+ }
+
+ /* Generic fallback */
+ k = hexmem(n->id.port_id, n->id.port_id_size);
+ if (!k)
+ return -ENOMEM;
+
+done:
+ *ret = n->port_id_as_string = k;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = n->ttl;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!n->system_name)
+ return -ENODATA;
+
+ *ret = n->system_name;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!n->system_description)
+ return -ENODATA;
+
+ *ret = n->system_description;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!n->port_description)
+ return -ENODATA;
+
+ *ret = n->port_description;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!n->has_capabilities)
+ return -ENODATA;
+
+ *ret = n->system_capabilities;
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) {
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ if (!n->has_capabilities)
+ return -ENODATA;
+
+ *ret = n->enabled_capabilities;
+ return 0;
+}
+
+int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) {
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
+ int r;
+
+ assert_return(ret, -EINVAL);
+ assert_return(raw || raw_size <= 0, -EINVAL);
+
+ n = lldp_neighbor_new(raw_size);
+ if (!n)
+ return -ENOMEM;
+
+ memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size);
+ r = lldp_neighbor_parse(n);
+ if (r < 0)
+ return r;
+
+ *ret = n;
+ n = 0;
+
+ return r;
+}
+
+_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) {
+ assert_return(n, -EINVAL);
+
+ assert(n->raw_size >= sizeof(struct ether_header));
+ n->rindex = sizeof(struct ether_header);
+
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) {
+ size_t length;
+
+ assert_return(n, -EINVAL);
+
+ if (n->rindex == n->raw_size) /* EOF */
+ return -ESPIPE;
+
+ if (n->rindex + 2 > n->raw_size) /* Truncated message */
+ return -EBADMSG;
+
+ length = LLDP_NEIGHBOR_LENGTH(n);
+ if (n->rindex + 2 + length > n->raw_size)
+ return -EBADMSG;
+
+ n->rindex += 2 + length;
+ return n->rindex < n->raw_size;
+}
+
+_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) {
+ assert_return(n, -EINVAL);
+ assert_return(type, -EINVAL);
+
+ if (n->rindex == n->raw_size) /* EOF */
+ return -ESPIPE;
+
+ if (n->rindex + 2 > n->raw_size)
+ return -EBADMSG;
+
+ *type = LLDP_NEIGHBOR_TYPE(n);
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) {
+ uint8_t k;
+ int r;
+
+ assert_return(n, -EINVAL);
+
+ r = sd_lldp_neighbor_tlv_get_type(n, &k);
+ if (r < 0)
+ return r;
+
+ return type == k;
+}
+
+_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype) {
+ const uint8_t *d;
+ size_t length;
+ int r;
+
+ assert_return(n, -EINVAL);
+ assert_return(oui, -EINVAL);
+ assert_return(subtype, -EINVAL);
+
+ r = sd_lldp_neighbor_tlv_is_type(n, SD_LLDP_TYPE_PRIVATE);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENXIO;
+
+ length = LLDP_NEIGHBOR_LENGTH(n);
+ if (length < 4)
+ return -EBADMSG;
+
+ if (n->rindex + 2 + length > n->raw_size)
+ return -EBADMSG;
+
+ d = LLDP_NEIGHBOR_DATA(n);
+ memcpy(oui, d, 3);
+ *subtype = d[3];
+
+ return 0;
+}
+
+_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype) {
+ uint8_t k[3], st;
+ int r;
+
+ r = sd_lldp_neighbor_tlv_get_oui(n, k, &st);
+ if (r == -ENXIO)
+ return 0;
+ if (r < 0)
+ return r;
+
+ return memcmp(k, oui, 3) == 0 && st == subtype;
+}
+
+_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) {
+ size_t length;
+
+ assert_return(n, -EINVAL);
+ assert_return(ret, -EINVAL);
+ assert_return(size, -EINVAL);
+
+ /* Note that this returns the full TLV, including the TLV header */
+
+ if (n->rindex + 2 > n->raw_size)
+ return -EBADMSG;
+
+ length = LLDP_NEIGHBOR_LENGTH(n);
+
+ if (n->rindex + 2 + length > n->raw_size)
+ return -EBADMSG;
+
+ *ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
+ *size = length + 2;
+
+ return 0;
+}
diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h
new file mode 100644
index 0000000000..050159ab73
--- /dev/null
+++ b/src/libsystemd-network/lldp-neighbor.h
@@ -0,0 +1,106 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+#include <systemd/sd-lldp.h>
+
+#include "hash-funcs.h"
+#include "lldp-internal.h"
+#include "time-util.h"
+
+typedef struct LLDPNeighborID {
+ /* The spec calls this an "MSAP identifier" */
+ void *chassis_id;
+ size_t chassis_id_size;
+
+ void *port_id;
+ size_t port_id_size;
+} LLDPNeighborID;
+
+struct sd_lldp_neighbor {
+ /* Neighbor objects stay around as long as they are linked into an "sd_lldp" object or n_ref > 0. */
+ sd_lldp *lldp;
+ unsigned n_ref;
+
+ usec_t until;
+ unsigned prioq_idx;
+
+ struct ether_addr source_address;
+ struct ether_addr destination_address;
+
+ LLDPNeighborID id;
+
+ /* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */
+ size_t raw_size;
+
+ /* The current read index for the iterative TLV interface */
+ size_t rindex;
+
+ /* And a couple of fields parsed out. */
+ bool has_ttl:1;
+ bool has_capabilities:1;
+ bool has_port_vlan_id:1;
+
+ uint16_t ttl;
+
+ uint16_t system_capabilities;
+ uint16_t enabled_capabilities;
+
+ char *port_description;
+ char *system_name;
+ char *system_description;
+
+ uint16_t port_vlan_id;
+
+ char *chassis_id_as_string;
+ char *port_id_as_string;
+};
+
+static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) {
+ return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor));
+}
+
+static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) {
+ return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1;
+}
+
+static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) {
+ uint8_t *p;
+
+ p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex;
+ return p[1] + (((size_t) (p[0] & 1)) << 8);
+}
+
+static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) {
+ return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2;
+}
+
+extern const struct hash_ops lldp_neighbor_id_hash_ops;
+int lldp_neighbor_prioq_compare_func(const void *a, const void *b);
+
+sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n);
+sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size);
+int lldp_neighbor_parse(sd_lldp_neighbor *n);
+void lldp_neighbor_start_ttl(sd_lldp_neighbor *n);
+bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b);
diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c
index 42058c4449..f031760351 100644
--- a/src/libsystemd-network/lldp-network.c
+++ b/src/libsystemd-network/lldp-network.c
@@ -19,65 +19,58 @@
***/
#include <linux/filter.h>
-#include <linux/if_ether.h>
+#include <netinet/if_ether.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 {
- struct ethhdr hdr;
- uint8_t tlvs[0];
- } LLDPFrame;
- struct sock_filter filter[] = {
- BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest)), /* A <- 4 bytes of destination MAC */
+ static const struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ethhdr, h_dest)), /* A <- 4 bytes of destination MAC */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_proto)), /* A <- protocol */
+ BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */
BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */
BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */
};
- struct sock_fprog fprog = {
+ static const struct sock_fprog fprog = {
.len = ELEMENTSOF(filter),
- .filter = filter
+ .filter = (struct sock_filter*) filter,
};
- _cleanup_close_ int s = -1;
-
union sockaddr_union saddrll = {
.ll.sll_family = AF_PACKET,
.ll.sll_ifindex = ifindex,
};
+ _cleanup_close_ int fd = -1;
int r;
assert(ifindex > 0);
- s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (s < 0)
+ fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, htons(ETHERTYPE_LLDP));
+ if (fd < 0)
return -errno;
- r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
+ r = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
if (r < 0)
return -errno;
- r = bind(s, &saddrll.sa, sizeof(saddrll.ll));
+ r = bind(fd, &saddrll.sa, sizeof(saddrll.ll));
if (r < 0)
return -errno;
- r = s;
- s = -1;
+ r = fd;
+ fd = -1;
return r;
}
diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h
index 3eb03a102d..43ed54b3b2 100644
--- a/src/libsystemd-network/lldp-network.h
+++ b/src/libsystemd-network/lldp-network.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <systemd/sd-event.h>
int lldp_network_bind_raw_socket(int ifindex);
diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c
deleted file mode 100644
index c86f62a6c2..0000000000
--- a/src/libsystemd-network/lldp-port.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 "async.h"
-#include "lldp-internal.h"
-#include "lldp-network.h"
-#include "lldp-port.h"
-
-int lldp_port_start(lldp_port *p) {
- int r;
-
- assert_return(p, -EINVAL);
-
- r = lldp_network_bind_raw_socket(p->ifindex);
- if (r < 0)
- return r;
-
- p->rawfd = r;
-
- r = sd_event_add_io(p->event, &p->lldp_port_rx,
- p->rawfd, EPOLLIN, lldp_receive_packet, p);
- if (r < 0) {
- 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_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_errno(r, "Failed to set event name: %m");
- goto fail;
- }
-
- return 0;
-
-fail:
- lldp_port_stop(p);
-
- return r;
-}
-
-int lldp_port_stop(lldp_port *p) {
-
- assert_return(p, -EINVAL);
-
- p->rawfd = asynchronous_close(p->rawfd);
- p->lldp_port_rx = sd_event_source_unref(p->lldp_port_rx);
-
- return 0;
-}
-
-void lldp_port_free(lldp_port *p) {
- if (!p)
- return;
-
- lldp_port_stop(p);
-
- free(p->ifname);
- free(p);
-}
-
-int lldp_port_new(int ifindex,
- const char *ifname,
- const struct ether_addr *addr,
- void *userdata,
- lldp_port **ret) {
- _cleanup_free_ lldp_port *p = NULL;
-
- assert_return(ifindex, -EINVAL);
- assert_return(ifname, -EINVAL);
- assert_return(addr, -EINVAL);
-
- p = new0(lldp_port, 1);
- if (!p)
- return -ENOMEM;
-
- p->rawfd = -1;
- p->ifindex = ifindex;
-
- p->ifname = strdup(ifname);
- if (!p->ifname)
- return -ENOMEM;
-
- memcpy(&p->mac, addr, ETH_ALEN);
-
- p->userdata = userdata;
-
- *ret = p;
-
- p = NULL;
-
- return 0;
-}
diff --git a/src/libsystemd-network/lldp-port.h b/src/libsystemd-network/lldp-port.h
deleted file mode 100644
index 36e1edc17c..0000000000
--- a/src/libsystemd-network/lldp-port.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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/>.
-***/
-
-#pragma once
-
-#include <net/ethernet.h>
-
-#include <systemd/sd-event.h>
-#include <systemd/sd-lldp.h>
-
-#include "util.h"
-
-typedef struct lldp_port lldp_port;
-
-typedef enum LLDPPortStatus {
- LLDP_PORT_STATUS_NONE,
- LLDP_PORT_STATUS_ENABLED,
- LLDP_PORT_STATUS_DISABLED,
- _LLDP_PORT_STATUS_MAX,
- _LLDP_PORT_STATUS_INVALID = -1,
-} LLDPPortStatus;
-
-struct lldp_port {
- LLDPPortStatus status;
-
- int ifindex;
- char *ifname;
-
- struct ether_addr mac;
-
- int rawfd;
-
- sd_event *event;
- sd_event_source *lldp_port_rx;
-
- int event_priority;
-
- void *userdata;
-};
-
-int lldp_port_new(int ifindex,
- const char *ifname,
- const struct ether_addr *addr,
- void *userdata,
- lldp_port **ret);
-void lldp_port_free(lldp_port *p);
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_port*, lldp_port_free);
-#define _cleanup_lldp_port_free_ _cleanup_(lldp_port_freep)
-
-int lldp_port_start(lldp_port *p);
-int lldp_port_stop(lldp_port *p);
diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c
deleted file mode 100644
index 9170b50691..0000000000
--- a/src/libsystemd-network/lldp-tlv.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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 <arpa/inet.h>
-#include <net/ethernet.h>
-
-#include "alloc-util.h"
-#include "lldp-tlv.h"
-#include "macro.h"
-
-int tlv_section_new(tlv_section **ret) {
- tlv_section *s;
-
- s = new0(tlv_section, 1);
- if (!s)
- return -ENOMEM;
-
- *ret = s;
-
- return 0;
-}
-
-void tlv_section_free(tlv_section *m) {
-
- if (!m)
- return;
-
- free(m);
-}
-
-int tlv_packet_new(tlv_packet **ret) {
- tlv_packet *m;
-
- m = new0(tlv_packet, 1);
- if (!m)
- return -ENOMEM;
-
- LIST_HEAD_INIT(m->sections);
- m->n_ref = 1;
-
- *ret = m;
-
- return 0;
-}
-
-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 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) {
- uint8_t *p;
-
- assert_return(m, -EINVAL);
- assert_return(data, -EINVAL);
- assert_return(data_length, -EINVAL);
-
- if (m->length + data_length > ETHER_MAX_LEN)
- return -ENOMEM;
-
- p = m->pdu + m->length;
- memcpy(p, data, data_length);
- m->length += data_length;
-
- return 0;
-}
-
-int tlv_packet_append_u8(tlv_packet *m, uint8_t data) {
-
- assert_return(m, -EINVAL);
-
- return tlv_packet_append_bytes(m, &data, sizeof(uint8_t));
-}
-
-int tlv_packet_append_u16(tlv_packet *m, uint16_t data) {
- uint16_t type;
-
- assert_return(m, -EINVAL);
-
- type = htons(data);
-
- return tlv_packet_append_bytes(m, &type, sizeof(uint16_t));
-}
-
-int tlv_packet_append_u32(tlv_packet *m, uint32_t data) {
- uint32_t type;
-
- assert_return(m, -EINVAL);
-
- type = htonl(data);
-
- return tlv_packet_append_bytes(m, &type, sizeof(uint32_t));
-}
-
-int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) {
-
- assert_return(m, -EINVAL);
-
- return tlv_packet_append_bytes(m, data, size);
-}
-
-int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) {
-
- assert_return(m, -EINVAL);
-
- m->container_pos = m->pdu + m->length;
-
- return tlv_packet_append_u16(m, type << 9);
-}
-
-int lldp_tlv_packet_close_container(tlv_packet *m) {
- uint16_t type;
-
- assert_return(m, -EINVAL);
- assert_return(m->container_pos, -EINVAL);
-
- memcpy(&type, m->container_pos, sizeof(uint16_t));
-
- type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff);
- memcpy(m->container_pos, &type, sizeof(uint16_t));
-
- return 0;
-}
-
-static inline int tlv_packet_read_internal(tlv_section *m, void **data) {
-
- assert_return(m->read_pos, -EINVAL);
-
- *data = m->read_pos;
-
- return 0;
-}
-
-int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) {
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- memcpy(data, val, sizeof(uint8_t));
-
- m->container->read_pos ++;
-
- return 0;
-}
-
-int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) {
- uint16_t t;
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- memcpy(&t, val, sizeof(uint16_t));
- *data = ntohs(t);
-
- m->container->read_pos += 2;
-
- return 0;
-}
-
-int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) {
- uint32_t t;
- void *val;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- memcpy(&t, val, sizeof(uint32_t));
- *data = ntohl(t);
-
- m->container->read_pos += 4;
-
- return r;
-}
-
-int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) {
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- *data = (char *) val;
- *data_length = m->container->data + m->container->length - m->container->read_pos;
-
- m->container->read_pos += *data_length;
-
- return 0;
-}
-
-int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) {
- void *val = NULL;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = tlv_packet_read_internal(m->container, &val);
- if (r < 0)
- return r;
-
- *data = (uint8_t *) val;
- *data_length = m->container->data + m->container->length - m->container->read_pos;
-
- m->container->read_pos += *data_length;
-
- return 0;
-}
-
-/* parse raw TLV packet */
-int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) {
- tlv_section *section, *tail;
- uint16_t t, l;
- uint8_t *p;
- int r;
-
- assert_return(m, -EINVAL);
- assert_return(size, -EINVAL);
-
- p = m->pdu;
-
- /* extract Ethernet header */
- memcpy(&m->mac, p, ETH_ALEN);
- p += sizeof(struct ether_header);
-
- for (l = 0; l <= size; ) {
- r = tlv_section_new(&section);
- if (r < 0)
- return r;
-
- memcpy(&t, p, sizeof(uint16_t));
-
- section->type = ntohs(t) >> 9;
- section->length = ntohs(t) & 0x01ff;
-
- if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) {
- tlv_section_free(section);
- break;
- }
-
- 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);
- LIST_INSERT_AFTER(section, m->sections, tail, section);
-
- p += section->length;
- l += (section->length + 2);
- }
-
- return 0;
-}
-
-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)
- break;
- if (!s)
- return -1;
-
- m->container = s;
-
- m->container->read_pos = s->data;
- if (!m->container->read_pos) {
- 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;
- }
-
- return 0;
-}
-
-int lldp_tlv_packet_exit_container(tlv_packet *m) {
- assert_return(m, -EINVAL);
-
- m->container = 0;
-
- 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)
- return r;
-
- r = tlv_packet_read_u16(tlv, value);
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- 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)
- return r;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out;
-
- switch (subtype) {
- case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out:
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- 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)
- return r;
-
- r = tlv_packet_read_u8(tlv, &subtype);
- if (r < 0)
- goto out;
-
- 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 out;
-
- *data = (uint8_t *) s;
-
- break;
- case LLDP_PORT_SUBTYPE_MAC_ADDRESS:
-
- r = tlv_packet_read_bytes(tlv, data, length);
- if (r < 0)
- goto out;
-
- break;
- default:
- r = -EOPNOTSUPP;
- break;
- }
-
- *type = subtype;
-
- out:
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- 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)
- return r;
-
- r = tlv_packet_read_u16(tlv, id);
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- 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)
- return r;
-
- r = tlv_packet_read_u8(tlv, flags);
- if (r >= 0)
- r = tlv_packet_read_u16(tlv, id);
-
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- 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)
- return r;
-
- 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);
-
- 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)
- return r;
-
- r = tlv_packet_read_u16(tlv, id);
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- 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)
- return r;
-
- r = tlv_packet_read_u8(tlv, status);
- if (r >= 0)
- r = tlv_packet_read_u32(tlv, id);
-
- r2 = lldp_tlv_packet_exit_container(tlv);
-
- 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
deleted file mode 100644
index 4362b2ace6..0000000000
--- a/src/libsystemd-network/lldp-tlv.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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/>.
-***/
-
-#pragma once
-
-#include <net/ethernet.h>
-
-#include <systemd/sd-lldp.h>
-
-#include "list.h"
-#include "lldp.h"
-#include "util.h"
-
-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;
-
- 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 sd_lldp_packet {
- unsigned n_ref;
-
- uint16_t type;
- uint16_t length;
- usec_t ts;
-
- uint8_t *container_pos;
- uint8_t pdu[ETHER_MAX_LEN];
-
- void *userdata;
-
- struct ether_addr mac;
- tlv_section *container;
-
- LIST_HEAD(tlv_section, sections);
-};
-
-int tlv_packet_new(tlv_packet **ret);
-
-int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type);
-int lldp_tlv_packet_close_container(tlv_packet *m);
-
-int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length);
-int tlv_packet_append_u8(tlv_packet *m, uint8_t data);
-int tlv_packet_append_u16(tlv_packet *m, uint16_t data);
-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);
-int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length);
-int tlv_packet_read_u8(tlv_packet *m, uint8_t *data);
-int tlv_packet_read_u16(tlv_packet *m, uint16_t *data);
-int tlv_packet_read_u32(tlv_packet *m, uint32_t *data);
-
-int tlv_packet_parse_pdu(tlv_packet *t, uint16_t size);
diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h
deleted file mode 100644
index d2c7164633..0000000000
--- a/src/libsystemd-network/lldp.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
-
- 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/>.
-***/
-
-#pragma once
-
-#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }
-
-#define ETHERTYPE_LLDP 0x88cc
-
-/* IEEE 802.3AB Clause 9: TLV Types */
-typedef enum LLDPTypes {
- LLDP_TYPE_END = 0,
- LLDP_TYPE_CHASSIS_ID = 1,
- LLDP_TYPE_PORT_ID = 2,
- LLDP_TYPE_TTL = 3,
- LLDP_TYPE_PORT_DESCRIPTION = 4,
- LLDP_TYPE_SYSTEM_NAME = 5,
- LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
- LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
- LLDP_TYPE_MGMT_ADDRESS = 8,
- LLDP_TYPE_PRIVATE = 127,
- _LLDP_TYPE_MAX,
- _LLDP_TYPE_INVALID = -1,
-} LLDPTypes;
-
-/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */
-typedef enum LLDPChassisSubtypes {
- LLDP_CHASSIS_SUBTYPE_RESERVED = 0,
- LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1,
- LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2,
- LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3,
- LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4,
- LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
- LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
- LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7,
- _LLDP_CHASSIS_SUBTYPE_MAX,
- _LLDP_CHASSIS_SUBTYPE_INVALID = -1,
-} LLDPChassisSubtypes;
-
-/* IEEE 802.3AB Clause 9.5.3: Port subtype */
-typedef enum LLDPPortSubtypes {
- LLDP_PORT_SUBTYPE_RESERVED = 0,
- LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1,
- LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2,
- LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3,
- LLDP_PORT_SUBTYPE_NETWORK = 4,
- LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
- LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
- LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
- _LLDP_PORT_SUBTYPE_MAX,
- _LLDP_PORT_SUBTYPE_INVALID = -1
-} LLDPPortSubtypes;
-
-typedef enum LLDPSystemCapabilities {
- LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
- LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
- LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
- LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3,
- LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4,
- LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5,
- LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6,
- LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
- LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
- LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
- LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
- _LLDP_SYSTEM_CAPABILITIES_MAX,
- _LLDP_SYSTEM_CAPABILITIES_INVALID = -1,
-} LLDPSystemCapabilities;
-
-typedef enum LLDPMedSubtype {
- LLDP_MED_SUBTYPE_RESERVED = 0,
- LLDP_MED_SUBTYPE_CAPABILITIES = 1,
- LLDP_MED_SUBTYPE_NETWORK_POLICY = 2,
- LLDP_MED_SUBTYPE_LOCATION_ID = 3,
- LLDP_MED_SUBTYPE_EXTENDED_PVMDI = 4,
- LLDP_MED_SUBTYPE_INV_HWREV = 5,
- LLDP_MED_SUBTYPE_INV_FWREV = 6,
- LLDP_MED_SUBTYPE_INV_SWREV = 7,
- LLDP_MED_SUBTYPE_INV_SERIAL = 8,
- LLDP_MED_SUBTYPE_INV_MANUFACTURER = 9,
- LLDP_MED_SUBTYPE_INV_MODELNAME = 10,
- LLDP_MED_SUBTYPE_INV_ASSETID = 11,
- _LLDP_MED_SUBTYPE_MAX,
- _LLDP_MED_SUBTYPE_INVALID = -1,
-} LLDPMedSubtype;
-
-typedef enum LLDPMedCapability {
- LLDP_MED_CAPABILITY_CAPAPILITIES = 1 << 0,
- LLDP_MED_CAPABILITY_NETWORK_POLICY = 1 << 1,
- LLDP_MED_CAPABILITY_LOCATION_ID = 1 << 2,
- LLDP_MED_CAPABILITY_EXTENDED_PSE = 1 << 3,
- LLDP_MED_CAPABILITY_EXTENDED_PD = 1 << 4,
- LLDP_MED_CAPABILITY_INVENTORY = 1 << 5,
- 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 35860cf11a..d57baf8fff 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -27,11 +27,13 @@
#include "condition.h"
#include "conf-parser.h"
#include "dhcp-lease-internal.h"
+#include "ether-addr-util.c"
#include "hexdecoct.h"
#include "log.h"
#include "network-internal.h"
#include "parse-util.h"
#include "siphash24.h"
+#include "socket-util.h"
#include "string-util.h"
#include "strv.h"
#include "utf8.h"
@@ -175,58 +177,19 @@ int config_parse_net_condition(const char *unit,
return 0;
}
-int config_parse_ifname(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) {
-
- char **s = data;
- _cleanup_free_ char *n = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- n = strdup(rvalue);
- if (!n)
- return log_oom();
-
- if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- return 0;
- }
-
- free(*s);
- if (*n) {
- *s = n;
- n = NULL;
- } else
- *s = NULL;
-
- return 0;
-}
-
-int config_parse_ifnames(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_ifnames(
+ 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) {
char ***sv = data;
- const char *word, *state;
- size_t l;
int r;
assert(filename);
@@ -234,22 +197,27 @@ int config_parse_ifnames(const char *unit,
assert(rvalue);
assert(data);
- FOREACH_WORD(word, l, rvalue, state) {
- char *n;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
- n = strndup(word, l);
- if (!n)
- return log_oom();
+ r = extract_first_word(&rvalue, &word, NULL, 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse interface name list: %s", rvalue);
+ return 0;
+ }
+ if (r == 0)
+ break;
- if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- free(n);
+ if (!ifname_valid(word)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not valid or too long, ignoring assignment: %s", rvalue);
return 0;
}
- r = strv_consume(sv, n);
+ r = strv_push(sv, word);
if (r < 0)
return log_oom();
+
+ word = NULL;
}
return 0;
@@ -305,6 +273,8 @@ int config_parse_hwaddr(const char *unit,
void *userdata) {
struct ether_addr **hwaddr = data;
struct ether_addr *n;
+ const char *start;
+ size_t offset;
int r;
assert(filename);
@@ -316,14 +286,10 @@ int config_parse_hwaddr(const char *unit,
if (!n)
return log_oom();
- r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
- &n->ether_addr_octet[0],
- &n->ether_addr_octet[1],
- &n->ether_addr_octet[2],
- &n->ether_addr_octet[3],
- &n->ether_addr_octet[4],
- &n->ether_addr_octet[5]);
- if (r != 6) {
+ start = rvalue + strspn(rvalue, WHITESPACE);
+ r = ether_addr_from_string(start, n, &offset);
+
+ if (r || (start[offset + strspn(start + offset, WHITESPACE)] != '\0')) {
log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue);
free(n);
return 0;
@@ -335,6 +301,36 @@ int config_parse_hwaddr(const char *unit,
return 0;
}
+int config_parse_iaid(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ uint32_t iaid;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = safe_atou32(rvalue, &iaid);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Unable to read IAID, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ *((uint32_t *)data) = iaid;
+
+ return 0;
+}
+
void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
unsigned i;
@@ -350,32 +346,32 @@ void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
int deserialize_in_addrs(struct in_addr **ret, const char *string) {
_cleanup_free_ struct in_addr *addresses = NULL;
int size = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- _cleanup_free_ char *addr_str = NULL;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
struct in_addr *new_addresses;
int r;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr));
if (!new_addresses)
return -ENOMEM;
else
addresses = new_addresses;
- addr_str = strndup(word, len);
- if (!addr_str)
- return -ENOMEM;
-
- r = inet_pton(AF_INET, addr_str, &(addresses[size]));
+ r = inet_pton(AF_INET, word, &(addresses[size]));
if (r <= 0)
continue;
- size ++;
+ size++;
}
*ret = addresses;
@@ -401,28 +397,28 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
int deserialize_in6_addrs(struct in6_addr **ret, const char *string) {
_cleanup_free_ struct in6_addr *addresses = NULL;
int size = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- _cleanup_free_ char *addr_str = NULL;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
struct in6_addr *new_addresses;
int r;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr));
if (!new_addresses)
return -ENOMEM;
else
addresses = new_addresses;
- addr_str = strndup(word, len);
- if (!addr_str)
- return -ENOMEM;
-
- r = inet_pton(AF_INET6, addr_str, &(addresses[size]));
+ r = inet_pton(AF_INET6, word, &(addresses[size]));
if (r <= 0)
continue;
@@ -463,29 +459,29 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) {
_cleanup_free_ struct sd_dhcp_route *routes = NULL;
size_t size = 0, allocated = 0;
- const char *word, *state;
- size_t len;
assert(ret);
assert(ret_size);
assert(ret_allocated);
assert(string);
- FOREACH_WORD(word, len, string, state) {
- /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
- _cleanup_free_ char* entry = NULL;
+ /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
char *tok, *tok_end;
unsigned n;
int r;
- if (!GREEDY_REALLOC(routes, allocated, size + 1))
- return -ENOMEM;
+ r = extract_first_word(&string, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
- entry = strndup(word, len);
- if(!entry)
+ if (!GREEDY_REALLOC(routes, allocated, size + 1))
return -ENOMEM;
- tok = entry;
+ tok = word;
/* get the subnet */
tok_end = strchr(tok, '/');
diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h
index 2549d1420e..1cafb0747f 100644
--- a/src/libsystemd-network/network-internal.h
+++ b/src/libsystemd-network/network-internal.h
@@ -50,10 +50,6 @@ int config_parse_hwaddr(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_ifname(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_ifnames(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);
@@ -62,6 +58,10 @@ int config_parse_ifalias(const char *unit, const char *filename, unsigned line,
const char *section, unsigned section_line, const char *lvalue,
int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_iaid(const char *unit, const char *filename, unsigned line,
+ const char *section, unsigned section_line, const char *lvalue,
+ int ltype, const char *rvalue, void *data, void *userdata);
+
int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result);
const char *net_get_name(struct udev_device *device);
diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c
index bd5ec76fc5..193f31880f 100644
--- a/src/libsystemd-network/sd-dhcp-client.c
+++ b/src/libsystemd-network/sd-dhcp-client.c
@@ -82,7 +82,7 @@ struct sd_dhcp_client {
} _packed_ ll;
struct {
/* 255: Node-specific (RFC 4361) */
- uint32_t iaid;
+ be32_t iaid;
struct duid duid;
} _packed_ ns;
struct {
@@ -101,7 +101,7 @@ struct sd_dhcp_client {
sd_event_source *timeout_t1;
sd_event_source *timeout_t2;
sd_event_source *timeout_expire;
- sd_dhcp_client_cb_t cb;
+ sd_dhcp_client_callback_t cb;
void *userdata;
sd_dhcp_lease *lease;
usec_t start_delay;
@@ -115,14 +115,22 @@ static const uint8_t default_req_opts[] = {
SD_DHCP_OPTION_DOMAIN_NAME_SERVER,
};
-static int client_receive_message_raw(sd_event_source *s, int fd,
- uint32_t revents, void *userdata);
-static int client_receive_message_udp(sd_event_source *s, int fd,
- uint32_t revents, void *userdata);
+static int client_receive_message_raw(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata);
+static int client_receive_message_udp(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata);
static void client_stop(sd_dhcp_client *client, int error);
-int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
- void *userdata) {
+int sd_dhcp_client_set_callback(
+ sd_dhcp_client *client,
+ sd_dhcp_client_callback_t cb,
+ void *userdata) {
assert_return(client, -EINVAL);
client->cb = cb;
@@ -171,8 +179,9 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) {
return 0;
}
-int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
- const struct in_addr *last_addr) {
+int sd_dhcp_client_set_request_address(
+ sd_dhcp_client *client,
+ const struct in_addr *last_addr) {
assert_return(client, -EINVAL);
assert_return (IN_SET(client->state, DHCP_STATE_INIT,
DHCP_STATE_STOPPED), -EBUSY);
@@ -196,8 +205,12 @@ int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) {
return 0;
}
-int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
- size_t addr_len, uint16_t arp_type) {
+int sd_dhcp_client_set_mac(
+ sd_dhcp_client *client,
+ const uint8_t *addr,
+ size_t addr_len,
+ uint16_t arp_type) {
+
DHCP_CLIENT_DONT_DESTROY(client);
bool need_restart = false;
@@ -234,8 +247,11 @@ int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
return 0;
}
-int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
- const uint8_t **data, size_t *data_len) {
+int sd_dhcp_client_get_client_id(
+ sd_dhcp_client *client,
+ uint8_t *type,
+ const uint8_t **data,
+ size_t *data_len) {
assert_return(client, -EINVAL);
assert_return(type, -EINVAL);
@@ -254,8 +270,12 @@ int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
return 0;
}
-int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
- const uint8_t *data, size_t data_len) {
+int sd_dhcp_client_set_client_id(
+ sd_dhcp_client *client,
+ uint8_t type,
+ const uint8_t *data,
+ size_t data_len) {
+
DHCP_CLIENT_DONT_DESTROY(client);
bool need_restart = false;
@@ -298,8 +318,71 @@ int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
return 0;
}
-int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
- const char *hostname) {
+/**
+ * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid
+ * without further modification. Otherwise, if duid_type is supported, DUID
+ * is set based on that type. Otherwise, an error is returned.
+ */
+int sd_dhcp_client_set_iaid_duid(
+ sd_dhcp_client *client,
+ uint32_t iaid,
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len) {
+
+ DHCP_CLIENT_DONT_DESTROY(client);
+ int r;
+ size_t len;
+
+ assert_return(client, -EINVAL);
+ assert_return(duid_len == 0 || duid != NULL, -EINVAL);
+
+ if (duid != NULL) {
+ r = dhcp_validate_duid_len(duid_type, duid_len);
+ if (r < 0)
+ return r;
+ }
+
+ zero(client->client_id);
+ client->client_id.type = 255;
+
+ /* If IAID is not configured, generate it. */
+ if (iaid == 0) {
+ r = dhcp_identifier_set_iaid(client->index, client->mac_addr,
+ client->mac_addr_len,
+ &client->client_id.ns.iaid);
+ if (r < 0)
+ return r;
+ } else
+ client->client_id.ns.iaid = htobe32(iaid);
+
+ if (duid != NULL) {
+ client->client_id.ns.duid.type = htobe16(duid_type);
+ memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len);
+ len = sizeof(client->client_id.ns.duid.type) + duid_len;
+ } else if (duid_type == DUID_TYPE_EN) {
+ r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &len);
+ if (r < 0)
+ return r;
+ } else
+ return -EOPNOTSUPP;
+
+ client->client_id_len = sizeof(client->client_id.type) + len +
+ sizeof(client->client_id.ns.iaid);
+
+ if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) {
+ log_dhcp_client(client, "Configured IAID+DUID, restarting.");
+ client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
+ sd_dhcp_client_start(client);
+ }
+
+ return 0;
+}
+
+int sd_dhcp_client_set_hostname(
+ sd_dhcp_client *client,
+ const char *hostname) {
+
char *new_hostname = NULL;
assert_return(client, -EINVAL);
@@ -322,8 +405,10 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client,
return 0;
}
-int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client,
- const char *vci) {
+int sd_dhcp_client_set_vendor_class_identifier(
+ sd_dhcp_client *client,
+ const char *vci) {
+
char *new_vci = NULL;
assert_return(client, -EINVAL);
@@ -406,9 +491,14 @@ static void client_stop(sd_dhcp_client *client, int error) {
client_initialize(client);
}
-static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
- uint8_t type, size_t *_optlen, size_t *_optoffset) {
- _cleanup_free_ DHCPPacket *packet;
+static int client_message_init(
+ sd_dhcp_client *client,
+ DHCPPacket **ret,
+ uint8_t type,
+ size_t *_optlen,
+ size_t *_optoffset) {
+
+ _cleanup_free_ DHCPPacket *packet = NULL;
size_t optlen, optoffset, size;
be16_t max_size;
usec_t time_now;
@@ -548,8 +638,12 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret,
return 0;
}
-static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset,
- const char *fqdn) {
+static int client_append_fqdn_option(
+ DHCPMessage *message,
+ size_t optlen,
+ size_t *optoffset,
+ const char *fqdn) {
+
uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH];
int r;
@@ -566,8 +660,11 @@ static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t
return r;
}
-static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet,
- size_t len) {
+static int dhcp_client_send_raw(
+ sd_dhcp_client *client,
+ DHCPPacket *packet,
+ size_t len) {
+
dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT,
INADDR_BROADCAST, DHCP_PORT_SERVER, len);
@@ -774,8 +871,11 @@ static int client_send_request(sd_dhcp_client *client) {
static int client_start(sd_dhcp_client *client);
-static int client_timeout_resend(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_resend(
+ sd_event_source *s,
+ uint64_t usec,
+ void *userdata) {
+
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
usec_t next_timeout = 0;
@@ -919,8 +1019,10 @@ error:
return 0;
}
-static int client_initialize_io_events(sd_dhcp_client *client,
- sd_event_io_handler_t io_callback) {
+static int client_initialize_io_events(
+ sd_dhcp_client *client,
+ sd_event_io_handler_t io_callback) {
+
int r;
assert(client);
@@ -958,7 +1060,7 @@ static int client_initialize_time_events(sd_dhcp_client *client) {
client->timeout_resend = sd_event_source_unref(client->timeout_resend);
if (client->start_delay) {
- sd_event_now(client->event, clock_boottime_or_monotonic(), &usec);
+ assert_se(sd_event_now(client->event, clock_boottime_or_monotonic(), &usec) >= 0);
usec += client->start_delay;
}
@@ -987,8 +1089,7 @@ error:
}
-static int client_initialize_events(sd_dhcp_client *client,
- sd_event_io_handler_t io_callback) {
+static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) {
client_initialize_io_events(client, io_callback);
client_initialize_time_events(client);
@@ -1028,8 +1129,7 @@ static int client_start(sd_dhcp_client *client) {
return client_start_delayed(client);
}
-static int client_timeout_expire(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
@@ -1069,8 +1169,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata)
return client_initialize_events(client, client_receive_message_raw);
}
-static int client_timeout_t1(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp_client *client = userdata;
DHCP_CLIENT_DONT_DESTROY(client);
@@ -1080,8 +1179,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec,
return client_initialize_time_events(client);
}
-static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
- size_t len) {
+static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
int r;
@@ -1132,8 +1230,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer,
return 0;
}
-static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
- size_t len) {
+static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) {
int r;
r = dhcp_option_parse(force, len, NULL, NULL, NULL);
@@ -1145,8 +1242,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force,
return 0;
}
-static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack,
- size_t len) {
+static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_free_ char *error_message = NULL;
int r;
@@ -1374,8 +1470,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) {
return 0;
}
-static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message,
- int len) {
+static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) {
DHCP_CLIENT_DONT_DESTROY(client);
char time_string[FORMAT_TIMESPAN_MAX];
int r = 0, notify_event = 0;
@@ -1521,8 +1616,12 @@ error:
return r;
}
-static int client_receive_message_udp(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
+static int client_receive_message_udp(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
+
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPMessage *message = NULL;
const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } };
@@ -1541,7 +1640,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
if (!message)
return -ENOMEM;
- len = read(fd, message, buflen);
+ len = recv(fd, message, buflen, 0);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
@@ -1599,8 +1698,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd,
return client_handle_message(client, message, len);
}
-static int client_receive_message_raw(sd_event_source *s, int fd,
- uint32_t revents, void *userdata) {
+static int client_receive_message_raw(
+ sd_event_source *s,
+ int fd,
+ uint32_t revents,
+ void *userdata) {
+
sd_dhcp_client *client = userdata;
_cleanup_free_ DHCPPacket *packet = NULL;
uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
@@ -1691,8 +1794,7 @@ int sd_dhcp_client_stop(sd_dhcp_client *client) {
return 0;
}
-int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event,
- int priority) {
+int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) {
int r;
assert_return(client, -EINVAL);
diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c
index d8d6f446ee..d4c680d485 100644
--- a/src/libsystemd-network/sd-dhcp-lease.c
+++ b/src/libsystemd-network/sd-dhcp-lease.c
@@ -825,7 +825,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
if (r >= 0) {
- _cleanup_free_ char *client_id_hex;
+ _cleanup_free_ char *client_id_hex = NULL;
client_id_hex = hexmem(client_id, client_id_len);
if (!client_id_hex) {
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c
index e11462e6ac..5e8b4e4823 100644
--- a/src/libsystemd-network/sd-dhcp-server.c
+++ b/src/libsystemd-network/sd-dhcp-server.c
@@ -208,8 +208,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) {
return 0;
}
-int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event,
- int priority) {
+int sd_dhcp_server_attach_event(sd_dhcp_server *server, sd_event *event, int64_t priority) {
int r;
assert_return(server, -EINVAL);
@@ -281,10 +280,11 @@ static int dhcp_server_send_unicast_raw(sd_dhcp_server *server,
}
static int dhcp_server_send_udp(sd_dhcp_server *server, be32_t destination,
+ uint16_t destination_port,
DHCPMessage *message, size_t len) {
union sockaddr_union dest = {
.in.sin_family = AF_INET,
- .in.sin_port = htobe16(DHCP_PORT_CLIENT),
+ .in.sin_port = htobe16(destination_port),
.in.sin_addr.s_addr = destination,
};
struct iovec iov = {
@@ -343,6 +343,7 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
DHCPRequest *req, DHCPPacket *packet,
int type, size_t optoffset) {
be32_t destination = INADDR_ANY;
+ uint16_t destination_port = DHCP_PORT_CLIENT;
int r;
assert(server);
@@ -387,17 +388,19 @@ int dhcp_server_send_packet(sd_dhcp_server *server,
*/
if (req->message->giaddr) {
destination = req->message->giaddr;
+ destination_port = DHCP_PORT_SERVER;
if (type == DHCP_NAK)
packet->dhcp.flags = htobe16(0x8000);
} else if (req->message->ciaddr && type != DHCP_NAK)
destination = req->message->ciaddr;
if (destination != INADDR_ANY)
- return dhcp_server_send_udp(server, destination, &packet->dhcp,
+ return dhcp_server_send_udp(server, destination,
+ destination_port, &packet->dhcp,
sizeof(DHCPMessage) + optoffset);
else if (requested_broadcast(req) || type == DHCP_NAK)
return dhcp_server_send_udp(server, INADDR_BROADCAST,
- &packet->dhcp,
+ destination_port, &packet->dhcp,
sizeof(DHCPMessage) + optoffset);
else
/* we cannot send UDP packet to specific MAC address when the
@@ -465,10 +468,12 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req,
if (r < 0)
return r;
- r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- SD_DHCP_OPTION_ROUTER, 4, &server->address);
- if (r < 0)
- return r;
+ if (server->emit_router) {
+ r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
+ SD_DHCP_OPTION_ROUTER, 4, &server->address);
+ if (r < 0)
+ return r;
+ }
r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset);
if (r < 0)
@@ -502,10 +507,12 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req,
if (r < 0)
return r;
- r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
- SD_DHCP_OPTION_ROUTER, 4, &server->address);
- if (r < 0)
- return r;
+ if (server->emit_router) {
+ r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0,
+ SD_DHCP_OPTION_ROUTER, 4, &server->address);
+ if (r < 0)
+ return r;
+ }
if (server->n_dns > 0) {
r = dhcp_option_append(
@@ -580,7 +587,8 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address,
memcpy(&packet->dhcp.chaddr, chaddr, ETH_ALEN);
- r = dhcp_server_send_udp(server, address, &packet->dhcp,
+ r = dhcp_server_send_udp(server, address, DHCP_PORT_CLIENT,
+ &packet->dhcp,
sizeof(DHCPMessage) + optoffset);
if (r < 0)
return r;
@@ -1154,3 +1162,14 @@ int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr ntp[], u
return 1;
}
+
+int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled) {
+ assert_return(server, -EINVAL);
+
+ if (enabled == server->emit_router)
+ return 0;
+
+ server->emit_router = enabled;
+
+ return 1;
+}
diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c
index 494036cb54..2760b039ba 100644
--- a/src/libsystemd-network/sd-dhcp6-client.c
+++ b/src/libsystemd-network/sd-dhcp6-client.c
@@ -64,7 +64,7 @@ struct sd_dhcp6_client {
uint8_t retransmit_count;
sd_event_source *timeout_resend;
sd_event_source *timeout_resend_expire;
- sd_dhcp6_client_cb_t cb;
+ sd_dhcp6_client_callback_t cb;
void *userdata;
struct duid duid;
size_t duid_len;
@@ -111,7 +111,10 @@ DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int);
static int client_start(sd_dhcp6_client *client, enum DHCP6State state);
-int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) {
+int sd_dhcp6_client_set_callback(
+ sd_dhcp6_client *client,
+ sd_dhcp6_client_callback_t cb,
+ void *userdata) {
assert_return(client, -EINVAL);
client->cb = cb;
@@ -131,7 +134,10 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) {
return 0;
}
-int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) {
+int sd_dhcp6_client_set_local_address(
+ sd_dhcp6_client *client,
+ const struct in6_addr *local_address) {
+
assert_return(client, -EINVAL);
assert_return(local_address, -EINVAL);
assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL);
@@ -180,41 +186,47 @@ static int client_ensure_duid(sd_dhcp6_client *client) {
return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
}
+/**
+ * Sets DUID. If duid is non-null, the DUID is set to duid_type + duid
+ * without further modification. Otherwise, if duid_type is supported, DUID
+ * is set based on that type. Otherwise, an error is returned.
+ */
int sd_dhcp6_client_set_duid(
sd_dhcp6_client *client,
- uint16_t type,
- uint8_t *duid, size_t duid_len) {
- assert_return(client, -EINVAL);
- assert_return(duid, -EINVAL);
- assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL);
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len) {
+ int r;
+ assert_return(client, -EINVAL);
+ assert_return(duid_len == 0 || duid != NULL, -EINVAL);
assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
- switch (type) {
- case DHCP6_DUID_LLT:
- if (duid_len <= sizeof(client->duid.llt))
- return -EINVAL;
- break;
- case DHCP6_DUID_EN:
- if (duid_len != sizeof(client->duid.en))
- return -EINVAL;
- break;
- case DHCP6_DUID_LL:
- if (duid_len <= sizeof(client->duid.ll))
- return -EINVAL;
- break;
- case DHCP6_DUID_UUID:
- if (duid_len != sizeof(client->duid.uuid))
- return -EINVAL;
- break;
- default:
- /* accept unknown type in order to be forward compatible */
- break;
+ if (duid != NULL) {
+ r = dhcp_validate_duid_len(duid_type, duid_len);
+ if (r < 0)
+ return r;
}
- client->duid.type = htobe16(type);
- memcpy(&client->duid.raw.data, duid, duid_len);
- client->duid_len = duid_len + sizeof(client->duid.type);
+ if (duid != NULL) {
+ client->duid.type = htobe16(duid_type);
+ memcpy(&client->duid.raw.data, duid, duid_len);
+ client->duid_len = sizeof(client->duid.type) + duid_len;
+ } else if (duid_type == DUID_TYPE_EN) {
+ r = dhcp_identifier_set_duid_en(&client->duid, &client->duid_len);
+ if (r < 0)
+ return r;
+ } else
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
+ assert_return(client, -EINVAL);
+ assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY);
+
+ client->ia_na.id = htobe32(iaid);
return 0;
}
@@ -439,8 +451,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) {
return 0;
}
-static int client_timeout_t2(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp6_client *client = userdata;
assert_return(s, -EINVAL);
@@ -457,8 +468,7 @@ static int client_timeout_t2(sd_event_source *s, uint64_t usec,
return 0;
}
-static int client_timeout_t1(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp6_client *client = userdata;
assert_return(s, -EINVAL);
@@ -475,8 +485,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec,
return 0;
}
-static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, void *userdata) {
sd_dhcp6_client *client = userdata;
DHCP6_CLIENT_DONT_DESTROY(client);
enum DHCP6State state;
@@ -502,8 +511,7 @@ static usec_t client_timeout_compute_random(usec_t val) {
(random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC;
}
-static int client_timeout_resend(sd_event_source *s, uint64_t usec,
- void *userdata) {
+static int client_timeout_resend(sd_event_source *s, uint64_t usec, void *userdata) {
int r = 0;
sd_dhcp6_client *client = userdata;
usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0;
@@ -670,9 +678,11 @@ static int client_ensure_iaid(sd_dhcp6_client *client) {
return 0;
}
-static int client_parse_message(sd_dhcp6_client *client,
- DHCP6Message *message, size_t len,
- sd_dhcp6_lease *lease) {
+static int client_parse_message(
+ sd_dhcp6_client *client,
+ DHCP6Message *message,
+ size_t len,
+ sd_dhcp6_lease *lease) {
int r;
uint8_t *optval, *option, *id = NULL;
uint16_t optcode, status;
@@ -907,14 +917,13 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
if (!message)
return -ENOMEM;
- len = read(fd, message, buflen);
+ len = recv(fd, message, buflen, 0);
if (len < 0) {
if (errno == EAGAIN || errno == EINTR)
return 0;
- log_dhcp6_client(client, "Could not receive message from UDP socket: %m");
+ return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
- return -errno;
} else if ((size_t)len < sizeof(DHCP6Message))
return 0;
@@ -937,8 +946,7 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
break;
default:
- log_dhcp6_client(client, "unknown message type %d",
- message->type);
+ log_dhcp6_client(client, "Unknown message type %d", message->type);
return 0;
}
@@ -997,10 +1005,9 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents,
return 0;
}
- if (r >= 0) {
+ if (r >= 0)
log_dhcp6_client(client, "Recv %s",
dhcp6_message_type_to_string(message->type));
- }
return 0;
}
@@ -1053,7 +1060,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) {
if (client->lease->ia.lifetime_t1 == 0xffffffff ||
client->lease->ia.lifetime_t2 == 0xffffffff) {
- log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x",
+ log_dhcp6_client(client, "Infinite T1 0x%08x or T2 0x%08x",
be32toh(client->lease->ia.lifetime_t1),
be32toh(client->lease->ia.lifetime_t2));
@@ -1169,8 +1176,13 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
return r;
r = dhcp6_network_bind_udp_socket(client->index, &client->local_address);
- if (r < 0)
- return r;
+ if (r < 0) {
+ _cleanup_free_ char *p = NULL;
+
+ (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &client->local_address, &p);
+ return log_dhcp6_client_errno(client, r,
+ "Failed to bind to UDP socket at address %s: %m", strna(p));
+ }
client->fd = r;
@@ -1186,7 +1198,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
goto error;
r = sd_event_source_set_description(client->receive_message,
- "dhcp6-receive-message");
+ "dhcp6-receive-message");
if (r < 0)
goto error;
@@ -1194,8 +1206,8 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) {
state = DHCP6_STATE_INFORMATION_REQUEST;
log_dhcp6_client(client, "Started in %s mode",
- client->information_request? "Information request":
- "Managed");
+ client->information_request? "Information request":
+ "Managed");
return client_start(client, state);
@@ -1204,7 +1216,7 @@ error:
return r;
}
-int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) {
+int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int64_t priority) {
int r;
assert_return(client, -EINVAL);
diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c
index f97fc0bf47..f1ed7ca747 100644
--- a/src/libsystemd-network/sd-ipv4acd.c
+++ b/src/libsystemd-network/sd-ipv4acd.c
@@ -92,7 +92,7 @@ struct sd_ipv4acd {
struct ether_addr mac_addr;
sd_event *event;
int event_priority;
- sd_ipv4acd_cb_t cb;
+ sd_ipv4acd_callback_t cb;
void* userdata;
};
@@ -428,7 +428,7 @@ int sd_ipv4acd_detach_event(sd_ipv4acd *ll) {
return 0;
}
-int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority) {
int r;
assert_return(ll, -EINVAL);
@@ -447,7 +447,7 @@ int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) {
return 0;
}
-int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) {
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_t cb, void *userdata) {
assert_return(ll, -EINVAL);
ll->cb = cb;
@@ -456,7 +456,7 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata)
return 0;
}
-int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){
+int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address) {
assert_return(ll, -EINVAL);
assert_return(address, -EINVAL);
assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY);
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index 7725b67548..fc27408989 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -52,7 +52,7 @@ struct sd_ipv4ll {
/* External */
be32_t claimed_address;
- sd_ipv4ll_cb_t cb;
+ sd_ipv4ll_callback_t cb;
void* userdata;
};
@@ -160,7 +160,7 @@ int sd_ipv4ll_detach_event(sd_ipv4ll *ll) {
return sd_ipv4acd_detach_event(ll->acd);
}
-int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
+int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) {
int r;
assert_return(ll, -EINVAL);
@@ -172,7 +172,7 @@ int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) {
return 0;
}
-int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
+int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) {
assert_return(ll, -EINVAL);
ll->cb = cb;
@@ -181,7 +181,7 @@ int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) {
return 0;
}
-int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){
+int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) {
assert_return(ll, -EINVAL);
assert_return(address, -EINVAL);
diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c
index 6bb2c7797b..5a7380cd3f 100644
--- a/src/libsystemd-network/sd-lldp.c
+++ b/src/libsystemd-network/sd-lldp.c
@@ -1,21 +1,21 @@
/***
- This file is part of systemd.
+ This file is part of systemd.
- Copyright (C) 2014 Tom Gundersen
- Copyright (C) 2014 Susant Sahani
+ Copyright (C) 2014 Tom Gundersen
+ Copyright (C) 2014 Susant Sahani
- 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 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.
+ 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/>.
+ 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 <arpa/inet.h>
@@ -24,733 +24,473 @@
#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 "prioq.h"
-#include "siphash24.h"
-#include "string-util.h"
-
-typedef enum LLDPAgentRXState {
- LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4,
- LLDP_AGENT_RX_DELETE_AGED_INFO,
- LLDP_AGENT_RX_LLDP_INITIALIZE,
- LLDP_AGENT_RX_WAIT_FOR_FRAME,
- LLDP_AGENT_RX_RX_FRAME,
- LLDP_AGENT_RX_DELETE_INFO,
- LLDP_AGENT_RX_UPDATE_INFO,
- _LLDP_AGENT_RX_STATE_MAX,
- _LLDP_AGENT_RX_INVALID = -1,
-} LLDPAgentRXState;
-
-/* Section 10.5.2.2 Reception counters */
-struct lldp_agent_statistics {
- uint64_t stats_ageouts_total;
- uint64_t stats_frames_discarded_total;
- uint64_t stats_frames_in_errors_total;
- uint64_t stats_frames_in_total;
- uint64_t stats_tlvs_discarded_total;
- uint64_t stats_tlvs_unrecognized_total;
-};
-
-struct sd_lldp {
- lldp_port *port;
-
- Prioq *by_expiry;
- Hashmap *neighbour_mib;
-
- sd_lldp_cb_t cb;
-
- void *userdata;
-
- LLDPAgentRXState rx_state;
- lldp_agent_statistics statistics;
-};
-
-static void chassis_id_hash_func(const void *p, struct siphash *state) {
- const lldp_chassis_id *id = p;
-
- assert(id);
- assert(id->data);
-
- siphash24_compress(&id->length, sizeof(id->length), state);
- siphash24_compress(id->data, id->length, state);
-}
+#include "lldp-neighbor.h"
+#include "lldp-network.h"
+#include "socket-util.h"
+#include "ether-addr-util.h"
-static int chassis_id_compare_func(const void *_a, const void *_b) {
- const lldp_chassis_id *a, *b;
+#define LLDP_DEFAULT_NEIGHBORS_MAX 128U
- a = _a;
- b = _b;
+static void lldp_flush_neighbors(sd_lldp *lldp) {
+ sd_lldp_neighbor *n;
- assert(!a->length || a->data);
- assert(!b->length || b->data);
+ assert(lldp);
- if (a->type != b->type)
- return -1;
+ while ((n = hashmap_first(lldp->neighbor_by_id)))
+ lldp_neighbor_unlink(n);
+}
- if (a->length != b->length)
- return a->length < b->length ? -1 : 1;
+static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) {
+ assert(lldp);
+ assert(n);
- return memcmp(a->data, b->data, a->length);
-}
+ log_lldp("Invoking callback for '%c'.", event);
-static const struct hash_ops chassis_id_hash_ops = {
- .hash = chassis_id_hash_func,
- .compare = chassis_id_compare_func
-};
+ if (!lldp->callback)
+ return;
-static void lldp_mib_delete_objects(sd_lldp *lldp);
-static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state);
-static void lldp_run_state_machine(sd_lldp *ll);
+ lldp->callback(lldp, event, n, lldp->userdata);
+}
-static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) {
- int r;
+static int lldp_make_space(sd_lldp *lldp, size_t extra) {
+ usec_t t = USEC_INFINITY;
+ bool changed = false;
assert(lldp);
- assert(tlv);
-
- /* Remove expired packets */
- if (prioq_size(lldp->by_expiry) > 0) {
- lldp_set_state(lldp, LLDP_AGENT_RX_DELETE_INFO);
+ /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries
+ * are free. */
- lldp_mib_delete_objects(lldp);
- }
+ for (;;) {
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
- r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv);
- if (r < 0)
- goto out;
+ n = prioq_peek(lldp->neighbor_by_expiry);
+ if (!n)
+ break;
- lldp_set_state(lldp, LLDP_AGENT_RX_UPDATE_INFO);
+ sd_lldp_neighbor_ref(n);
- log_lldp("Packet added. MIB size: %d , PQ size: %d",
- hashmap_size(lldp->neighbour_mib),
- prioq_size(lldp->by_expiry));
+ if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra))
+ goto remove_one;
- lldp->statistics.stats_frames_in_total ++;
+ if (t == USEC_INFINITY)
+ t = now(clock_boottime_or_monotonic());
- out:
- if (r < 0)
- log_lldp("Receive frame failed: %s", strerror(-r));
+ if (n->until > t)
+ break;
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
+ remove_one:
+ lldp_neighbor_unlink(n);
+ lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n);
+ changed = true;
+ }
- return 0;
+ return changed;
}
-/* 10.3.2 LLDPDU validation: rxProcessFrame() */
-int lldp_handle_packet(tlv_packet *tlv, uint16_t length) {
- bool system_description = false, system_name = false, chassis_id = false;
- bool malformed = false, port_id = false, ttl = false, end = false;
- uint16_t type, len, i, l, t;
- lldp_port *port;
- uint8_t *p, *q;
- sd_lldp *lldp;
- int r;
-
- assert(tlv);
- assert(length > 0);
-
- port = (lldp_port *) tlv->userdata;
- lldp = (sd_lldp *) port->userdata;
-
- if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) {
- log_lldp("Port: %s is disabled. Dropping.", lldp->port->ifname);
- goto out;
- }
+static bool lldp_keep_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
+ assert(lldp);
+ assert(n);
- lldp_set_state(lldp, LLDP_AGENT_RX_RX_FRAME);
+ /* Don't keep data with a zero TTL */
+ if (n->ttl <= 0)
+ return false;
- p = tlv->pdu;
- p += sizeof(struct ether_header);
+ /* Filter out data from the filter address */
+ if (!ether_addr_is_null(&lldp->filter_address) &&
+ ether_addr_equal(&lldp->filter_address, &n->source_address))
+ return false;
- for (i = 1, l = 0; l <= length; i++) {
+ /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with
+ * no caps field set. */
+ if (n->has_capabilities &&
+ (n->enabled_capabilities & lldp->capability_mask) == 0)
+ return false;
- memcpy(&t, p, sizeof(uint16_t));
+ /* Keep everything else */
+ return true;
+}
- type = ntohs(t) >> 9;
- len = ntohs(t) & 0x01ff;
+static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor);
- if (type == LLDP_TYPE_END) {
- if (len != 0) {
- log_lldp("TLV type end must be length 0 (not %d). Dropping.", len);
+static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) {
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *old = NULL;
+ bool keep;
+ int r;
- malformed = true;
- goto out;
- }
+ assert(lldp);
+ assert(n);
+ assert(!n->lldp);
- end = true;
+ keep = lldp_keep_neighbor(lldp, n);
- break;
- } else if (type >=_LLDP_TYPE_MAX) {
- log_lldp("TLV type: %d not recognized. Dropping.", type);
+ /* First retrieve the old entry for this MSAP */
+ old = hashmap_get(lldp->neighbor_by_id, &n->id);
+ if (old) {
+ sd_lldp_neighbor_ref(old);
- malformed = true;
- goto out;
+ if (!keep) {
+ lldp_neighbor_unlink(old);
+ lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, old);
+ return 0;
}
- /* skip type and length encoding */
- p += 2;
- q = p;
-
- p += len;
- l += (len + 2);
+ if (lldp_neighbor_equal(n, old)) {
+ /* Is this equal, then restart the TTL counter, but don't do anyting else. */
+ lldp_start_timer(lldp, old);
+ lldp_callback(lldp, SD_LLDP_EVENT_REFRESHED, old);
+ return 0;
+ }
- if (i <= 3) {
- if (i != type) {
- log_lldp("TLV missing or out of order. Dropping.");
+ /* Data changed, remove the old entry, and add a new one */
+ lldp_neighbor_unlink(old);
- malformed = true;
- goto out;
- }
- }
+ } else if (!keep)
+ return 0;
- switch(type) {
- case LLDP_TYPE_CHASSIS_ID:
+ /* Then, make room for at least one new neighbor */
+ lldp_make_space(lldp, 1);
- if (len < 2) {
- log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len);
+ r = hashmap_put(lldp->neighbor_by_id, &n->id, n);
+ if (r < 0)
+ goto finish;
- malformed = true;
- goto out;
- }
+ r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx);
+ if (r < 0) {
+ assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n);
+ goto finish;
+ }
- if (chassis_id) {
- log_lldp("Duplicate Chassis ID TLV found. Dropping.");
+ n->lldp = lldp;
- malformed = true;
- goto out;
- }
+ lldp_start_timer(lldp, n);
+ lldp_callback(lldp, old ? SD_LLDP_EVENT_UPDATED : SD_LLDP_EVENT_ADDED, n);
- /* Look what subtype it has */
- if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) {
- log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q);
+ return 1;
- malformed = true;
- goto out;
+finish:
+ if (old)
+ lldp_callback(lldp, SD_LLDP_EVENT_REMOVED, n);
- }
+ return r;
+}
- chassis_id = true;
+static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) {
+ int r;
- break;
- case LLDP_TYPE_PORT_ID:
+ assert(lldp);
+ assert(n);
- if (len < 2) {
- log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len);
+ r = lldp_neighbor_parse(n);
+ if (r == -EBADMSG) /* Ignore bad messages */
+ return 0;
+ if (r < 0)
+ return r;
- malformed = true;
- goto out;
- }
+ r = lldp_add_neighbor(lldp, n);
+ if (r < 0) {
+ log_lldp_errno(r, "Failed to add datagram. Ignoring.");
+ return 0;
+ }
- if (port_id) {
- log_lldp("Duplicate Port ID TLV found. Dropping.");
+ log_lldp("Successfully processed LLDP datagram.");
+ return 0;
+}
- malformed = true;
- goto out;
- }
+static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
+ ssize_t space, length;
+ sd_lldp *lldp = userdata;
- /* Look what subtype it has */
- if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) {
- log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q);
+ assert(fd >= 0);
+ assert(lldp);
- malformed = true;
- goto out;
+ space = next_datagram_size_fd(fd);
+ if (space < 0)
+ return log_lldp_errno(space, "Failed to determine datagram size to read: %m");
- }
+ n = lldp_neighbor_new(space);
+ if (!n)
+ return -ENOMEM;
- port_id = true;
+ length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT);
+ if (length < 0)
+ return log_lldp_errno(errno, "Failed to read LLDP datagram: %m");
- break;
- case LLDP_TYPE_TTL:
+ if ((size_t) length != n->raw_size) {
+ log_lldp("Packet size mismatch.");
+ return -EINVAL;
+ }
- if(len != 2) {
- log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len);
+ return lldp_handle_datagram(lldp, n);
+}
- malformed = true;
- goto out;
- }
+_public_ int sd_lldp_start(sd_lldp *lldp) {
+ int r;
- if (ttl) {
- log_lldp("Duplicate TTL TLV found. Dropping.");
+ assert_return(lldp, -EINVAL);
- malformed = true;
- goto out;
- }
+ if (lldp->fd >= 0)
+ return 0;
- ttl = true;
+ assert(!lldp->io_event_source);
- break;
- case LLDP_TYPE_SYSTEM_NAME:
+ lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex);
+ if (lldp->fd < 0)
+ return lldp->fd;
- /* According to RFC 1035 the length of a FQDN is limited to 255 characters */
- if (len > 255) {
- log_lldp("Received invalid system name length: %d. Dropping.", len);
- malformed = true;
- goto out;
- }
+ if (lldp->event) {
+ r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp);
+ if (r < 0)
+ goto fail;
- if (system_name) {
- log_lldp("Duplicate system name found. Dropping.");
- malformed = true;
- goto out;
- }
+ r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority);
+ if (r < 0)
+ goto fail;
- system_name = true;
+ (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io");
+ }
- break;
- case LLDP_TYPE_SYSTEM_DESCRIPTION:
-
- /* 0 <= n <= 255 octets */
- if (len > 255) {
- log_lldp("Received invalid system description length: %d. Dropping.", len);
- malformed = true;
- goto out;
- }
-
- if (system_description) {
- log_lldp("Duplicate system description found. Dropping.");
- malformed = true;
- goto out;
- }
-
- system_description = true;
- break;
- default:
+ return 1;
- if (len == 0) {
- log_lldp("TLV type: %d length 0 received. Dropping.", type);
+fail:
+ lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
+ lldp->fd = safe_close(lldp->fd);
- malformed = true;
- goto out;
- }
- break;
- }
- }
+ return r;
+}
- if(!chassis_id || !port_id || !ttl || !end) {
- log_lldp("One or more mandatory TLV missing. Dropping.");
+_public_ int sd_lldp_stop(sd_lldp *lldp) {
+ assert_return(lldp, -EINVAL);
- malformed = true;
- goto out;
+ if (lldp->fd < 0)
+ return 0;
- }
+ lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source);
+ lldp->io_event_source = sd_event_source_unref(lldp->io_event_source);
+ lldp->fd = safe_close(lldp->fd);
- r = tlv_packet_parse_pdu(tlv, length);
- if (r < 0) {
- log_lldp("Failed to parse the TLV. Dropping.");
+ lldp_flush_neighbors(lldp);
- malformed = true;
- goto out;
- }
+ return 1;
+}
- return lldp_receive_frame(lldp, tlv);
+_public_ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) {
+ int r;
- out:
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
+ assert_return(lldp, -EINVAL);
+ assert_return(lldp->fd < 0, -EBUSY);
+ assert_return(!lldp->event, -EBUSY);
- if (malformed) {
- lldp->statistics.stats_frames_discarded_total ++;
- lldp->statistics.stats_frames_in_errors_total ++;
+ if (event)
+ lldp->event = sd_event_ref(event);
+ else {
+ r = sd_event_default(&lldp->event);
+ if (r < 0)
+ return r;
}
- sd_lldp_packet_unref(tlv);
+ lldp->event_priority = priority;
return 0;
}
-static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) {
- const lldp_neighbour_port *p = a, *q = b;
+_public_ int sd_lldp_detach_event(sd_lldp *lldp) {
- if (p->until < q->until)
- return -1;
-
- if (p->until > q->until)
- return 1;
+ assert_return(lldp, -EINVAL);
+ assert_return(lldp->fd < 0, -EBUSY);
+ lldp->event = sd_event_unref(lldp->event);
return 0;
}
-static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) {
-
- assert(lldp);
- assert(state < _LLDP_AGENT_RX_STATE_MAX);
+_public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) {
+ assert_return(lldp, -EINVAL);
- lldp->rx_state = state;
+ lldp->callback = cb;
+ lldp->userdata = userdata;
- lldp_run_state_machine(lldp);
+ return 0;
}
-static void lldp_run_state_machine(sd_lldp *lldp) {
- if (!lldp->cb)
- return;
-
- switch (lldp->rx_state) {
- case LLDP_AGENT_RX_UPDATE_INFO:
- lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata);
- break;
- default:
- break;
- }
-}
+_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
-/* 10.5.5.2.1 mibDeleteObjects ()
- * The mibDeleteObjects () procedure deletes all information in the LLDP remote
- * systems MIB associated with the MSAP identifier if an LLDPDU is received with
- * an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */
+ if (!lldp)
+ return NULL;
-static void lldp_mib_delete_objects(sd_lldp *lldp) {
- lldp_neighbour_port *p;
- usec_t t = 0;
+ lldp_flush_neighbors(lldp);
- /* Remove all entries that are past their TTL */
- for (;;) {
+ hashmap_free(lldp->neighbor_by_id);
+ prioq_free(lldp->neighbor_by_expiry);
- if (prioq_size(lldp->by_expiry) <= 0)
- break;
+ sd_event_source_unref(lldp->io_event_source);
+ sd_event_source_unref(lldp->timer_event_source);
+ sd_event_unref(lldp->event);
+ safe_close(lldp->fd);
- p = prioq_peek(lldp->by_expiry);
- if (!p)
- break;
+ free(lldp);
- if (t <= 0)
- t = now(clock_boottime_or_monotonic());
+ return NULL;
+}
- if (p->until > t)
- break;
+_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) {
+ _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
+ int r;
- lldp_neighbour_port_remove_and_free(p);
+ assert_return(ret, -EINVAL);
+ assert_return(ifindex > 0, -EINVAL);
- lldp->statistics.stats_ageouts_total ++;
- }
-}
+ lldp = new0(sd_lldp, 1);
+ if (!lldp)
+ return -ENOMEM;
-static void lldp_mib_objects_flush(sd_lldp *lldp) {
- lldp_neighbour_port *p, *q;
- lldp_chassis *c;
+ lldp->fd = -1;
+ lldp->ifindex = ifindex;
+ lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX;
+ lldp->capability_mask = (uint16_t) -1;
- assert(lldp);
- assert(lldp->neighbour_mib);
- assert(lldp->by_expiry);
+ lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops);
+ if (!lldp->neighbor_by_id)
+ return -ENOMEM;
- /* Drop all packets */
- while ((c = hashmap_steal_first(lldp->neighbour_mib))) {
+ r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func);
+ if (r < 0)
+ return r;
- LIST_FOREACH_SAFE(port, p, q, c->ports) {
- lldp_neighbour_port_remove_and_free(p);
- }
- }
+ *ret = lldp;
+ lldp = NULL;
- assert(hashmap_size(lldp->neighbour_mib) == 0);
- assert(prioq_size(lldp->by_expiry) == 0);
+ return 0;
}
-int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) {
- _cleanup_free_ char *temp_path = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- uint8_t *mac, *port_id, type;
- lldp_neighbour_port *p;
- uint16_t data = 0, length = 0;
- char buf[LINE_MAX];
- lldp_chassis *c;
- usec_t time;
- Iterator i;
- int r;
+static int neighbor_compare_func(const void *a, const void *b) {
+ const sd_lldp_neighbor * const*x = a, * const *y = b;
- assert(lldp);
- assert(lldp_file);
+ return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id);
+}
- r = fopen_temporary(lldp_file, &f, &temp_path);
- if (r < 0)
- goto fail;
-
- fchmod(fileno(f), 0644);
-
- HASHMAP_FOREACH(c, lldp->neighbour_mib, i) {
- LIST_FOREACH(port, p, c->ports) {
- _cleanup_free_ char *s = NULL;
- char *k, *t;
-
- r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length);
- if (r < 0)
- continue;
-
- sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
-
- s = strdup(buf);
- if (!s) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length);
- if (r < 0)
- continue;
-
- if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) {
- k = strndup((char *) port_id, length -1);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type);
- free(k);
- } else {
- mac = port_id;
- sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type);
- }
-
- k = strappend(s, buf);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- time = now(clock_boottime_or_monotonic());
-
- /* Don't write expired packets */
- if (time - p->until <= 0)
- continue;
-
- sprintf(buf, "'_TTL="USEC_FMT"' ", p->until);
-
- k = strappend(s, buf);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- r = sd_lldp_packet_read_system_name(p->packet, &k, &length);
- if (r < 0)
- k = strappend(s, "'_NAME=N/A' ");
- else {
- t = strndup(k, length);
- if (!t) {
- r = -ENOMEM;
- goto fail;
- }
-
- k = strjoin(s, "'_NAME=", t, "' ", NULL);
- free(t);
- }
-
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- (void) sd_lldp_packet_read_system_capability(p->packet, &data);
-
- sprintf(buf, "'_CAP=%x'", data);
-
- k = strappend(s, buf);
- if (!k) {
- r = -ENOMEM;
- goto fail;
- }
-
- free(s);
- s = k;
-
- fprintf(f, "%s\n", s);
- }
- }
+static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) {
+ sd_lldp *lldp = userdata;
+ int r, q;
- r = fflush_and_check(f);
+ r = lldp_make_space(lldp, 0);
if (r < 0)
- goto fail;
+ return log_lldp_errno(r, "Failed to make space: %m");
- if (rename(temp_path, lldp_file) < 0) {
- r = -errno;
- goto fail;
- }
+ q = lldp_start_timer(lldp, NULL);
+ if (q < 0)
+ return log_lldp_errno(q, "Failed to restart timer: %m");
return 0;
-
- fail:
- if (temp_path)
- (void) unlink(temp_path);
-
- return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file);
}
-int sd_lldp_start(sd_lldp *lldp) {
+static int lldp_start_timer(sd_lldp *lldp, sd_lldp_neighbor *neighbor) {
+ sd_lldp_neighbor *n;
int r;
- assert_return(lldp, -EINVAL);
- assert_return(lldp->port, -EINVAL);
+ assert(lldp);
- lldp->port->status = LLDP_PORT_STATUS_ENABLED;
+ if (neighbor)
+ lldp_neighbor_start_ttl(neighbor);
- lldp_set_state(lldp, LLDP_AGENT_RX_LLDP_INITIALIZE);
+ n = prioq_peek(lldp->neighbor_by_expiry);
+ if (!n) {
- r = lldp_port_start(lldp->port);
- if (r < 0) {
- log_lldp("Failed to start Port : %s , %s",
- lldp->port->ifname,
- strerror(-r));
+ if (lldp->timer_event_source)
+ return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF);
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL);
-
- return r;
+ return 0;
}
- lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME);
-
- return 0;
-}
-
-int sd_lldp_stop(sd_lldp *lldp) {
- int r;
+ if (lldp->timer_event_source) {
+ r = sd_event_source_set_time(lldp->timer_event_source, n->until);
+ if (r < 0)
+ return r;
- assert_return(lldp, -EINVAL);
- assert_return(lldp->port, -EINVAL);
+ return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT);
+ }
- lldp->port->status = LLDP_PORT_STATUS_DISABLED;
+ if (!lldp->event)
+ return 0;
- r = lldp_port_stop(lldp->port);
+ r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp);
if (r < 0)
return r;
- lldp_mib_objects_flush(lldp);
+ r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority);
+ if (r < 0)
+ return r;
+ (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer");
return 0;
}
-int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) {
- int r;
+_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) {
+ sd_lldp_neighbor **l = NULL, *n;
+ Iterator i;
+ int k = 0, r;
assert_return(lldp, -EINVAL);
- assert_return(!lldp->port->event, -EBUSY);
+ assert_return(ret, -EINVAL);
- if (event)
- lldp->port->event = sd_event_ref(event);
- else {
- r = sd_event_default(&lldp->port->event);
- if (r < 0)
- return r;
+ if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */
+ *ret = NULL;
+ return 0;
}
- lldp->port->event_priority = priority;
+ l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id));
+ if (!l)
+ return -ENOMEM;
- return 0;
-}
+ r = lldp_start_timer(lldp, NULL);
+ if (r < 0) {
+ free(l);
+ return r;
+ }
-int sd_lldp_detach_event(sd_lldp *lldp) {
+ HASHMAP_FOREACH(n, lldp->neighbor_by_id, i)
+ l[k++] = sd_lldp_neighbor_ref(n);
- assert_return(lldp, -EINVAL);
+ assert((size_t) k == hashmap_size(lldp->neighbor_by_id));
- lldp->port->event = sd_event_unref(lldp->port->event);
+ /* Return things in a stable order */
+ qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func);
+ *ret = l;
- return 0;
+ return k;
}
-int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) {
+_public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) {
assert_return(lldp, -EINVAL);
+ assert_return(m <= 0, -EINVAL);
- lldp->cb = cb;
- lldp->userdata = userdata;
+ lldp->neighbors_max = m;
+ lldp_make_space(lldp, 0);
return 0;
}
-sd_lldp* sd_lldp_unref(sd_lldp *lldp) {
-
- if (!lldp)
- return NULL;
-
- /* Drop all packets */
- lldp_mib_objects_flush(lldp);
-
- lldp_port_free(lldp->port);
-
- hashmap_free(lldp->neighbour_mib);
- prioq_free(lldp->by_expiry);
-
- free(lldp);
- return NULL;
-}
-
-int sd_lldp_new(int ifindex,
- const char *ifname,
- const struct ether_addr *mac,
- sd_lldp **ret) {
- _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
- int r;
-
- assert_return(ret, -EINVAL);
- assert_return(ifindex > 0, -EINVAL);
- assert_return(ifname, -EINVAL);
- assert_return(mac, -EINVAL);
-
- lldp = new0(sd_lldp, 1);
- if (!lldp)
- return -ENOMEM;
-
- r = lldp_port_new(ifindex, ifname, mac, lldp, &lldp->port);
- if (r < 0)
- return r;
-
- lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops);
- if (!lldp->neighbour_mib)
- return -ENOMEM;
-
- r = prioq_ensure_allocated(&lldp->by_expiry,
- ttl_expiry_item_prioq_compare_func);
- if (r < 0)
- return r;
-
- lldp->rx_state = LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL;
+_public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) {
+ assert_return(lldp, -EINVAL);
+ assert_return(mask != 0, -EINVAL);
- *ret = lldp;
- lldp = NULL;
+ lldp->capability_mask = mask;
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;
-
+_public_ int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *addr) {
assert_return(lldp, -EINVAL);
- assert_return(tlvs, -EINVAL);
- HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) {
- LIST_FOREACH(port, p, c->ports)
- count++;
- }
+ /* In order to deal nicely with bridges that send back our own packets, allow one address to be filtered, so
+ * that our own can be filtered out here. */
- if (!count) {
- *tlvs = NULL;
+ if (!addr) {
+ zero(lldp->filter_address);
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;
+ lldp->filter_address = *addr;
+ return 0;
}
diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c
index cd07fc1b3f..1c0d300cb3 100644
--- a/src/libsystemd-network/sd-ndisc.c
+++ b/src/libsystemd-network/sd-ndisc.c
@@ -166,7 +166,7 @@ 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_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority) {
int r;
assert_return(nd, -EINVAL);
diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c
index 7d8a957227..d84859c053 100644
--- a/src/libsystemd-network/test-dhcp-option.c
+++ b/src/libsystemd-network/test-dhcp-option.c
@@ -110,14 +110,9 @@ static DHCPMessage *create_message(uint8_t *options, uint16_t optlen,
message = malloc0(len);
assert_se(message);
- if (options && optlen)
- memcpy(&message->options, options, optlen);
-
- if (file && filelen <= 128)
- memcpy(&message->file, file, filelen);
-
- if (sname && snamelen <= 64)
- memcpy(&message->sname, sname, snamelen);
+ memcpy_safe(&message->options, options, optlen);
+ memcpy_safe(&message->file, file, filelen);
+ memcpy_safe(&message->sname, sname, snamelen);
return message;
}
diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c
index 0243bc132b..8c6d214d6f 100644
--- a/src/libsystemd-network/test-lldp.c
+++ b/src/libsystemd-network/test-lldp.c
@@ -22,6 +22,7 @@
#include <net/ethernet.h>
#include <stdio.h>
#include <string.h>
+#include <unistd.h>
#include <systemd/sd-event.h>
#include <systemd/sd-lldp.h>
@@ -29,8 +30,6 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "lldp-network.h"
-#include "lldp-tlv.h"
-#include "lldp.h"
#include "macro.h"
#include "string-util.h"
@@ -38,211 +37,8 @@
#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_(sd_lldp_packet_unrefp) tlv_packet *m = NULL;
- const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR;
- struct ether_header ether = {
- .ether_type = htons(ETHERTYPE_LLDP),
- };
-
- /* Append Ethernet header */
- memcpy(&ether.ether_dhost, lldp_dst, ETHER_ADDR_LEN);
- memcpy(&ether.ether_shost, &mac_addr, ETHER_ADDR_LEN);
-
- assert_se(tlv_packet_new(&m) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, &ether, sizeof(struct ether_header)) >= 0);
-
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
-
- assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0);
- assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* port name */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0);
-
- assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0);
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* ttl */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0);
-
- assert_se(tlv_packet_append_u16(m, 170) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* system name */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME,
- strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0);
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* system descrition */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
-
- assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC,
- strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0);
-
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- /* Mark end of packet */
- assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0);
- assert_se(lldp_tlv_packet_close_container(m) >= 0);
-
- *ret = m;
-
- m = NULL;
-
- return 0;
-}
-
-static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) {
- uint8_t *p, subtype;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0);
- assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
-
- switch (subtype) {
- case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS:
-
- *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS;
- assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0);
-
- assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0);
-
- break;
- default:
- assert_not_reached("Unhandled option");
- }
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_port_id_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
- uint8_t subtype;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0);
-
- assert_se(tlv_packet_read_u8(m, &subtype) >= 0);
-
- switch (subtype) {
- case LLDP_PORT_SUBTYPE_INTERFACE_NAME:
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length-1);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_PORT) == 1);
- break;
- default:
- assert_not_reached("Unhandled option");
- }
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_system_name_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0);
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 1;
-}
-
-static int lldp_parse_system_desc_tlv(tlv_packet *m) {
- _cleanup_free_ char *p = NULL;
- char *str = NULL;
- uint16_t length;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0);
- assert_se(tlv_packet_read_string(m, &str, &length) >= 0);
-
- p = strndup(str, length);
- assert_se(p);
-
- assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- return 0;
-}
-
-static int lldp_parse_ttl_tlv(tlv_packet *m) {
- uint16_t ttl;
-
- assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0);
- assert_se(tlv_packet_read_u16(m, &ttl) >= 0);
-
- assert_se(ttl == 170);
-
- assert_se(lldp_tlv_packet_exit_container(m) >= 0);
-
- 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;
-
- assert_se(tlv_packet_parse_pdu(m, len) >= 0);
- assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0);
- assert_se(lldp_parse_port_id_tlv(m) >= 0);
- assert_se(lldp_parse_system_name_tlv(m) >= 0);
- 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;
-}
-
-static void test_parser(void) {
- _cleanup_(sd_lldp_packet_unrefp) 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);
-}
+static int test_fd[2] = { -1, -1 };
+static int lldp_handler_calls;
int lldp_network_bind_raw_socket(int ifindex) {
if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0)
@@ -251,28 +47,27 @@ int lldp_network_bind_raw_socket(int ifindex) {
return test_fd[0];
}
-static int lldp_handler_calls;
-static void lldp_handler (sd_lldp *lldp, int event, void *userdata) {
+static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
lldp_handler_calls++;
}
-static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) {
+static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) {
int r;
- r = sd_lldp_new(42, "dummy", &mac_addr, lldp);
- if (r)
+ r = sd_lldp_new(lldp, 42);
+ if (r < 0)
return r;
r = sd_lldp_attach_event(*lldp, e, 0);
- if (r)
+ if (r < 0)
return r;
r = sd_lldp_set_callback(*lldp, cb, cb_data);
- if (r)
+ if (r < 0)
return r;
r = sd_lldp_start(*lldp);
- if (r)
+ if (r < 0)
return r;
return 0;
@@ -282,11 +77,11 @@ static int stop_lldp(sd_lldp *lldp) {
int r;
r = sd_lldp_stop(lldp);
- if (r)
+ if (r < 0)
return r;
r = sd_lldp_detach_event(lldp);
- if (r)
+ if (r < 0)
return r;
sd_lldp_unref(lldp);
@@ -296,13 +91,8 @@ static int stop_lldp(sd_lldp *lldp) {
}
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[] = {
+
+ static const uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */
@@ -319,51 +109,53 @@ static void test_receive_basic_packet(sd_event *e) {
0x00, 0x00 /* End Of LLDPDU */
};
+ sd_lldp *lldp;
+ sd_lldp_neighbor **neighbors;
+ uint8_t type;
+ const void *data;
+ uint16_t ttl;
+ size_t length;
+ const char *str;
+
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_get_neighbors(lldp, &neighbors) == 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(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0);
+ assert_se(type == SD_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(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0);
+ assert_se(type == SD_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_neighbor_get_port_description(neighbors[0], &str) == 0);
+ assert_se(streq(str, "Port"));
- 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_neighbor_get_system_name(neighbors[0], &str) == 0);
+ assert_se(streq(str, "SYS"));
- 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_neighbor_get_system_description(neighbors[0], &str) == 0);
+ assert_se(streq(str, "foo"));
- assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0);
+ assert_se(sd_lldp_neighbor_get_ttl(neighbors[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);
+ sd_lldp_neighbor_unref(neighbors[0]);
+ free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
static void test_receive_incomplete_packet(sd_event *e) {
sd_lldp *lldp;
- sd_lldp_packet **packets;
+ sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -383,18 +175,14 @@ static void test_receive_incomplete_packet(sd_event *e) {
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(sd_lldp_get_neighbors(lldp, &neighbors) == 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;
+ sd_lldp_neighbor **neighbors;
uint8_t frame[] = {
/* Ethernet header */
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/
@@ -426,29 +214,30 @@ static void test_receive_oui_packet(sd_event *e) {
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(sd_lldp_get_neighbors(lldp, &neighbors) == 1);
+
+ assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_CHASSIS_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_PORT_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_TTL) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], SD_LLDP_OUI_802_1, SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0);
+ assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], SD_LLDP_TYPE_END) > 0);
+ assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0);
+
+ sd_lldp_neighbor_unref(neighbors[0]);
+ free(neighbors);
assert_se(stop_lldp(lldp) == 0);
}
@@ -456,7 +245,7 @@ static void test_receive_oui_packet(sd_event *e) {
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e = NULL;
- test_parser();
+ log_set_max_level(LOG_DEBUG);
/* LLDP reception tests */
assert_se(sd_event_new(&e) == 0);
diff --git a/src/libsystemd/Makefile b/src/libsystemd/Makefile
index 202133a4d8..2c6505918b 100644
--- a/src/libsystemd/Makefile
+++ b/src/libsystemd/Makefile
@@ -23,27 +23,9 @@
include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
-LIBSYSTEMD_CURRENT=14
+LIBSYSTEMD_CURRENT=15
LIBSYSTEMD_REVISION=0
-LIBSYSTEMD_AGE=14
-
-# The following four libraries only exist for compatibility reasons,
-# their version info should not be bumped anymore
-LIBSYSTEMD_LOGIN_CURRENT=9
-LIBSYSTEMD_LOGIN_REVISION=3
-LIBSYSTEMD_LOGIN_AGE=9
-
-LIBSYSTEMD_DAEMON_CURRENT=0
-LIBSYSTEMD_DAEMON_REVISION=12
-LIBSYSTEMD_DAEMON_AGE=0
-
-LIBSYSTEMD_ID128_CURRENT=0
-LIBSYSTEMD_ID128_REVISION=28
-LIBSYSTEMD_ID128_AGE=0
-
-LIBSYSTEMD_JOURNAL_CURRENT=11
-LIBSYSTEMD_JOURNAL_REVISION=5
-LIBSYSTEMD_JOURNAL_AGE=11
+LIBSYSTEMD_AGE=15
EXTRA_DIST += \
src/libsystemd/libsystemd.pc.in \
@@ -95,7 +77,6 @@ tests += \
test-bus-cleanup \
test-bus-server \
test-bus-match \
- test-bus-proxy \
test-bus-kernel \
test-bus-kernel-bloom \
test-bus-zero-copy \
diff --git a/src/libsystemd/compat-libs/.gitignore b/src/libsystemd/compat-libs/.gitignore
deleted file mode 100644
index 662c154cdd..0000000000
--- a/src/libsystemd/compat-libs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/libsystemd-*.pc
diff --git a/src/libsystemd/compat-libs/Makefile b/src/libsystemd/compat-libs/Makefile
deleted file mode 100644
index 9d528431f4..0000000000
--- a/src/libsystemd/compat-libs/Makefile
+++ /dev/null
@@ -1,146 +0,0 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*-
-#
-# This file is part of systemd.
-#
-# Copyright 2010-2012 Lennart Poettering
-# Copyright 2010-2012 Kay Sievers
-# Copyright 2013 Zbigniew Jędrzejewski-Szmek
-# Copyright 2013 David Strauss
-# Copyright 2016 Luke Shumaker
-#
-# 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 $(dir $(lastword $(MAKEFILE_LIST)))/../../../config.mk
-include $(topsrcdir)/build-aux/Makefile.head.mk
-
-ifneq ($(ENABLE_COMPAT_LIBS),)
-libsystemd-%.c: src/compat-libs/libsystemd-%.sym
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)sed -r -n 's/^ +(sd_.*);/obsolete_lib(\1,$(notdir $(basename $<)));/p' <$< >$@
-
-BUILT_SOURCES += \
- libsystemd-journal.c \
- libsystemd-login.c \
- libsystemd-id128.c \
- libsystemd-daemon.c
-
-nodist_libsystemd_journal_la_SOURCES = \
- libsystemd-journal.c
-
-libsystemd_journal_la_SOURCES = \
- src/compat-libs/libsystemd-journal.sym
-
-libsystemd_journal_la_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -imacros$(top_srcdir)/src/compat-libs/linkwarning.h
-
-libsystemd_journal_la_LDFLAGS = \
- $(AM_LDFLAGS) \
- -version-info $(LIBSYSTEMD_JOURNAL_CURRENT):$(LIBSYSTEMD_JOURNAL_REVISION):$(LIBSYSTEMD_JOURNAL_AGE) \
- -Wl,--version-script=$(srcdir)/libsystemd-journal.sym
-
-libsystemd_journal_la_LIBADD = \
- libsystemd-journal-internal.la \
- libsystemd-internal.la
-
-nodist_libsystemd_login_la_SOURCES = \
- libsystemd-login.c
-
-libsystemd_login_la_SOURCES = \
- src/compat-libs/libsystemd-login.sym
-
-libsystemd_login_la_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -imacros$(top_srcdir)/src/compat-libs/linkwarning.h
-
-libsystemd_login_la_LDFLAGS = \
- $(AM_LDFLAGS) \
- -version-info $(LIBSYSTEMD_LOGIN_CURRENT):$(LIBSYSTEMD_LOGIN_REVISION):$(LIBSYSTEMD_LOGIN_AGE) \
- -Wl,--version-script=$(srcdir)/libsystemd-login.sym
-
-libsystemd_login_la_LIBADD = \
- libsystemd-internal.la
-
-nodist_libsystemd_id128_la_SOURCES = \
- libsystemd-id128.c
-
-libsystemd_id128_la_SOURCES = \
- src/compat-libs/libsystemd-id128.sym
-
-libsystemd_id128_la_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -imacros$(top_srcdir)/src/compat-libs/linkwarning.h
-
-libsystemd_id128_la_LDFLAGS = \
- $(AM_LDFLAGS) \
- -version-info $(LIBSYSTEMD_ID128_CURRENT):$(LIBSYSTEMD_ID128_REVISION):$(LIBSYSTEMD_ID128_AGE) \
- -Wl,--version-script=$(srcdir)/libsystemd-id128.sym
-
-libsystemd_id128_la_LIBADD = \
- libsystemd-internal.la
-
-nodist_libsystemd_daemon_la_SOURCES = \
- libsystemd-daemon.c
-
-libsystemd_daemon_la_SOURCES = \
- src/compat-libs/libsystemd-daemon.sym
-
-libsystemd_daemon_la_CPPFLAGS = \
- $(AM_CPPFLAGS) \
- -imacros$(top_srcdir)/src/compat-libs/linkwarning.h
-
-libsystemd_daemon_la_LDFLAGS = \
- $(AM_LDFLAGS) \
- -version-info $(LIBSYSTEMD_DAEMON_CURRENT):$(LIBSYSTEMD_DAEMON_REVISION):$(LIBSYSTEMD_DAEMON_AGE) \
- -Wl,--version-script=$(srcdir)/libsystemd-daemon.sym
-
-libsystemd_daemon_la_LIBADD = \
- libsystemd-internal.la
-
-lib_LTLIBRARIES += \
- libsystemd-journal.la \
- libsystemd-login.la \
- libsystemd-id128.la \
- libsystemd-daemon.la
-
-pkgconfiglib_DATA += \
- src/compat-libs/libsystemd-journal.pc \
- src/compat-libs/libsystemd-login.pc \
- src/compat-libs/libsystemd-id128.pc \
- src/compat-libs/libsystemd-daemon.pc
-
-# move lib from $(libdir) to $(libdir) and update devel link, if needed
-compat-lib-install-hook:
- libname=libsystemd-login.so && $(move-to-libdir)
- libname=libsystemd-journal.so && $(move-to-libdir)
- libname=libsystemd-id128.so && $(move-to-libdir)
- libname=libsystemd-daemon.so && $(move-to-libdir)
-
-compat-lib-uninstall-hook:
- rm -f $(DESTDIR)$(libdir)/libsystemd-login.so*
- rm -f $(DESTDIR)$(libdir)/libsystemd-journal.so*
- rm -f $(DESTDIR)$(libdir)/libsystemd-id128.so*
- rm -f $(DESTDIR)$(libdir)/libsystemd-daemon.so*
-
-INSTALL_EXEC_HOOKS += compat-lib-install-hook
-UNINSTALL_EXEC_HOOKS += compat-lib-uninstall-hook
-endif # ENABLE_COMPAT_LIBS
-
-EXTRA_DIST += \
- src/compat-libs/linkwarning.h \
- src/compat-libs/libsystemd-journal.pc.in \
- src/compat-libs/libsystemd-login.pc.in \
- src/compat-libs/libsystemd-id128.pc.in \
- src/compat-libs/libsystemd-daemon.pc.in
-
-include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/libsystemd/compat-libs/libsystemd-daemon.pc.in b/src/libsystemd/compat-libs/libsystemd-daemon.pc.in
deleted file mode 100644
index 847afc9d60..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-daemon.pc.in
+++ /dev/null
@@ -1,19 +0,0 @@
-# Permission is hereby granted, free of charge, to any person
-# obtaining a copy of this software and associated documentation files
-# (the "Software"), to deal in the Software without restriction,
-# including without limitation the rights to use, copy, modify, merge,
-# publish, distribute, sublicense, and/or sell copies of the Software,
-# and to permit persons to whom the Software is furnished to do so,
-# subject to the following conditions:
-
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: systemd
-Description: systemd Daemon Utility Library - deprecated
-URL: @PACKAGE_URL@
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lsystemd
-Cflags: -I${includedir}
diff --git a/src/libsystemd/compat-libs/libsystemd-daemon.sym b/src/libsystemd/compat-libs/libsystemd-daemon.sym
deleted file mode 100644
index f440238931..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-daemon.sym
+++ /dev/null
@@ -1,27 +0,0 @@
-/***
- Permission is hereby granted, free of charge, to any person
- obtaining a copy of this software and associated documentation files
- (the "Software"), to deal in the Software without restriction,
- including without limitation the rights to use, copy, modify, merge,
- publish, distribute, sublicense, and/or sell copies of the Software,
- and to permit persons to whom the Software is furnished to do so,
- subject to the following conditions:
-***/
-
-/* Original symbols from systemd v31 */
-
-LIBSYSTEMD_DAEMON_31 {
-global:
- sd_booted;
- sd_is_fifo;
- sd_is_mq;
- sd_is_socket;
- sd_is_socket_inet;
- sd_is_socket_unix;
- sd_is_special;
- sd_listen_fds;
- sd_notify;
- sd_notifyf;
-local:
- *;
-};
diff --git a/src/libsystemd/compat-libs/libsystemd-id128.pc.in b/src/libsystemd/compat-libs/libsystemd-id128.pc.in
deleted file mode 100644
index 80f8fee6c3..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-id128.pc.in
+++ /dev/null
@@ -1,18 +0,0 @@
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: systemd
-Description: systemd 128 Bit ID Utility Library - deprecated
-URL: @PACKAGE_URL@
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lsystemd
-Cflags: -I${includedir}
diff --git a/src/libsystemd/compat-libs/libsystemd-id128.sym b/src/libsystemd/compat-libs/libsystemd-id128.sym
deleted file mode 100644
index 604c0026c6..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-id128.sym
+++ /dev/null
@@ -1,21 +0,0 @@
-/***
- This file is part of systemd.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-***/
-
-/* Original symbols from systemd v38 */
-
-LIBSYSTEMD_ID128_38 {
-global:
- sd_id128_to_string;
- sd_id128_from_string;
- sd_id128_randomize;
- sd_id128_get_machine;
- sd_id128_get_boot;
-local:
- *;
-};
diff --git a/src/libsystemd/compat-libs/libsystemd-journal.pc.in b/src/libsystemd/compat-libs/libsystemd-journal.pc.in
deleted file mode 100644
index 395f71005b..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-journal.pc.in
+++ /dev/null
@@ -1,19 +0,0 @@
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: systemd
-Description: systemd Journal Utility Library - deprecated
-URL: @PACKAGE_URL@
-Version: @PACKAGE_VERSION@
-Requires: libsystemd = @PACKAGE_VERSION@
-Libs: -L${libdir} -lsystemd
-Cflags: -I${includedir}
diff --git a/src/libsystemd/compat-libs/libsystemd-journal.sym b/src/libsystemd/compat-libs/libsystemd-journal.sym
deleted file mode 100644
index 4eb15910d2..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-journal.sym
+++ /dev/null
@@ -1,111 +0,0 @@
-/***
- This file is part of systemd.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-***/
-
-/* Original symbols from systemd v38 */
-
-LIBSYSTEMD_JOURNAL_38 {
-global:
- sd_journal_print;
- sd_journal_printv;
- sd_journal_send;
- sd_journal_sendv;
- sd_journal_stream_fd;
- sd_journal_open;
- sd_journal_close;
- sd_journal_previous;
- sd_journal_next;
- sd_journal_previous_skip;
- sd_journal_next_skip;
- sd_journal_get_realtime_usec;
- sd_journal_get_monotonic_usec;
- sd_journal_get_data;
- sd_journal_enumerate_data;
- sd_journal_restart_data;
- sd_journal_add_match;
- sd_journal_flush_matches;
- sd_journal_seek_head;
- sd_journal_seek_tail;
- sd_journal_seek_monotonic_usec;
- sd_journal_seek_realtime_usec;
- sd_journal_seek_cursor;
- sd_journal_get_cursor;
- sd_journal_get_fd;
- sd_journal_process;
-local:
- *;
-};
-
-LIBSYSTEMD_JOURNAL_183 {
-global:
- sd_journal_print_with_location;
- sd_journal_printv_with_location;
- sd_journal_send_with_location;
- sd_journal_sendv_with_location;
-} LIBSYSTEMD_JOURNAL_38;
-
-LIBSYSTEMD_JOURNAL_184 {
-global:
- sd_journal_get_cutoff_realtime_usec;
- sd_journal_get_cutoff_monotonic_usec;
-} LIBSYSTEMD_JOURNAL_183;
-
-LIBSYSTEMD_JOURNAL_187 {
-global:
- sd_journal_wait;
- sd_journal_open_directory;
- sd_journal_add_disjunction;
-} LIBSYSTEMD_JOURNAL_184;
-
-LIBSYSTEMD_JOURNAL_188 {
-global:
- sd_journal_perror;
- sd_journal_perror_with_location;
-} LIBSYSTEMD_JOURNAL_187;
-
-LIBSYSTEMD_JOURNAL_190 {
-global:
- sd_journal_get_usage;
-} LIBSYSTEMD_JOURNAL_188;
-
-LIBSYSTEMD_JOURNAL_195 {
-global:
- sd_journal_test_cursor;
- sd_journal_query_unique;
- sd_journal_enumerate_unique;
- sd_journal_restart_unique;
-} LIBSYSTEMD_JOURNAL_190;
-
-LIBSYSTEMD_JOURNAL_196 {
-global:
- sd_journal_get_catalog;
- sd_journal_get_catalog_for_message_id;
- sd_journal_set_data_threshold;
- sd_journal_get_data_threshold;
-} LIBSYSTEMD_JOURNAL_195;
-
-LIBSYSTEMD_JOURNAL_198 {
-global:
- sd_journal_reliable_fd;
-} LIBSYSTEMD_JOURNAL_196;
-
-LIBSYSTEMD_JOURNAL_201 {
-global:
- sd_journal_get_events;
- sd_journal_get_timeout;
-} LIBSYSTEMD_JOURNAL_198;
-
-LIBSYSTEMD_JOURNAL_202 {
-global:
- sd_journal_add_conjunction;
-} LIBSYSTEMD_JOURNAL_201;
-
-LIBSYSTEMD_JOURNAL_205 {
-global:
- sd_journal_open_files;
-} LIBSYSTEMD_JOURNAL_202;
diff --git a/src/libsystemd/compat-libs/libsystemd-login.pc.in b/src/libsystemd/compat-libs/libsystemd-login.pc.in
deleted file mode 100644
index db3f79c99a..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-login.pc.in
+++ /dev/null
@@ -1,18 +0,0 @@
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-
-Name: systemd
-Description: systemd Login Utility Library - deprecated
-URL: @PACKAGE_URL@
-Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lsystemd
-Cflags: -I${includedir}
diff --git a/src/libsystemd/compat-libs/libsystemd-login.sym b/src/libsystemd/compat-libs/libsystemd-login.sym
deleted file mode 100644
index 54aa91c609..0000000000
--- a/src/libsystemd/compat-libs/libsystemd-login.sym
+++ /dev/null
@@ -1,87 +0,0 @@
-/***
- This file is part of systemd.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-***/
-
-/* Original symbols from systemd v31 */
-
-LIBSYSTEMD_LOGIN_31 {
-global:
- sd_get_seats;
- sd_get_sessions;
- sd_get_uids;
- sd_login_monitor_flush;
- sd_login_monitor_get_fd;
- sd_login_monitor_new;
- sd_login_monitor_unref;
- sd_pid_get_owner_uid;
- sd_pid_get_session;
- sd_seat_can_multi_session;
- sd_seat_get_active;
- sd_seat_get_sessions;
- sd_session_get_seat;
- sd_session_get_uid;
- sd_session_is_active;
- sd_uid_get_seats;
- sd_uid_get_sessions;
- sd_uid_get_state;
- sd_uid_is_on_seat;
-local:
- *;
-};
-
-LIBSYSTEMD_LOGIN_38 {
-global:
- sd_pid_get_unit;
- sd_session_get_service;
-} LIBSYSTEMD_LOGIN_31;
-
-LIBSYSTEMD_LOGIN_43 {
-global:
- sd_session_get_type;
- sd_session_get_class;
- sd_session_get_display;
-} LIBSYSTEMD_LOGIN_38;
-
-LIBSYSTEMD_LOGIN_186 {
-global:
- sd_session_get_state;
- sd_seat_can_tty;
- sd_seat_can_graphical;
-} LIBSYSTEMD_LOGIN_43;
-
-LIBSYSTEMD_LOGIN_198 {
-global:
- sd_session_get_tty;
-} LIBSYSTEMD_LOGIN_186;
-
-LIBSYSTEMD_LOGIN_201 {
-global:
- sd_login_monitor_get_events;
- sd_login_monitor_get_timeout;
-} LIBSYSTEMD_LOGIN_198;
-
-LIBSYSTEMD_LOGIN_202 {
-global:
- sd_pid_get_user_unit;
- sd_pid_get_machine_name;
-} LIBSYSTEMD_LOGIN_201;
-
-LIBSYSTEMD_LOGIN_203 {
-global:
- sd_get_machine_names;
-} LIBSYSTEMD_LOGIN_202;
-
-LIBSYSTEMD_LOGIN_205 {
-global:
- sd_pid_get_slice;
-} LIBSYSTEMD_LOGIN_203;
-
-LIBSYSTEMD_LOGIN_207 {
-global:
- sd_session_get_vt;
-} LIBSYSTEMD_LOGIN_205;
diff --git a/src/libsystemd/compat-libs/linkwarning.h b/src/libsystemd/compat-libs/linkwarning.h
deleted file mode 100644
index 79ece9e7d1..0000000000
--- a/src/libsystemd/compat-libs/linkwarning.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/***
- This file is part of systemd, but is heavily based on
- glibc's libc-symbols.h.
-
- Copyright (C) 1995-1998,2000-2006,2008,2009 Free Software Foundation, Inc
-
- 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/>.
-***/
-
-#pragma once
-
-#define __make_section_unallocated(section_string) \
- asm (".section " section_string "\n\t.previous");
-
-#define __sec_comment "\n#APP\n\t#"
-
-#define link_warning(symbol, msg) \
- __make_section_unallocated (".gnu.warning." #symbol) \
- static const char __evoke_link_warning_##symbol[] \
- __attribute__ ((used, section (".gnu.warning." #symbol __sec_comment))) \
- = msg
-
-#define obsolete_lib(name, lib) \
- link_warning(name, #name " was moved to libsystemd. Do not use " #lib ".")
diff --git a/src/libsystemd/include/systemd/_sd-common.h b/src/libsystemd/include/systemd/_sd-common.h
index 2d4e1f26e1..3bb886be75 100644
--- a/src/libsystemd/include/systemd/_sd-common.h
+++ b/src/libsystemd/include/systemd/_sd-common.h
@@ -74,7 +74,7 @@
#endif
#define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \
- static inline void func##p(type **p) { \
+ static __inline__ void func##p(type **p) { \
if (*p) \
func(*p); \
} \
diff --git a/src/libsystemd/include/systemd/sd-bus-protocol.h b/src/libsystemd/include/systemd/sd-bus-protocol.h
index 47b256d5b9..623cee0c50 100644
--- a/src/libsystemd/include/systemd/sd-bus-protocol.h
+++ b/src/libsystemd/include/systemd/sd-bus-protocol.h
@@ -59,7 +59,7 @@ enum {
SD_BUS_TYPE_STRUCT_END = ')',
SD_BUS_TYPE_DICT_ENTRY = 'e', /* not actually used in signatures */
SD_BUS_TYPE_DICT_ENTRY_BEGIN = '{',
- SD_BUS_TYPE_DICT_ENTRY_END = '}',
+ SD_BUS_TYPE_DICT_ENTRY_END = '}'
};
/* Well-known errors. Note that this is only a sanitized subset of the
diff --git a/src/libsystemd/include/systemd/sd-bus-vtable.h b/src/libsystemd/include/systemd/sd-bus-vtable.h
index 9363f5425a..2b684b5678 100644
--- a/src/libsystemd/include/systemd/sd-bus-vtable.h
+++ b/src/libsystemd/include/systemd/sd-bus-vtable.h
@@ -34,7 +34,7 @@ enum {
_SD_BUS_VTABLE_METHOD = 'M',
_SD_BUS_VTABLE_SIGNAL = 'S',
_SD_BUS_VTABLE_PROPERTY = 'P',
- _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W',
+ _SD_BUS_VTABLE_WRITABLE_PROPERTY = 'W'
};
enum {
diff --git a/src/libsystemd/include/systemd/sd-bus.h b/src/libsystemd/include/systemd/sd-bus.h
index 2ded47c2b6..3c1b4b97a4 100644
--- a/src/libsystemd/include/systemd/sd-bus.h
+++ b/src/libsystemd/include/systemd/sd-bus.h
@@ -89,13 +89,13 @@ enum {
SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 32,
SD_BUS_CREDS_DESCRIPTION = 1ULL << 33,
SD_BUS_CREDS_AUGMENT = 1ULL << 63, /* special flag, if on sd-bus will augment creds struct, in a potentially race-full way. */
- _SD_BUS_CREDS_ALL = (1ULL << 34) -1,
+ _SD_BUS_CREDS_ALL = (1ULL << 34) -1
};
enum {
SD_BUS_NAME_REPLACE_EXISTING = 1ULL << 0,
SD_BUS_NAME_ALLOW_REPLACEMENT = 1ULL << 1,
- SD_BUS_NAME_QUEUE = 1ULL << 2,
+ SD_BUS_NAME_QUEUE = 1ULL << 2
};
/* Callbacks */
diff --git a/src/libsystemd/include/systemd/sd-device.h b/src/libsystemd/include/systemd/sd-device.h
index 5bfca6ecec..c1d07561d7 100644
--- a/src/libsystemd/include/systemd/sd-device.h
+++ b/src/libsystemd/include/systemd/sd-device.h
@@ -22,6 +22,7 @@
***/
#include <inttypes.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include "_sd-common.h"
diff --git a/src/libsystemd/include/systemd/sd-dhcp-client.h b/src/libsystemd/include/systemd/sd-dhcp-client.h
index 897a6b0223..f7bd5c4b7a 100644
--- a/src/libsystemd/include/systemd/sd-dhcp-client.h
+++ b/src/libsystemd/include/systemd/sd-dhcp-client.h
@@ -84,26 +84,57 @@ enum {
typedef struct sd_dhcp_client sd_dhcp_client;
-typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event,
- void *userdata);
-int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb,
- void *userdata);
-
-int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option);
-int sd_dhcp_client_set_request_address(sd_dhcp_client *client,
- const struct in_addr *last_address);
-int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast);
-int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index);
-int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr,
- size_t addr_len, uint16_t arp_type);
-int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type,
- const uint8_t *data, size_t data_len);
-int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type,
- const uint8_t **data, size_t *data_len);
-int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu);
-int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname);
-int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci);
-int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret);
+typedef void (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata);
+int sd_dhcp_client_set_callback(
+ sd_dhcp_client *client,
+ sd_dhcp_client_callback_t cb,
+ void *userdata);
+
+int sd_dhcp_client_set_request_option(
+ sd_dhcp_client *client,
+ uint8_t option);
+int sd_dhcp_client_set_request_address(
+ sd_dhcp_client *client,
+ const struct in_addr *last_address);
+int sd_dhcp_client_set_request_broadcast(
+ sd_dhcp_client *client,
+ int broadcast);
+int sd_dhcp_client_set_index(
+ sd_dhcp_client *client,
+ int interface_index);
+int sd_dhcp_client_set_mac(
+ sd_dhcp_client *client,
+ const uint8_t *addr,
+ size_t addr_len,
+ uint16_t arp_type);
+int sd_dhcp_client_set_client_id(
+ sd_dhcp_client *client,
+ uint8_t type,
+ const uint8_t *data,
+ size_t data_len);
+int sd_dhcp_client_set_iaid_duid(
+ sd_dhcp_client *client,
+ uint32_t iaid,
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len);
+int sd_dhcp_client_get_client_id(
+ sd_dhcp_client *client,
+ uint8_t *type,
+ const uint8_t **data,
+ size_t *data_len);
+int sd_dhcp_client_set_mtu(
+ sd_dhcp_client *client,
+ uint32_t mtu);
+int sd_dhcp_client_set_hostname(
+ sd_dhcp_client *client,
+ const char *hostname);
+int sd_dhcp_client_set_vendor_class_identifier(
+ sd_dhcp_client *client,
+ const char *vci);
+int sd_dhcp_client_get_lease(
+ sd_dhcp_client *client,
+ sd_dhcp_lease **ret);
int sd_dhcp_client_stop(sd_dhcp_client *client);
int sd_dhcp_client_start(sd_dhcp_client *client);
@@ -113,7 +144,10 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client);
int sd_dhcp_client_new(sd_dhcp_client **ret);
-int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority);
+int sd_dhcp_client_attach_event(
+ sd_dhcp_client *client,
+ sd_event *event,
+ int64_t priority);
int sd_dhcp_client_detach_event(sd_dhcp_client *client);
sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client);
diff --git a/src/libsystemd/include/systemd/sd-dhcp-server.h b/src/libsystemd/include/systemd/sd-dhcp-server.h
index ede8f18533..bbb2bb203c 100644
--- a/src/libsystemd/include/systemd/sd-dhcp-server.h
+++ b/src/libsystemd/include/systemd/sd-dhcp-server.h
@@ -37,7 +37,7 @@ int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex);
sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server);
sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server);
-int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int priority);
+int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int64_t priority);
int sd_dhcp_server_detach_event(sd_dhcp_server *client);
sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client);
@@ -51,6 +51,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres
int sd_dhcp_server_set_timezone(sd_dhcp_server *server, const char *timezone);
int sd_dhcp_server_set_dns(sd_dhcp_server *server, const struct in_addr ntp[], unsigned n);
int sd_dhcp_server_set_ntp(sd_dhcp_server *server, const struct in_addr dns[], unsigned n);
+int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled);
int sd_dhcp_server_set_max_lease_time(sd_dhcp_server *server, uint32_t t);
int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t);
diff --git a/src/libsystemd/include/systemd/sd-dhcp6-client.h b/src/libsystemd/include/systemd/sd-dhcp6-client.h
index 9c05336ab9..6bcd9862c9 100644
--- a/src/libsystemd/include/systemd/sd-dhcp6-client.h
+++ b/src/libsystemd/include/systemd/sd-dhcp6-client.h
@@ -76,29 +76,52 @@ enum {
typedef struct sd_dhcp6_client sd_dhcp6_client;
-typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event,
- void *userdata);
-int sd_dhcp6_client_set_callback(sd_dhcp6_client *client,
- sd_dhcp6_client_cb_t cb, void *userdata);
-
-int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index);
-int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address);
-int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr,
- size_t addr_len, uint16_t arp_type);
-int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid,
- size_t duid_len);
-int sd_dhcp6_client_set_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);
-
-int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret);
+typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata);
+int sd_dhcp6_client_set_callback(
+ sd_dhcp6_client *client,
+ sd_dhcp6_client_callback_t cb,
+ void *userdata);
+
+int sd_dhcp6_client_set_index(
+ sd_dhcp6_client *client,
+ int interface_index);
+int sd_dhcp6_client_set_local_address(
+ sd_dhcp6_client *client,
+ const struct in6_addr *local_address);
+int sd_dhcp6_client_set_mac(
+ sd_dhcp6_client *client,
+ const uint8_t *addr,
+ size_t addr_len,
+ uint16_t arp_type);
+int sd_dhcp6_client_set_duid(
+ sd_dhcp6_client *client,
+ uint16_t duid_type,
+ const void *duid,
+ size_t duid_len);
+int sd_dhcp6_client_set_iaid(
+ sd_dhcp6_client *client,
+ uint32_t iaid);
+int sd_dhcp6_client_set_information_request(
+ sd_dhcp6_client *client,
+ int enabled);
+int sd_dhcp6_client_get_information_request(
+ sd_dhcp6_client *client,
+ int *enabled);
+int sd_dhcp6_client_set_request_option(
+ sd_dhcp6_client *client,
+ uint16_t option);
+
+int sd_dhcp6_client_get_lease(
+ sd_dhcp6_client *client,
+ sd_dhcp6_lease **ret);
int sd_dhcp6_client_stop(sd_dhcp6_client *client);
int sd_dhcp6_client_start(sd_dhcp6_client *client);
int sd_dhcp6_client_is_running(sd_dhcp6_client *client);
-int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event,
- int priority);
+int sd_dhcp6_client_attach_event(
+ sd_dhcp6_client *client,
+ sd_event *event,
+ int64_t priority);
int sd_dhcp6_client_detach_event(sd_dhcp6_client *client);
sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client);
sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client);
diff --git a/src/libsystemd/include/systemd/sd-event.h b/src/libsystemd/include/systemd/sd-event.h
index 1ea97e47f8..531ace1c34 100644
--- a/src/libsystemd/include/systemd/sd-event.h
+++ b/src/libsystemd/include/systemd/sd-event.h
@@ -55,7 +55,7 @@ enum {
SD_EVENT_RUNNING,
SD_EVENT_EXITING,
SD_EVENT_FINISHED,
- SD_EVENT_PREPARING,
+ SD_EVENT_PREPARING
};
enum {
@@ -69,7 +69,11 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
+#if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata);
+#else
+typedef void* sd_event_child_handler_t;
+#endif
int sd_event_default(sd_event **e);
diff --git a/src/libsystemd/include/systemd/sd-id128.h b/src/libsystemd/include/systemd/sd-id128.h
index a3bf5897b8..4dff0b9b81 100644
--- a/src/libsystemd/include/systemd/sd-id128.h
+++ b/src/libsystemd/include/systemd/sd-id128.h
@@ -100,11 +100,11 @@ int sd_id128_get_boot(sd_id128_t *ret);
((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \
0 })
-_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
+_sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) {
return memcmp(&a, &b, 16) == 0;
}
-_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) {
+_sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) {
return a.qwords[0] == 0 && a.qwords[1] == 0;
}
diff --git a/src/libsystemd/include/systemd/sd-ipv4acd.h b/src/libsystemd/include/systemd/sd-ipv4acd.h
index 0fb52b33f9..93db7a4a6c 100644
--- a/src/libsystemd/include/systemd/sd-ipv4acd.h
+++ b/src/libsystemd/include/systemd/sd-ipv4acd.h
@@ -37,12 +37,12 @@ enum {
};
typedef struct sd_ipv4acd sd_ipv4acd;
-typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata);
+typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *ll, int event, void *userdata);
int sd_ipv4acd_detach_event(sd_ipv4acd *ll);
-int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority);
+int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int64_t priority);
int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address);
-int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata);
+int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_callback_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);
diff --git a/src/libsystemd/include/systemd/sd-ipv4ll.h b/src/libsystemd/include/systemd/sd-ipv4ll.h
index 2d1d51a473..9167623167 100644
--- a/src/libsystemd/include/systemd/sd-ipv4ll.h
+++ b/src/libsystemd/include/systemd/sd-ipv4ll.h
@@ -36,12 +36,12 @@ enum {
};
typedef struct sd_ipv4ll sd_ipv4ll;
-typedef void (*sd_ipv4ll_cb_t)(sd_ipv4ll *ll, int event, void *userdata);
+typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata);
int sd_ipv4ll_detach_event(sd_ipv4ll *ll);
-int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority);
+int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority);
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_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_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);
diff --git a/src/libsystemd/include/systemd/sd-journal.h b/src/libsystemd/include/systemd/sd-journal.h
index 559a8fa929..3e61feb81f 100644
--- a/src/libsystemd/include/systemd/sd-journal.h
+++ b/src/libsystemd/include/systemd/sd-journal.h
@@ -67,12 +67,13 @@ typedef struct sd_journal sd_journal;
/* Open flags */
enum {
- SD_JOURNAL_LOCAL_ONLY = 1,
- SD_JOURNAL_RUNTIME_ONLY = 2,
- SD_JOURNAL_SYSTEM = 4,
- SD_JOURNAL_CURRENT_USER = 8,
+ SD_JOURNAL_LOCAL_ONLY = 1 << 0,
+ SD_JOURNAL_RUNTIME_ONLY = 1 << 1,
+ SD_JOURNAL_SYSTEM = 1 << 2,
+ SD_JOURNAL_CURRENT_USER = 1 << 3,
+ SD_JOURNAL_OS_ROOT = 1 << 4,
- SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM, /* deprecated name */
+ SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM /* deprecated name */
};
/* Wakeup event types */
@@ -84,8 +85,10 @@ enum {
int sd_journal_open(sd_journal **ret, int flags);
int sd_journal_open_directory(sd_journal **ret, const char *path, int flags);
+int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags);
int sd_journal_open_files(sd_journal **ret, const char **paths, int flags);
-int sd_journal_open_container(sd_journal **ret, const char *machine, int flags);
+int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags);
+int sd_journal_open_container(sd_journal **ret, const char *machine, int flags); /* deprecated */
void sd_journal_close(sd_journal *j);
int sd_journal_previous(sd_journal *j);
diff --git a/src/libsystemd/include/systemd/sd-lldp.h b/src/libsystemd/include/systemd/sd-lldp.h
index 45d8a36697..391e7c2a2e 100644
--- a/src/libsystemd/include/systemd/sd-lldp.h
+++ b/src/libsystemd/include/systemd/sd-lldp.h
@@ -30,57 +30,147 @@
_SD_BEGIN_DECLARATIONS;
+typedef struct sd_lldp sd_lldp;
+typedef struct sd_lldp_neighbor sd_lldp_neighbor;
+
+/* IEEE 802.3AB Clause 9: TLV Types */
enum {
- SD_LLDP_EVENT_UPDATE_INFO = 0,
+ SD_LLDP_TYPE_END = 0,
+ SD_LLDP_TYPE_CHASSIS_ID = 1,
+ SD_LLDP_TYPE_PORT_ID = 2,
+ SD_LLDP_TYPE_TTL = 3,
+ SD_LLDP_TYPE_PORT_DESCRIPTION = 4,
+ SD_LLDP_TYPE_SYSTEM_NAME = 5,
+ SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6,
+ SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7,
+ SD_LLDP_TYPE_MGMT_ADDRESS = 8,
+ SD_LLDP_TYPE_PRIVATE = 127,
};
+/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */
enum {
- SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE,
- SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE,
- SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE,
+ SD_LLDP_CHASSIS_SUBTYPE_RESERVED = 0,
+ SD_LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1,
+ SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2,
+ SD_LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3,
+ SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4,
+ SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5,
+ SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6,
+ SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7,
};
-typedef struct sd_lldp sd_lldp;
-typedef struct sd_lldp_packet sd_lldp_packet;
+/* IEEE 802.3AB Clause 9.5.3: Port subtype */
+enum {
+ SD_LLDP_PORT_SUBTYPE_RESERVED = 0,
+ SD_LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1,
+ SD_LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2,
+ SD_LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3,
+ SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4,
+ SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5,
+ SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6,
+ SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7,
+};
-typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata);
+enum {
+ SD_LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0,
+ SD_LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1,
+ SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2,
+ SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3,
+ SD_LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4,
+ SD_LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5,
+ SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6,
+ SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7,
+ SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8,
+ SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9,
+ SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10,
+};
-int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret);
-sd_lldp* sd_lldp_unref(sd_lldp *lldp);
+#define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1)
-int sd_lldp_start(sd_lldp *lldp);
-int sd_lldp_stop(sd_lldp *lldp);
+#define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \
+ ((uint16_t) \
+ (SD_LLDP_SYSTEM_CAPABILITIES_REPEATER| \
+ SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE| \
+ SD_LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \
+ SD_LLDP_SYSTEM_CAPABILITIES_ROUTER| \
+ SD_LLDP_SYSTEM_CAPABILITIES_DOCSIS| \
+ SD_LLDP_SYSTEM_CAPABILITIES_CVLAN| \
+ SD_LLDP_SYSTEM_CAPABILITIES_SVLAN| \
+ SD_LLDP_SYSTEM_CAPABILITIES_TPMR))
-int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority);
-int sd_lldp_detach_event(sd_lldp *lldp);
+#define SD_LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 }
+#define SD_LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f }
-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);
+enum {
+ SD_LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1,
+ SD_LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2,
+ SD_LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3,
+ SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4,
+ SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5,
+ SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6,
+ SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7,
+};
-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);
+typedef enum sd_lldp_event {
+ SD_LLDP_EVENT_ADDED = 'a',
+ SD_LLDP_EVENT_REMOVED = 'r',
+ SD_LLDP_EVENT_UPDATED = 'u',
+ SD_LLDP_EVENT_REFRESHED = 'f',
+} sd_lldp_event;
-/* 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);
+typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata);
-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_new(sd_lldp **ret, int ifindex);
+sd_lldp* sd_lldp_unref(sd_lldp *lldp);
-int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest);
+int sd_lldp_start(sd_lldp *lldp);
+int sd_lldp_stop(sd_lldp *lldp);
+
+int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority);
+int sd_lldp_detach_event(sd_lldp *lldp);
-int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs);
+int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata);
+
+/* Controls how much and what to store in the neighbors database */
+int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n);
+int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask);
+int sd_lldp_set_filter_address(sd_lldp *lldp, const struct ether_addr *address);
+
+int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors);
+
+int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size);
+sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n);
+sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n);
+
+/* Access to LLDP frame metadata */
+int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address);
+int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address);
+int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
+
+/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */
+int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
+int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret);
+int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size);
+int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret);
+int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret);
+int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret);
+int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret);
+int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret);
+int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
+int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret);
+
+/* Low-level, iterative TLV access. This is for evertyhing else, it iteratively goes through all available TLVs
+ * (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */
+int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n);
+int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n);
+int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type);
+int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type);
+int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype);
+int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype);
+int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref);
-_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref);
+_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref);
_SD_END_DECLARATIONS;
diff --git a/src/libsystemd/include/systemd/sd-login.h b/src/libsystemd/include/systemd/sd-login.h
index 3c10ff032f..e3ecbd8378 100644
--- a/src/libsystemd/include/systemd/sd-login.h
+++ b/src/libsystemd/include/systemd/sd-login.h
@@ -108,7 +108,7 @@ int sd_peer_get_slice(int fd, char **slice);
int sd_peer_get_user_slice(int fd, char **slice);
/* Similar to sd_pid_get_machine_name(), but retrieves data about the
- * peer of a a connected AF_UNIX socket */
+ * peer of a connected AF_UNIX socket */
int sd_peer_get_machine_name(int fd, char **machine);
/* Similar to sd_pid_get_cgroup(), but retrieves data about the peer
diff --git a/src/libsystemd/include/systemd/sd-messages.h b/src/libsystemd/include/systemd/sd-messages.h
index 1aeac17851..1865e0492f 100644
--- a/src/libsystemd/include/systemd/sd-messages.h
+++ b/src/libsystemd/include/systemd/sd-messages.h
@@ -82,8 +82,6 @@ _SD_BEGIN_DECLARATIONS;
#define SD_MESSAGE_INVALID_CONFIGURATION SD_ID128_MAKE(c7,72,d2,4e,9a,88,4c,be,b9,ea,12,62,5c,30,6c,01)
-#define SD_MESSAGE_BOOTCHART SD_ID128_MAKE(9f,26,aa,56,2c,f4,40,c2,b1,6c,77,3d,04,79,b5,18)
-
#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d)
#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65)
#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
diff --git a/src/libsystemd/include/systemd/sd-ndisc.h b/src/libsystemd/include/systemd/sd-ndisc.h
index 734701bca3..c77a435d17 100644
--- a/src/libsystemd/include/systemd/sd-ndisc.h
+++ b/src/libsystemd/include/systemd/sd-ndisc.h
@@ -52,7 +52,7 @@ int sd_ndisc_set_callback(sd_ndisc *nd,
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_attach_event(sd_ndisc *nd, sd_event *event, int64_t priority);
int sd_ndisc_detach_event(sd_ndisc *nd);
sd_event *sd_ndisc_get_event(sd_ndisc *nd);
diff --git a/src/libsystemd/include/systemd/sd-netlink.h b/src/libsystemd/include/systemd/sd-netlink.h
index 333df4676f..c4cefe4e30 100644
--- a/src/libsystemd/include/systemd/sd-netlink.h
+++ b/src/libsystemd/include/systemd/sd-netlink.h
@@ -64,7 +64,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout);
int sd_netlink_add_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
int sd_netlink_remove_match(sd_netlink *nl, uint16_t match, sd_netlink_message_handler_t c, void *userdata);
-int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int priority);
+int sd_netlink_attach_event(sd_netlink *nl, sd_event *e, int64_t priority);
int sd_netlink_detach_event(sd_netlink *nl);
int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data);
@@ -131,14 +131,16 @@ int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type);
int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family);
int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex);
int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags);
-int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type);
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type);
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen);
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope);
int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags);
+int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table);
int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags);
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family);
+int sd_rtnl_message_route_set_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);
diff --git a/src/libsystemd/include/systemd/sd-network.h b/src/libsystemd/include/systemd/sd-network.h
index e20d12c44d..0f13e2bae7 100644
--- a/src/libsystemd/include/systemd/sd-network.h
+++ b/src/libsystemd/include/systemd/sd-network.h
@@ -99,11 +99,11 @@ int sd_network_link_get_network_file(int ifindex, char **filename);
/* Get DNS entries for a given link. These are string representations of
* IP addresses */
-int sd_network_link_get_dns(int ifindex, char ***addr);
+int sd_network_link_get_dns(int ifindex, char ***ret);
/* Get NTP entries for a given link. These are domain names or string
* representations of IP addresses */
-int sd_network_link_get_ntp(int ifindex, char ***addr);
+int sd_network_link_get_ntp(int ifindex, char ***ret);
/* Indicates whether or not LLMNR should be enabled for the link
* Possible levels of support: yes, no, resolve
@@ -133,19 +133,17 @@ int sd_network_link_get_dnssec(int ifindex, char **dnssec);
*/
int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta);
-int sd_network_link_get_lldp(int ifindex, char **lldp);
-
/* Get the search DNS domain names for a given link. */
int sd_network_link_get_search_domains(int ifindex, char ***domains);
/* Get the route DNS domain names for a given link. */
int sd_network_link_get_route_domains(int ifindex, char ***domains);
-/* Get the CARRIERS to which current link is bound to. */
-int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers);
+/* Get the carrier interface indexes to which current link is bound to. */
+int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes);
/* Get the CARRIERS that are bound to current link. */
-int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers);
+int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes);
/* Get the timezone that was learnt on a specific link. */
int sd_network_link_get_timezone(int ifindex, char **timezone);
diff --git a/src/libsystemd/include/systemd/sd-resolve.h b/src/libsystemd/include/systemd/sd-resolve.h
index 9c3b0ee70f..fe3b910671 100644
--- a/src/libsystemd/include/systemd/sd-resolve.h
+++ b/src/libsystemd/include/systemd/sd-resolve.h
@@ -79,7 +79,7 @@ int sd_resolve_wait(sd_resolve *resolve, uint64_t timeout_usec);
int sd_resolve_get_tid(sd_resolve *resolve, pid_t *tid);
-int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int priority);
+int sd_resolve_attach_event(sd_resolve *resolve, sd_event *e, int64_t priority);
int sd_resolve_detach_event(sd_resolve *resolve);
sd_event *sd_resolve_get_event(sd_resolve *resolve);
diff --git a/src/libsystemd/libsystemd-internal/Makefile b/src/libsystemd/libsystemd-internal/Makefile
index fca4d7f146..6bf0488bf5 100644
--- a/src/libsystemd/libsystemd-internal/Makefile
+++ b/src/libsystemd/libsystemd-internal/Makefile
@@ -196,12 +196,6 @@ test_bus_match_SOURCES = \
test_bus_match_LDADD = \
libshared.la
-test_bus_proxy_SOURCES = \
- src/libsystemd/sd-bus/test-bus-proxy.c
-
-test_bus_proxy_LDADD = \
- libshared.la
-
test_bus_kernel_SOURCES = \
src/libsystemd/sd-bus/test-bus-kernel.c
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.c
index 2d8ca47987..a19e98e94b 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.c
@@ -38,6 +38,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, ESHUTDOWN),
+ SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_GENERATED, EADDRNOTAVAIL),
+ SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_LINKED, ELOOP),
SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM),
SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED),
@@ -68,10 +70,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_NO_NAME_SERVERS, ESRCH),
SD_BUS_ERROR_MAP(BUS_ERROR_INVALID_REPLY, EINVAL),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_RR, ENOENT),
- SD_BUS_ERROR_MAP(BUS_ERROR_NO_RESOURCES, ENOMEM),
SD_BUS_ERROR_MAP(BUS_ERROR_CNAME_LOOP, EDEADLK),
SD_BUS_ERROR_MAP(BUS_ERROR_ABORTED, ECANCELED),
- SD_BUS_ERROR_MAP(BUS_ERROR_CONNECTION_FAILURE, ECONNREFUSED),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SERVICE, EUNATCH),
SD_BUS_ERROR_MAP(BUS_ERROR_DNSSEC_FAILED, EHOSTUNREACH),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_TRUST_ANCHOR, EHOSTUNREACH),
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.h b/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.h
index fab8748f46..c8f369cb78 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-common-errors.h
@@ -34,6 +34,8 @@
#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive"
#define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked"
+#define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated"
+#define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked"
#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable"
#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation"
#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
@@ -67,10 +69,8 @@
#define BUS_ERROR_NO_NAME_SERVERS "org.freedesktop.resolve1.NoNameServers"
#define BUS_ERROR_INVALID_REPLY "org.freedesktop.resolve1.InvalidReply"
#define BUS_ERROR_NO_SUCH_RR "org.freedesktop.resolve1.NoSuchRR"
-#define BUS_ERROR_NO_RESOURCES "org.freedesktop.resolve1.NoResources"
#define BUS_ERROR_CNAME_LOOP "org.freedesktop.resolve1.CNameLoop"
#define BUS_ERROR_ABORTED "org.freedesktop.resolve1.Aborted"
-#define BUS_ERROR_CONNECTION_FAILURE "org.freedesktop.resolve1.ConnectionFailure"
#define BUS_ERROR_NO_SUCH_SERVICE "org.freedesktop.resolve1.NoSuchService"
#define BUS_ERROR_DNSSEC_FAILED "org.freedesktop.resolve1.DnssecFailed"
#define BUS_ERROR_NO_TRUST_ANCHOR "org.freedesktop.resolve1.NoTrustAnchor"
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-control.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-control.c
index 9a975baa24..00de530d58 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-control.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-control.c
@@ -678,6 +678,7 @@ int bus_get_name_creds_kdbus(
(mask & (SD_BUS_CREDS_PPID|
SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
@@ -795,6 +796,7 @@ static int bus_get_name_creds_dbus1(
((mask & SD_BUS_CREDS_AUGMENT) &&
(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
@@ -947,6 +949,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **
(mask & (SD_BUS_CREDS_PPID|
SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
@@ -1131,8 +1134,7 @@ static int add_name_change_match(sd_bus *bus,
item->name_change.old_id.id = old_owner_id;
item->name_change.new_id.id = new_owner_id;
- if (name)
- memcpy(item->name_change.name, name, l);
+ memcpy_safe(item->name_change.name, name, l);
/* If the old name is unset or empty, then
* this can match against added names */
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-dump.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-dump.c
index 7c81e7a25d..21a6b20a11 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-dump.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-dump.c
@@ -74,7 +74,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
"%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%"PRIi64,
m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
- m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_normal(),
+ m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", special_glyph(TRIANGULAR_BULLET), ansi_normal(),
ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_normal(),
m->header->endian,
m->header->flags,
@@ -198,7 +198,7 @@ int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
else if (type == SD_BUS_TYPE_DICT_ENTRY)
fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
- level ++;
+ level++;
continue;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-kernel.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-kernel.c
index 0896eeb177..59398b841d 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-kernel.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-kernel.c
@@ -1693,50 +1693,6 @@ int bus_kernel_open_bus_fd(const char *bus, char **path) {
return fd;
}
-int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **ep_path) {
- _cleanup_free_ char *path = NULL;
- struct kdbus_cmd *make;
- struct kdbus_item *n;
- const char *name;
- int fd;
-
- fd = bus_kernel_open_bus_fd(bus_name, &path);
- if (fd < 0)
- return fd;
-
- make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd, items)) +
- ALIGN8(offsetof(struct kdbus_item, str) + DECIMAL_STR_MAX(uid_t) + 1 + strlen(ep_name) + 1),
- 8);
- make->size = ALIGN8(offsetof(struct kdbus_cmd, items));
- make->flags = KDBUS_MAKE_ACCESS_WORLD;
-
- n = make->items;
- sprintf(n->str, UID_FMT "-%s", getuid(), ep_name);
- n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
- n->type = KDBUS_ITEM_MAKE_NAME;
- make->size += ALIGN8(n->size);
- name = n->str;
-
- if (ioctl(fd, KDBUS_CMD_ENDPOINT_MAKE, make) < 0) {
- safe_close(fd);
- return -errno;
- }
-
- if (ep_path) {
- char *p;
-
- p = strjoin(dirname(path), "/", name, NULL);
- if (!p) {
- safe_close(fd);
- return -ENOMEM;
- }
-
- *ep_path = p;
- }
-
- return fd;
-}
-
int bus_kernel_try_close(sd_bus *bus) {
struct kdbus_cmd byebye = { .size = sizeof(byebye) };
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-message.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-message.c
index 6a9e87c2d8..a9359c1528 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-message.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-message.c
@@ -1131,10 +1131,7 @@ _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) {
assert_return(!m->sealed, -EPERM);
assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
- if (b)
- m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
- else
- m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
+ SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b);
return 0;
}
@@ -1143,10 +1140,7 @@ _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) {
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
- if (b)
- m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
- else
- m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
+ SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b);
return 0;
}
@@ -1155,10 +1149,7 @@ _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
- if (b)
- m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
- else
- m->header->flags &= ~BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
+ SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b);
return 0;
}
@@ -1198,7 +1189,7 @@ struct bus_body_part *message_append_part(sd_bus_message *m) {
part->memfd = -1;
m->body_end = part;
- m->n_body_parts ++;
+ m->n_body_parts++;
return part;
}
@@ -1643,7 +1634,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void
}
if (type == SD_BUS_TYPE_UNIX_FD)
- m->n_fds ++;
+ m->n_fds++;
if (c->enclosing != SD_BUS_TYPE_ARRAY)
c->index++;
@@ -2387,9 +2378,9 @@ int bus_message_append_ap(
t = types;
if (n_array != (unsigned) -1)
- n_array --;
+ n_array--;
else {
- types ++;
+ types++;
n_struct--;
}
@@ -2631,8 +2622,7 @@ _public_ int sd_bus_message_append_array(
if (r < 0)
return r;
- if (size > 0)
- memcpy(p, ptr, size);
+ memcpy_safe(p, ptr, size);
return 0;
}
@@ -3867,7 +3857,7 @@ static int build_struct_offsets(
if (r < 0)
return r;
if (r == 0 && p[n] != 0) /* except the last item */
- n_variable ++;
+ n_variable++;
n_total++;
p += n;
@@ -4467,9 +4457,9 @@ static int message_read_ap(
t = types;
if (n_array != (unsigned) -1)
- n_array --;
+ n_array--;
else {
- types ++;
+ types++;
n_struct--;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-objects.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-objects.c
index 1f285ae8a6..9bd07ffcab 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-objects.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-objects.c
@@ -145,7 +145,7 @@ static int add_enumerated_to_set(
continue;
}
- if (!object_path_is_valid(*k)){
+ if (!object_path_is_valid(*k)) {
free(*k);
r = -EINVAL;
continue;
@@ -337,7 +337,7 @@ static int check_access(sd_bus *bus, sd_bus_message *m, struct vtable_member *c,
if (cap == 0)
cap = CAP_SYS_ADMIN;
else
- cap --;
+ cap--;
r = sd_bus_query_sender_privilege(m, cap);
if (r < 0)
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-slot.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-slot.c
index b1783cd4a9..75c1692bf5 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-slot.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-slot.c
@@ -206,7 +206,7 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
assert(slot->n_ref > 0);
if (slot->n_ref > 1) {
- slot->n_ref --;
+ slot->n_ref--;
return NULL;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-socket.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-socket.c
index a0008190c5..1486d7cd55 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-socket.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-socket.c
@@ -60,7 +60,7 @@ static void iovec_advance(struct iovec iov[], unsigned *idx, size_t size) {
i->iov_base = NULL;
i->iov_len = 0;
- (*idx) ++;
+ (*idx)++;
}
}
@@ -350,7 +350,7 @@ static int bus_socket_auth_write(sd_bus *b, const char *t) {
if (!p)
return -ENOMEM;
- memcpy(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len);
+ memcpy_safe(p, b->auth_iovec[0].iov_base, b->auth_iovec[0].iov_len);
memcpy(p + b->auth_iovec[0].iov_len, t, l);
b->auth_iovec[0].iov_base = p;
@@ -787,7 +787,7 @@ int bus_socket_write_message(sd_bus *bus, sd_bus_message *m, size_t *idx) {
n = m->n_iovec * sizeof(struct iovec);
iov = alloca(n);
- memcpy(iov, m->iovec, n);
+ memcpy_safe(iov, m->iovec, n);
j = 0;
iovec_advance(iov, &j, *idx);
@@ -998,7 +998,7 @@ int bus_socket_read_message(sd_bus *bus) {
return -ENOMEM;
}
- memcpy(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int));
+ memcpy_safe(f + bus->n_fds, CMSG_DATA(cmsg), n * sizeof(int));
bus->fds = f;
bus->n_fds += n;
} else
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/bus-track.c b/src/libsystemd/libsystemd-internal/sd-bus/bus-track.c
index 5d08b0a37b..81e6d22816 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/bus-track.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/bus-track.c
@@ -129,7 +129,7 @@ _public_ sd_bus_track* sd_bus_track_unref(sd_bus_track *track) {
assert(track->n_ref > 0);
if (track->n_ref > 1) {
- track->n_ref --;
+ track->n_ref--;
return NULL;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/sd-bus.c b/src/libsystemd/libsystemd-internal/sd-bus/sd-bus.c
index 850949fa25..d3c194e135 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/sd-bus.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/sd-bus.c
@@ -313,10 +313,7 @@ _public_ int sd_bus_negotiate_creds(sd_bus *bus, int b, uint64_t mask) {
assert_return(!IN_SET(bus->state, BUS_CLOSING, BUS_CLOSED), -EPERM);
assert_return(!bus_pid_changed(bus), -ECHILD);
- if (b)
- bus->creds_mask |= mask;
- else
- bus->creds_mask &= ~mask;
+ SET_FLAG(bus->creds_mask, mask, b);
/* The well knowns we need unconditionally, so that matches can work */
bus->creds_mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME;
@@ -530,7 +527,7 @@ static void skip_address_key(const char **p) {
*p += strcspn(*p, ",");
if (**p == ',')
- (*p) ++;
+ (*p)++;
}
static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
@@ -695,7 +692,7 @@ static int parse_exec_address(sd_bus *b, const char **p, char **guid) {
goto fail;
}
- (*p) ++;
+ (*p)++;
if (ul >= n_argv) {
if (!GREEDY_REALLOC0(argv, allocated, ul + 2)) {
@@ -839,7 +836,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid)
b->sockaddr.un.sun_family = AF_UNIX;
strncpy(b->sockaddr.un.sun_path, "/var/run/dbus/system_bus_socket", sizeof(b->sockaddr.un.sun_path));
- b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen("/var/run/dbus/system_bus_socket");
+ b->sockaddr_size = SOCKADDR_UN_LEN(b->sockaddr.un);
return 0;
}
@@ -1668,7 +1665,7 @@ static int dispatch_wqueue(sd_bus *bus) {
* it got full, then all bets are off
* anyway. */
- bus->wqueue_size --;
+ bus->wqueue_size--;
sd_bus_message_unref(bus->wqueue[0]);
memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
bus->windex = 0;
@@ -1717,7 +1714,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
/* Dispatch a queued message */
*m = bus->rqueue[0];
- bus->rqueue_size --;
+ bus->rqueue_size--;
memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
return 1;
}
@@ -1781,7 +1778,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
r = bus_write_message(bus, m, hint_sync_call, &idx);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
return -ECONNRESET;
}
@@ -1809,7 +1806,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1))
return -ENOMEM;
- bus->wqueue[bus->wqueue_size ++] = sd_bus_message_ref(m);
+ bus->wqueue[bus->wqueue_size++] = sd_bus_message_ref(m);
}
finish:
@@ -2086,7 +2083,7 @@ _public_ int sd_bus_call(
r = bus_read_message(bus, false, 0);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = -ECONNRESET;
}
@@ -2119,7 +2116,7 @@ _public_ int sd_bus_call(
r = dispatch_wqueue(bus);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = -ECONNRESET;
}
@@ -2257,7 +2254,7 @@ static int process_timeout(sd_bus *bus) {
slot = container_of(c, sd_bus_slot, reply_callback);
- bus->iteration_counter ++;
+ bus->iteration_counter++;
bus->current_message = m;
bus->current_slot = sd_bus_slot_ref(slot);
@@ -2769,7 +2766,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
case BUS_OPENING:
r = bus_socket_process_opening(bus);
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = 1;
} else if (r < 0)
@@ -2780,7 +2777,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
case BUS_AUTHENTICATING:
r = bus_socket_process_authenticating(bus);
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = 1;
} else if (r < 0)
@@ -2794,7 +2791,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
case BUS_RUNNING:
case BUS_HELLO:
r = process_running(bus, hint_priority, priority, ret);
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
r = 1;
@@ -2917,7 +2914,7 @@ _public_ int sd_bus_flush(sd_bus *bus) {
for (;;) {
r = dispatch_wqueue(bus);
if (r < 0) {
- if (r == -ENOTCONN || r == -ECONNRESET || r == -EPIPE || r == -ESHUTDOWN) {
+ if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
bus_enter_closing(bus);
return -ECONNRESET;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/test-bus-error.c b/src/libsystemd/libsystemd-internal/sd-bus/test-bus-error.c
index b9ceda7a8b..bce3cc31c9 100644
--- a/src/libsystemd/libsystemd-internal/sd-bus/test-bus-error.c
+++ b/src/libsystemd/libsystemd-internal/sd-bus/test-bus-error.c
@@ -146,7 +146,7 @@ static void dump_mapping_table(void) {
}
printf("%s -> %i/%s\n", strna(m->name), m->code, strna(errno_to_name(m->code)));
- m ++;
+ m++;
}
printf("---------------------------\n");
}
diff --git a/src/libsystemd/libsystemd-internal/sd-bus/test-bus-proxy.c b/src/libsystemd/libsystemd-internal/sd-bus/test-bus-proxy.c
deleted file mode 100644
index a9fe44e66c..0000000000
--- a/src/libsystemd/libsystemd-internal/sd-bus/test-bus-proxy.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2015 David Herrmann <dh.herrmann@gmail.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-
-#include <systemd/sd-bus.h>
-
-#include "alloc-util.h"
-#include "bus-dump.h"
-#include "bus-kernel.h"
-#include "bus-util.h"
-#include "log.h"
-#include "util.h"
-
-typedef struct {
- const char *sender;
- int matched_acquired;
-} TestProxyMatch;
-
-static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- TestProxyMatch *match = userdata;
- const char *name;
- int r;
-
- r = sd_bus_message_read(m, "s", &name);
- assert_se(r >= 0);
-
- if (!streq_ptr(match->sender, name))
- return 0;
-
- ++match->matched_acquired;
- return 1;
-}
-
-static void test_proxy_matched(void) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *a = NULL;
- _cleanup_free_ char *matchstr = NULL;
- TestProxyMatch match = {};
- const char *me;
- int r;
-
- /* open bus 'a' */
-
- r = sd_bus_new(&a);
- assert_se(r >= 0);
-
- r = sd_bus_set_address(a, "unix:path=/var/run/dbus/system_bus_socket");
- assert_se(r >= 0);
-
- r = sd_bus_set_bus_client(a, true);
- assert_se(r >= 0);
-
- r = sd_bus_start(a);
- assert_se(r >= 0);
-
- r = sd_bus_get_unique_name(a, &me);
- assert_se(r >= 0);
-
- matchstr = strjoin("type='signal',"
- "member='NameAcquired',"
- "destination='",
- me,
- "'",
- NULL);
- assert_se(matchstr);
- r = sd_bus_add_match(a, NULL, matchstr, test_proxy_acquired, &match);
- assert_se(r >= 0);
-
- r = sd_bus_get_unique_name(a, &match.sender);
- assert_se(r >= 0);
-
- /* barrier to guarantee proxy/dbus-daemon handled the previous data */
- r = sd_bus_call_method(a,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "GetId",
- NULL, NULL, NULL);
- assert_se(r >= 0);
-
- /* now we can be sure the Name* signals were sent */
- do {
- r = sd_bus_process(a, NULL);
- } while (r > 0);
- assert_se(r == 0);
-
- assert_se(match.matched_acquired == 1);
-}
-
-int main(int argc, char **argv) {
- if (access("/var/run/dbus/system_bus_socket", F_OK) < 0)
- return EXIT_TEST_SKIP;
-
- log_parse_environment();
-
- test_proxy_matched();
-
- return EXIT_SUCCESS;
-}
diff --git a/src/libsystemd/libsystemd-internal/sd-daemon/sd-daemon.c b/src/libsystemd/libsystemd-internal/sd-daemon/sd-daemon.c
index 7c79a938b9..fa92199c43 100644
--- a/src/libsystemd/libsystemd-internal/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/libsystemd-internal/sd-daemon/sd-daemon.c
@@ -458,14 +458,12 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char
if (sockaddr.un.sun_path[0] == '@')
sockaddr.un.sun_path[0] = 0;
- msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
- if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
- msghdr.msg_namelen = sizeof(struct sockaddr_un);
+ msghdr.msg_namelen = SOCKADDR_UN_LEN(sockaddr.un);
have_pid = pid != 0 && pid != getpid();
if (n_fds > 0 || have_pid) {
- /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */
+ /* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
msghdr.msg_controllen =
(n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
(have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0);
diff --git a/src/libsystemd/libsystemd-internal/sd-device/device-internal.h b/src/libsystemd/libsystemd-internal/sd-device/device-internal.h
index b96441de56..ab222e27de 100644
--- a/src/libsystemd/libsystemd-internal/sd-device/device-internal.h
+++ b/src/libsystemd/libsystemd-internal/sd-device/device-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "hashmap.h"
#include "set.h"
diff --git a/src/libsystemd/libsystemd-internal/sd-device/device-private.c b/src/libsystemd/libsystemd-internal/sd-device/device-private.c
index bf7d3c6f9f..51cabcb048 100644
--- a/src/libsystemd/libsystemd-internal/sd-device/device-private.c
+++ b/src/libsystemd/libsystemd-internal/sd-device/device-private.c
@@ -890,7 +890,7 @@ void device_cleanup_tags(sd_device *device) {
set_free_free(device->tags);
device->tags = NULL;
device->property_tags_outdated = true;
- device->tags_generation ++;
+ device->tags_generation++;
}
void device_cleanup_devlinks(sd_device *device) {
@@ -899,7 +899,7 @@ void device_cleanup_devlinks(sd_device *device) {
set_free_free(device->devlinks);
device->devlinks = NULL;
device->property_devlinks_outdated = true;
- device->devlinks_generation ++;
+ device->devlinks_generation++;
}
void device_remove_tag(sd_device *device, const char *tag) {
@@ -908,7 +908,7 @@ void device_remove_tag(sd_device *device, const char *tag) {
free(set_remove(device->tags, tag));
device->property_tags_outdated = true;
- device->tags_generation ++;
+ device->tags_generation++;
}
static int device_tag(sd_device *device, const char *tag, bool add) {
diff --git a/src/libsystemd/libsystemd-internal/sd-device/sd-device.c b/src/libsystemd/libsystemd-internal/sd-device/sd-device.c
index 895002499c..d21a67cd4c 100644
--- a/src/libsystemd/libsystemd-internal/sd-device/sd-device.c
+++ b/src/libsystemd/libsystemd-internal/sd-device/sd-device.c
@@ -136,7 +136,7 @@ int device_add_property_aux(sd_device *device, const char *_key, const char *_va
}
if (!db) {
- device->properties_generation ++;
+ device->properties_generation++;
device->properties_buf_outdated = true;
}
@@ -309,7 +309,7 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s
if (name[len] == '/')
name[len] = '!';
- len ++;
+ len++;
}
syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name);
@@ -669,7 +669,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) {
return -EINVAL;
sysname[0] = '\0';
- sysname ++;
+ sysname++;
return sd_device_new_from_subsystem_sysname(ret, subsys, sysname);
}
@@ -971,7 +971,7 @@ static int device_set_sysname(sd_device *device) {
pos = strrchr(device->devpath, '/');
if (!pos)
return -EINVAL;
- pos ++;
+ pos++;
/* devpath is not a root directory */
if (*pos == '\0' || pos <= device->devpath)
@@ -986,7 +986,7 @@ static int device_set_sysname(sd_device *device) {
if (sysname[len] == '!')
sysname[len] = '/';
- len ++;
+ len++;
}
/* trailing number */
@@ -1066,7 +1066,7 @@ int device_add_tag(sd_device *device, const char *tag) {
if (r < 0)
return r;
- device->tags_generation ++;
+ device->tags_generation++;
device->property_tags_outdated = true;
return 0;
@@ -1086,7 +1086,7 @@ int device_add_devlink(sd_device *device, const char *devlink) {
if (r < 0)
return r;
- device->devlinks_generation ++;
+ device->devlinks_generation++;
device->property_devlinks_outdated = true;
return 0;
@@ -1212,19 +1212,19 @@ int device_get_id_filename(sd_device *device, const char **ret) {
if (major(devnum) > 0) {
assert(subsystem);
- /* use dev_t -- b259:131072, c254:0 */
+ /* use dev_t — b259:131072, c254:0 */
r = asprintf(&id, "%c%u:%u",
streq(subsystem, "block") ? 'b' : 'c',
major(devnum), minor(devnum));
if (r < 0)
return -ENOMEM;
} else if (ifindex > 0) {
- /* use netdev ifindex -- n3 */
+ /* use netdev ifindex — n3 */
r = asprintf(&id, "n%u", ifindex);
if (r < 0)
return -ENOMEM;
} else {
- /* use $subsys:$sysname -- pci:0000:00:1f.2
+ /* use $subsys:$sysname — pci:0000:00:1f.2
* sysname() has '!' translated, get it from devpath
*/
const char *sysname;
@@ -1397,7 +1397,7 @@ _public_ const char *sd_device_get_tag_first(sd_device *device) {
device->tags_iterator_generation = device->tags_generation;
device->tags_iterator = ITERATOR_FIRST;
- set_iterate(device->tags, &device->tags_iterator, &v);
+ (void) set_iterate(device->tags, &device->tags_iterator, &v);
return v;
}
@@ -1411,7 +1411,7 @@ _public_ const char *sd_device_get_tag_next(sd_device *device) {
if (device->tags_iterator_generation != device->tags_generation)
return NULL;
- set_iterate(device->tags, &device->tags_iterator, &v);
+ (void) set_iterate(device->tags, &device->tags_iterator, &v);
return v;
}
@@ -1425,7 +1425,7 @@ _public_ const char *sd_device_get_devlink_first(sd_device *device) {
device->devlinks_iterator_generation = device->devlinks_generation;
device->devlinks_iterator = ITERATOR_FIRST;
- set_iterate(device->devlinks, &device->devlinks_iterator, &v);
+ (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
return v;
}
@@ -1439,7 +1439,7 @@ _public_ const char *sd_device_get_devlink_next(sd_device *device) {
if (device->devlinks_iterator_generation != device->devlinks_generation)
return NULL;
- set_iterate(device->devlinks, &device->devlinks_iterator, &v);
+ (void) set_iterate(device->devlinks, &device->devlinks_iterator, &v);
return v;
}
@@ -1457,15 +1457,20 @@ static int device_properties_prepare(sd_device *device) {
return r;
if (device->property_devlinks_outdated) {
- char *devlinks = NULL;
+ _cleanup_free_ char *devlinks = NULL;
+ size_t devlinks_allocated = 0, devlinks_len = 0;
const char *devlink;
- devlink = sd_device_get_devlink_first(device);
- if (devlink)
- devlinks = strdupa(devlink);
+ for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
+ char *e;
- while ((devlink = sd_device_get_devlink_next(device)))
- devlinks = strjoina(devlinks, " ", devlink);
+ if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
+ return -ENOMEM;
+ if (devlinks_len > 0)
+ stpcpy(devlinks + devlinks_len++, " ");
+ e = stpcpy(devlinks + devlinks_len, devlink);
+ devlinks_len = e - devlinks;
+ }
r = device_add_property_internal(device, "DEVLINKS", devlinks);
if (r < 0)
@@ -1475,17 +1480,23 @@ static int device_properties_prepare(sd_device *device) {
}
if (device->property_tags_outdated) {
- char *tags = NULL;
+ _cleanup_free_ char *tags = NULL;
+ size_t tags_allocated = 0, tags_len = 0;
const char *tag;
- tag = sd_device_get_tag_first(device);
- if (tag)
- tags = strjoina(":", tag);
+ if (!GREEDY_REALLOC(tags, tags_allocated, 2))
+ return -ENOMEM;
+ stpcpy(tags, ":");
+ tags_len++;
- while ((tag = sd_device_get_tag_next(device)))
- tags = strjoina(tags, ":", tag);
+ for (tag = sd_device_get_tag_first(device); tag; tag = sd_device_get_tag_next(device)) {
+ char *e;
- tags = strjoina(tags, ":");
+ if (!GREEDY_REALLOC(tags, tags_allocated, tags_len + strlen(tag) + 2))
+ return -ENOMEM;
+ e = stpcpy(stpcpy(tags + tags_len, tag), ":");
+ tags_len = e - tags;
+ }
r = device_add_property_internal(device, "TAGS", tags);
if (r < 0)
@@ -1606,7 +1617,7 @@ _public_ const char *sd_device_get_sysattr_first(sd_device *device) {
device->sysattrs_iterator = ITERATOR_FIRST;
- set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
+ (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
return v;
}
@@ -1618,7 +1629,7 @@ _public_ const char *sd_device_get_sysattr_next(sd_device *device) {
if (!device->sysattrs_read)
return NULL;
- set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
+ (void) set_iterate(device->sysattrs, &device->sysattrs_iterator, &v);
return v;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-event/sd-event.c b/src/libsystemd/libsystemd-internal/sd-event/sd-event.c
index 0fec8d71b2..7f6f485353 100644
--- a/src/libsystemd/libsystemd-internal/sd-event/sd-event.c
+++ b/src/libsystemd/libsystemd-internal/sd-event/sd-event.c
@@ -951,7 +951,7 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t
sd_event_ref(e);
LIST_PREPEND(sources, e->sources, s);
- e->n_sources ++;
+ e->n_sources++;
return s;
}
@@ -1072,6 +1072,10 @@ _public_ int sd_event_add_time(
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) &&
+ !clock_boottime_supported())
+ return -EOPNOTSUPP;
+
if (!callback)
callback = time_exit_callback;
@@ -1145,8 +1149,7 @@ _public_ int sd_event_add_signal(
int r;
assert_return(e, -EINVAL);
- assert_return(sig > 0, -EINVAL);
- assert_return(sig < _NSIG, -EINVAL);
+ assert_return(SIGNAL_VALID(sig), -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
@@ -1235,7 +1238,7 @@ _public_ int sd_event_add_child(
return r;
}
- e->n_enabled_child_sources ++;
+ e->n_enabled_child_sources++;
r = event_make_signal_data(e, SIGCHLD, NULL);
if (r < 0) {
@@ -2200,7 +2203,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) {
if (_unlikely_(n != sizeof(si)))
return -EIO;
- assert(si.ssi_signo < _NSIG);
+ assert(SIGNAL_VALID(si.ssi_signo));
read_one = true;
@@ -2528,7 +2531,8 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
}
dual_timestamp_get(&e->timestamp);
- e->timestamp_boottime = now(CLOCK_BOOTTIME);
+ if (clock_boottime_supported())
+ e->timestamp_boottime = now(CLOCK_BOOTTIME);
for (i = 0; i < m; i++) {
@@ -2762,6 +2766,9 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
CLOCK_BOOTTIME,
CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP);
+ if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported())
+ return -EOPNOTSUPP;
+
if (!dual_timestamp_is_set(&e->timestamp)) {
/* Implicitly fall back to now() if we never ran
* before and thus have no cached time. */
@@ -2780,9 +2787,13 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
*usec = e->timestamp.monotonic;
break;
- default:
+ case CLOCK_BOOTTIME:
+ case CLOCK_BOOTTIME_ALARM:
*usec = e->timestamp_boottime;
break;
+
+ default:
+ assert_not_reached("Unknown clock?");
}
return 0;
diff --git a/src/libsystemd/libsystemd-internal/sd-event/test-event.c b/src/libsystemd/libsystemd-internal/sd-event/test-event.c
index 6beb1b08cd..324ad7ee02 100644
--- a/src/libsystemd/libsystemd-internal/sd-event/test-event.c
+++ b/src/libsystemd/libsystemd-internal/sd-event/test-event.c
@@ -270,8 +270,10 @@ static void test_sd_event_now(void) {
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0);
- assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
- assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
+ if (clock_boottime_supported()) {
+ assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
+ assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
+ }
assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
@@ -280,8 +282,10 @@ static void test_sd_event_now(void) {
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0);
- assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
- assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
+ if (clock_boottime_supported()) {
+ assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
+ assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
+ }
assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
}
@@ -291,7 +295,7 @@ static int n_rtqueue = 0;
static int rtqueue_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
last_rtqueue_sigval = si->ssi_int;
- n_rtqueue ++;
+ n_rtqueue++;
return 0;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-hwdb/hwdb-internal.h b/src/libsystemd/libsystemd-internal/sd-hwdb/hwdb-internal.h
index 13fddfc8ad..8ffb5e5c74 100644
--- a/src/libsystemd/libsystemd-internal/sd-hwdb/hwdb-internal.h
+++ b/src/libsystemd/libsystemd-internal/sd-hwdb/hwdb-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -16,7 +18,6 @@
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
#include "sparse-endian.h"
#include "util.h"
diff --git a/src/libsystemd/libsystemd-internal/sd-netlink/netlink-message.c b/src/libsystemd/libsystemd-internal/sd-netlink/netlink-message.c
index 0c307661f1..c00785ea41 100644
--- a/src/libsystemd/libsystemd-internal/sd-netlink/netlink-message.c
+++ b/src/libsystemd/libsystemd-internal/sd-netlink/netlink-message.c
@@ -34,7 +34,7 @@
#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;
+#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
@@ -107,10 +107,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
m->hdr->nlmsg_type == RTM_GETNEIGH,
-EINVAL);
- if (dump)
- m->hdr->nlmsg_flags |= NLM_F_DUMP;
- else
- m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
+ SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
return 0;
}
@@ -210,11 +207,11 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
* and gives us too little data (so don't do that)
*/
padding = mempcpy(RTA_DATA(rta), data, data_length);
- else {
+
+ else
/* if no data was passed, make sure we still initialize the padding
note that we can have data_length > 0 (used by some containers) */
padding = RTA_DATA(rta);
- }
/* make sure also the padding at the end of the message is initialized */
padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
@@ -346,7 +343,7 @@ int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, c
assert_return(m, -EINVAL);
assert_return(!m->sealed, -EPERM);
- r = add_rtattr(m, type, &data, len);
+ r = add_rtattr(m, type, data, len);
if (r < 0)
return r;
@@ -467,7 +464,7 @@ int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type
if (r < 0)
return r;
- m->containers[m->n_containers ++].offset = r;
+ m->containers[m->n_containers++].offset = r;
return 0;
}
@@ -498,7 +495,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
if (r < 0)
return r;
- m->containers[m->n_containers ++].offset = r;
+ m->containers[m->n_containers++].offset = r;
return 0;
}
@@ -510,7 +507,7 @@ int sd_netlink_message_close_container(sd_netlink_message *m) {
assert_return(m->n_containers > 0, -EINVAL);
m->containers[m->n_containers].type_system = NULL;
- m->n_containers --;
+ m->n_containers--;
return 0;
}
@@ -528,7 +525,7 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t
attribute = &m->containers[m->n_containers].attributes[type];
- if(!attribute->offset)
+ if (!attribute->offset)
return -ENODATA;
rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
@@ -735,7 +732,7 @@ static int netlink_container_parse(sd_netlink_message *m,
_cleanup_free_ struct netlink_attribute *attributes = NULL;
attributes = new0(struct netlink_attribute, count);
- if(!attributes)
+ if (!attributes)
return -ENOMEM;
for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
@@ -842,7 +839,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
else
size = (size_t)r;
- m->n_containers ++;
+ m->n_containers++;
r = netlink_container_parse(m,
&m->containers[m->n_containers],
@@ -850,7 +847,7 @@ int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short typ
container,
size);
if (r < 0) {
- m->n_containers --;
+ m->n_containers--;
return r;
}
@@ -867,7 +864,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m) {
m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
m->containers[m->n_containers].type_system = NULL;
- m->n_containers --;
+ m->n_containers--;
return 0;
}
diff --git a/src/libsystemd/libsystemd-internal/sd-netlink/netlink-socket.c b/src/libsystemd/libsystemd-internal/sd-netlink/netlink-socket.c
index 25b7509217..d28a413c65 100644
--- a/src/libsystemd/libsystemd-internal/sd-netlink/netlink-socket.c
+++ b/src/libsystemd/libsystemd-internal/sd-netlink/netlink-socket.c
@@ -82,7 +82,7 @@ static int broadcast_groups_get(sd_netlink *nl) {
return r;
for (i = 0; i < len; i++) {
- for (j = 0; j < sizeof(uint32_t) * 8; j ++) {
+ for (j = 0; j < sizeof(uint32_t) * 8; j++) {
uint32_t offset;
unsigned group;
@@ -168,7 +168,7 @@ int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
n_ref = broadcast_group_get_ref(nl, group);
- n_ref ++;
+ n_ref++;
r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL);
if (r < 0)
@@ -216,7 +216,7 @@ int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
assert(n_ref > 0);
- n_ref --;
+ n_ref--;
r = broadcast_group_set_ref(nl, group, n_ref);
if (r < 0)
@@ -444,14 +444,14 @@ int socket_read_message(sd_netlink *rtnl) {
if (r < 0)
return r;
- rtnl->rqueue[rtnl->rqueue_size ++] = first;
+ rtnl->rqueue[rtnl->rqueue_size++] = first;
first = NULL;
if (multi_part && (i < rtnl->rqueue_partial_size)) {
/* remove the message form the partial read queue */
memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
sizeof(sd_netlink_message*) * (rtnl->rqueue_partial_size - i - 1));
- rtnl->rqueue_partial_size --;
+ rtnl->rqueue_partial_size--;
}
return 1;
@@ -465,7 +465,7 @@ int socket_read_message(sd_netlink *rtnl) {
if (r < 0)
return r;
- rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
+ rtnl->rqueue_partial[rtnl->rqueue_partial_size++] = first;
}
first = NULL;
diff --git a/src/libsystemd/libsystemd-internal/sd-netlink/netlink-types.c b/src/libsystemd/libsystemd-internal/sd-netlink/netlink-types.c
index a5758bb516..3a4bac2ced 100644
--- a/src/libsystemd/libsystemd-internal/sd-netlink/netlink-types.c
+++ b/src/libsystemd/libsystemd-internal/sd-netlink/netlink-types.c
@@ -95,12 +95,43 @@ static const NLType rtnl_link_info_data_macvlan_types[] = {
};
static const NLType rtnl_link_info_data_bridge_types[] = {
- [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
- [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_VLAN_FILTERING] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_GROUP_FWD_MASK] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_ROOT_PORT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_ROOT_PATH_COST] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_TOPOLOGY_CHANGE] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_TOPOLOGY_CHANGE_DETECTED] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_HELLO_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_TCN_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_TOPOLOGY_CHANGE_TIMER] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_GC_TIMER] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_GROUP_ADDR] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_FDB_FLUSH] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_ROUTER] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_SNOOPING] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_QUERIER] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MCAST_HASH_MAX] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NETLINK_TYPE_U32 },
+ [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NETLINK_TYPE_U16 },
+ [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NETLINK_TYPE_U64 },
+ [IFLA_BR_NF_CALL_IPTABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NETLINK_TYPE_U8 },
+ [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NETLINK_TYPE_U16 },
};
static const NLType rtnl_link_info_data_vlan_types[] = {
diff --git a/src/libsystemd/libsystemd-internal/sd-netlink/rtnl-message.c b/src/libsystemd/libsystemd-internal/sd-netlink/rtnl-message.c
index 2f1254295a..f6482a6157 100644
--- a/src/libsystemd/libsystemd-internal/sd-netlink/rtnl-message.c
+++ b/src/libsystemd/libsystemd-internal/sd-netlink/rtnl-message.c
@@ -111,6 +111,20 @@ int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) {
return 0;
}
+int sd_rtnl_message_route_set_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);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_table = table;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
struct rtmsg *rtm;
@@ -126,6 +140,20 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
return 0;
}
+int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_family = family;
+
+ return 0;
+}
+
int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
struct rtmsg *rtm;
@@ -402,7 +430,6 @@ int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
int r;
assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
- assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
assert_return(ret, -EINVAL);
r = message_new(rtnl, ret, nlmsg_type);
@@ -616,7 +643,7 @@ int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
return 0;
}
-int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
+int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) {
struct ifinfomsg *ifi;
assert_return(m, -EINVAL);
diff --git a/src/libsystemd/libsystemd-internal/sd-netlink/sd-netlink.c b/src/libsystemd/libsystemd-internal/sd-netlink/sd-netlink.c
index c536364a24..3c7488463c 100644
--- a/src/libsystemd/libsystemd-internal/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/libsystemd-internal/sd-netlink/sd-netlink.c
@@ -279,7 +279,7 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) {
/* Dispatch a queued message */
*message = rtnl->rqueue[0];
- rtnl->rqueue_size --;
+ rtnl->rqueue_size--;
memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_netlink_message*) * rtnl->rqueue_size);
return 1;
@@ -774,7 +774,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) {
return 1;
}
-int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) {
+int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) {
int r;
assert_return(rtnl, -EINVAL);
diff --git a/src/libsystemd/libsystemd-internal/sd-netlink/test-netlink.c b/src/libsystemd/libsystemd-internal/sd-netlink/test-netlink.c
index e16c35144d..aadd0f06a8 100644
--- a/src/libsystemd/libsystemd-internal/sd-netlink/test-netlink.c
+++ b/src/libsystemd/libsystemd-internal/sd-netlink/test-netlink.c
@@ -217,7 +217,7 @@ static void test_event_loop(int ifindex) {
assert_se(sd_netlink_open(&rtnl) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, NULL) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, NULL) >= 0);
assert_se(sd_event_default(&event) >= 0);
@@ -234,7 +234,7 @@ static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata)
int *counter = userdata;
int r;
- (*counter) --;
+ (*counter)--;
r = sd_netlink_message_get_errno(m);
@@ -258,7 +258,7 @@ static void test_async(int ifindex) {
assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, ifindex) >= 0);
- assert_se(sd_netlink_call_async(rtnl, m, &link_handler, ifname, 0, &serial) >= 0);
+ assert_se(sd_netlink_call_async(rtnl, m, link_handler, ifname, 0, &serial) >= 0);
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
assert_se(sd_netlink_process(rtnl, &r) >= 0);
@@ -276,11 +276,11 @@ static void test_pipe(int ifindex) {
assert_se(sd_rtnl_message_new_link(rtnl, &m1, RTM_GETLINK, ifindex) >= 0);
assert_se(sd_rtnl_message_new_link(rtnl, &m2, RTM_GETLINK, ifindex) >= 0);
- counter ++;
- assert_se(sd_netlink_call_async(rtnl, m1, &pipe_handler, &counter, 0, NULL) >= 0);
+ counter++;
+ assert_se(sd_netlink_call_async(rtnl, m1, pipe_handler, &counter, 0, NULL) >= 0);
- counter ++;
- assert_se(sd_netlink_call_async(rtnl, m2, &pipe_handler, &counter, 0, NULL) >= 0);
+ counter++;
+ assert_se(sd_netlink_call_async(rtnl, m2, pipe_handler, &counter, 0, NULL) >= 0);
while (counter > 0) {
assert_se(sd_netlink_wait(rtnl, 0) >= 0);
@@ -330,12 +330,12 @@ static void test_match(void) {
assert_se(sd_netlink_open(&rtnl) >= 0);
- assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
- assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, &link_handler, NULL) >= 0);
+ assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
+ assert_se(sd_netlink_add_match(rtnl, RTM_NEWLINK, link_handler, NULL) >= 0);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 1);
- assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, &link_handler, NULL) == 0);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 1);
+ assert_se(sd_netlink_remove_match(rtnl, RTM_NEWLINK, link_handler, NULL) == 0);
assert_se((rtnl = sd_netlink_unref(rtnl)) == NULL);
}
diff --git a/src/libsystemd/libsystemd-internal/sd-network/sd-network.c b/src/libsystemd/libsystemd-internal/sd-network/sd-network.c
index 5ebe7de7af..70083213f9 100644
--- a/src/libsystemd/libsystemd-internal/sd-network/sd-network.c
+++ b/src/libsystemd/libsystemd-internal/sd-network/sd-network.c
@@ -31,6 +31,7 @@
#include "fs-util.h"
#include "macro.h"
#include "parse-util.h"
+#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "util.h"
@@ -102,16 +103,16 @@ _public_ int sd_network_get_route_domains(char ***ret) {
}
static int network_link_get_string(int ifindex, const char *field, char **ret) {
- _cleanup_free_ char *s = NULL, *p = NULL;
+ char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
+ _cleanup_free_ char *s = NULL;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(ret, -EINVAL);
- if (asprintf(&p, "/run/systemd/netif/links/%i", ifindex) < 0)
- return -ENOMEM;
+ xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
- r = parse_env_file(p, NEWLINE, field, &s, NULL);
+ r = parse_env_file(path, NEWLINE, field, &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@@ -126,17 +127,16 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) {
}
static int network_link_get_strv(int ifindex, const char *key, char ***ret) {
- _cleanup_free_ char *p = NULL, *s = NULL;
+ char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
_cleanup_strv_free_ char **a = NULL;
+ _cleanup_free_ char *s = NULL;
int r;
assert_return(ifindex > 0, -EINVAL);
assert_return(ret, -EINVAL);
- if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0)
- return -ENOMEM;
-
- r = parse_env_file(p, NEWLINE, key, &s, NULL);
+ xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
+ r = parse_env_file(path, NEWLINE, key, &s, NULL);
if (r == -ENOENT)
return -ENODATA;
if (r < 0)
@@ -187,32 +187,7 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char
return network_link_get_strv(ifindex, "DNSSEC_NTA", nta);
}
-_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) {
- _cleanup_free_ char *s = NULL, *p = NULL;
- size_t size;
- int r;
-
- assert_return(ifindex > 0, -EINVAL);
- assert_return(lldp, -EINVAL);
-
- if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0)
- return -ENOMEM;
-
- r = read_full_file(p, &s, &size);
- if (r == -ENOENT)
- return -ENODATA;
- if (r < 0)
- return r;
- if (size <= 0)
- return -ENODATA;
-
- *lldp = s;
- s = NULL;
-
- return 0;
-}
-
-int sd_network_link_get_timezone(int ifindex, char **ret) {
+_public_ int sd_network_link_get_timezone(int ifindex, char **ret) {
return network_link_get_string(ifindex, "TIMEZONE", ret);
}
@@ -232,12 +207,64 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) {
return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret);
}
-_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) {
- return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret);
+static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) {
+ char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1];
+ _cleanup_free_ int *ifis = NULL;
+ _cleanup_free_ char *s = NULL;
+ size_t allocated = 0, c = 0;
+ const char *x;
+ int r;
+
+ assert_return(ifindex > 0, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ xsprintf(path, "/run/systemd/netif/links/%i", ifindex);
+ r = parse_env_file(path, NEWLINE, key, &s, NULL);
+ if (r == -ENOENT)
+ return -ENODATA;
+ if (r < 0)
+ return r;
+ if (isempty(s)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ x = s;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&x, &word, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ r = parse_ifindex(word, &ifindex);
+ if (r < 0)
+ return r;
+
+ if (!GREEDY_REALLOC(ifis, allocated, c + 1))
+ return -ENOMEM;
+
+ ifis[c++] = ifindex;
+ }
+
+ if (!GREEDY_REALLOC(ifis, allocated, c + 1))
+ return -ENOMEM;
+ ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/
+
+ *ret = ifis;
+ ifis = NULL;
+
+ return c;
+}
+
+_public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) {
+ return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret);
}
-_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) {
- return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret);
+_public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) {
+ return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret);
}
static inline int MONITOR_TO_FD(sd_network_monitor *m) {
diff --git a/src/libsystemd/libsystemd-internal/sd-path/sd-path.c b/src/libsystemd/libsystemd-internal/sd-path/sd-path.c
index 61a8b092da..6d9f3e2a61 100644
--- a/src/libsystemd/libsystemd-internal/sd-path/sd-path.c
+++ b/src/libsystemd/libsystemd-internal/sd-path/sd-path.c
@@ -89,7 +89,8 @@ static int from_home_dir(const char *envname, const char *suffix, char **buffer,
static int from_user_dir(const char *field, char **buffer, const char **ret) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *b = NULL;
- const char *fn = NULL;
+ _cleanup_free_ const char *fn = NULL;
+ const char *c = NULL;
char line[LINE_MAX];
size_t n;
int r;
@@ -98,10 +99,14 @@ static int from_user_dir(const char *field, char **buffer, const char **ret) {
assert(buffer);
assert(ret);
- r = from_home_dir(NULL, ".config/user-dirs.dirs", &b, &fn);
+ r = from_home_dir("XDG_CONFIG_HOME", ".config", &b, &c);
if (r < 0)
return r;
+ fn = strappend(c, "/user-dirs.dirs");
+ if (!fn)
+ return -ENOMEM;
+
f = fopen(fn, "re");
if (!f) {
if (errno == ENOENT)
diff --git a/src/libsystemd/libsystemd-internal/sd-resolve/sd-resolve.c b/src/libsystemd/libsystemd-internal/sd-resolve/sd-resolve.c
index 30176d7283..6eacf2b69a 100644
--- a/src/libsystemd/libsystemd-internal/sd-resolve/sd-resolve.c
+++ b/src/libsystemd/libsystemd-internal/sd-resolve/sd-resolve.c
@@ -217,9 +217,8 @@ static void *serialize_addrinfo(void *p, const struct addrinfo *ai, size_t *leng
memcpy((uint8_t*) p, &s, sizeof(AddrInfoSerialization));
memcpy((uint8_t*) p + sizeof(AddrInfoSerialization), ai->ai_addr, ai->ai_addrlen);
-
- if (ai->ai_canonname)
- memcpy((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen, ai->ai_canonname, cnl);
+ memcpy_safe((char*) p + sizeof(AddrInfoSerialization) + ai->ai_addrlen,
+ ai->ai_canonname, cnl);
*length += l;
return (uint8_t*) p + l;
@@ -404,7 +403,7 @@ static void* thread_worker(void *p) {
assert_se(pthread_sigmask(SIG_BLOCK, &fullset, NULL) == 0);
/* Assign a pretty name to this thread */
- prctl(PR_SET_NAME, (unsigned long) "sd-resolve");
+ (void) prctl(PR_SET_NAME, (unsigned long) "sd-resolve");
while (!resolve->dead) {
union {
@@ -448,7 +447,7 @@ static int start_threads(sd_resolve *resolve, unsigned extra) {
if (r != 0)
return -r;
- resolve->n_valid_workers ++;
+ resolve->n_valid_workers++;
}
return 0;
@@ -580,9 +579,10 @@ static void resolve_free(sd_resolve *resolve) {
(void) send(resolve->fds[REQUEST_SEND_FD], &req, req.length, MSG_NOSIGNAL);
}
- /* Now terminate them and wait until they are gone. */
+ /* Now terminate them and wait until they are gone.
+ If we get an error than most likely the thread already exited. */
for (i = 0; i < resolve->n_valid_workers; i++)
- pthread_join(resolve->workers[i], NULL);
+ (void) pthread_join(resolve->workers[i], NULL);
/* Close all communication channels */
for (i = 0; i < _FD_MAX; i++)
@@ -658,7 +658,7 @@ static int complete_query(sd_resolve *resolve, sd_resolve_query *q) {
assert(q->resolve == resolve);
q->done = true;
- resolve->n_done ++;
+ resolve->n_done++;
resolve->current = sd_resolve_query_ref(q);
@@ -1192,7 +1192,7 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd
return 1;
}
-_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) {
+_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) {
int r;
assert_return(resolve, -EINVAL);
diff --git a/src/libsystemd/libsystemd-internal/sd-resolve/test-resolve.c b/src/libsystemd/libsystemd-internal/sd-resolve/test-resolve.c
index 9e3ac16597..0209cc77e7 100644
--- a/src/libsystemd/libsystemd-internal/sd-resolve/test-resolve.c
+++ b/src/libsystemd/libsystemd-internal/sd-resolve/test-resolve.c
@@ -63,7 +63,7 @@ static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, c
return 0;
}
- printf("Host: %s -- Serv: %s\n", strna(host), strna(serv));
+ printf("Host: %s — Serv: %s\n", strna(host), strna(serv));
return 0;
}
diff --git a/src/libsystemd/libsystemd-journal-internal/Makefile b/src/libsystemd/libsystemd-journal-internal/Makefile
index 3e54757a9f..964e1b5b4f 100644
--- a/src/libsystemd/libsystemd-journal-internal/Makefile
+++ b/src/libsystemd/libsystemd-journal-internal/Makefile
@@ -60,7 +60,9 @@ libsystemd_journal_internal_la_SOURCES = \
src/journal/mmap-cache.h \
src/journal/compress.c \
src/journal/audit-type.h \
- src/journal/audit-type.c
+ src/journal/audit-type.c \
+ src/shared/gcrypt-util.h \
+ src/shared/gcrypt-util.c
nodist_libsystemd_journal_internal_la_SOURCES = \
src/journal/audit_type-to-name.h
diff --git a/src/libsystemd/libsystemd-journal-internal/catalog.c b/src/libsystemd/libsystemd-journal-internal/catalog.c
index 962ca238b9..70838d958c 100644
--- a/src/libsystemd/libsystemd-journal-internal/catalog.c
+++ b/src/libsystemd/libsystemd-journal-internal/catalog.c
@@ -164,14 +164,14 @@ static int finish_item(
Hashmap *h,
sd_id128_t id,
const char *language,
- char *payload) {
+ char *payload, size_t payload_size) {
_cleanup_free_ CatalogItem *i = NULL;
- _cleanup_free_ char *combined = NULL, *prev = NULL;
- int r;
+ _cleanup_free_ char *prev = NULL, *combined = NULL;
assert(h);
assert(payload);
+ assert(payload_size > 0);
i = new0(CatalogItem, 1);
if (!i)
@@ -184,23 +184,25 @@ static int finish_item(
}
prev = hashmap_get(h, i);
-
- /* Already have such an item, combine them */
if (prev) {
+ /* Already have such an item, combine them */
combined = combine_entries(payload, prev);
if (!combined)
return log_oom();
- r = hashmap_update(h, i, combined);
- if (r < 0)
- return r;
- combined = NULL;
- /* A new item */
+ if (hashmap_update(h, i, combined) < 0)
+ return log_oom();
+ combined = NULL;
} else {
- r = hashmap_put(h, i, payload);
- if (r < 0)
- return r;
+ /* A new item */
+ combined = memdup(payload, payload_size + 1);
+ if (!combined)
+ return log_oom();
+
+ if (hashmap_put(h, i, combined) < 0)
+ return log_oom();
i = NULL;
+ combined = NULL;
}
return 0;
@@ -215,7 +217,7 @@ int catalog_file_lang(const char* filename, char **lang) {
beg = end - 1;
while (beg > filename && *beg != '.' && *beg != '/' && end - beg < 32)
- beg --;
+ beg--;
if (*beg != '.' || end <= beg + 1)
return 0;
@@ -262,6 +264,7 @@ static int catalog_entry_lang(const char* filename, int line,
int catalog_import_file(Hashmap *h, const char *path) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *payload = NULL;
+ size_t payload_size = 0, payload_allocated = 0;
unsigned n = 0;
sd_id128_t id;
_cleanup_free_ char *deflang = NULL, *lang = NULL;
@@ -283,8 +286,7 @@ int catalog_import_file(Hashmap *h, const char *path) {
for (;;) {
char line[LINE_MAX];
- size_t a, b, c;
- char *t;
+ size_t line_len;
if (!fgets(line, sizeof(line), f)) {
if (feof(f))
@@ -323,17 +325,23 @@ int catalog_import_file(Hashmap *h, const char *path) {
if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) {
if (got_id) {
- r = finish_item(h, id, lang ?: deflang, payload);
+ if (payload_size == 0) {
+ log_error("[%s:%u] No payload text.", path, n);
+ return -EINVAL;
+ }
+
+ r = finish_item(h, id, lang ?: deflang, payload, payload_size);
if (r < 0)
return r;
- payload = NULL;
lang = mfree(lang);
+ payload_size = 0;
}
if (with_language) {
- t = strstrip(line + 2 + 1 + 32 + 1);
+ char *t;
+ t = strstrip(line + 2 + 1 + 32 + 1);
r = catalog_entry_lang(path, n, t, deflang, &lang);
if (r < 0)
return r;
@@ -343,9 +351,6 @@ int catalog_import_file(Hashmap *h, const char *path) {
empty_line = false;
id = jd;
- if (payload)
- payload[0] = '\0';
-
continue;
}
}
@@ -356,34 +361,30 @@ int catalog_import_file(Hashmap *h, const char *path) {
return -EINVAL;
}
- a = payload ? strlen(payload) : 0;
- b = strlen(line);
-
- c = a + (empty_line ? 1 : 0) + b + 1 + 1;
- t = realloc(payload, c);
- if (!t)
+ line_len = strlen(line);
+ if (!GREEDY_REALLOC(payload, payload_allocated,
+ payload_size + (empty_line ? 1 : 0) + line_len + 1 + 1))
return log_oom();
- if (empty_line) {
- t[a] = '\n';
- memcpy(t + a + 1, line, b);
- t[a+b+1] = '\n';
- t[a+b+2] = 0;
- } else {
- memcpy(t + a, line, b);
- t[a+b] = '\n';
- t[a+b+1] = 0;
- }
+ if (empty_line)
+ payload[payload_size++] = '\n';
+ memcpy(payload + payload_size, line, line_len);
+ payload_size += line_len;
+ payload[payload_size++] = '\n';
+ payload[payload_size] = '\0';
- payload = t;
empty_line = false;
}
if (got_id) {
- r = finish_item(h, id, lang ?: deflang, payload);
+ if (payload_size == 0) {
+ log_error("[%s:%u] No payload text.", path, n);
+ return -EINVAL;
+ }
+
+ r = finish_item(h, id, lang ?: deflang, payload, payload_size);
if (r < 0)
return r;
- payload = NULL;
}
return 0;
diff --git a/src/libsystemd/libsystemd-journal-internal/compress.c b/src/libsystemd/libsystemd-journal-internal/compress.c
index 1933b87b00..ba734b5561 100644
--- a/src/libsystemd/libsystemd-journal-internal/compress.c
+++ b/src/libsystemd/libsystemd-journal-internal/compress.c
@@ -17,6 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
@@ -111,7 +112,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size,
if (src_size < 9)
return -ENOBUFS;
- r = LZ4_compress_limitedOutput(src, dst + 8, src_size, (int) dst_alloc_size - 8);
+ r = LZ4_compress_limitedOutput(src, (char*)dst + 8, src_size, (int) dst_alloc_size - 8);
if (r <= 0)
return -ENOBUFS;
@@ -175,7 +176,7 @@ int decompress_blob_xz(const void *src, uint64_t src_size,
return -ENOMEM;
s.avail_out = space - used;
- s.next_out = *dst + used;
+ s.next_out = *(uint8_t**)dst + used;
}
*dst_size = space - s.avail_out;
@@ -214,7 +215,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size,
} else
out = *dst;
- r = LZ4_decompress_safe(src + 8, out, src_size - 8, size);
+ r = LZ4_decompress_safe((char*)src + 8, out, src_size - 8, size);
if (r < 0 || r != size)
return -EBADMSG;
@@ -290,7 +291,7 @@ int decompress_startswith_xz(const void *src, uint64_t src_size,
if (!(greedy_realloc(buffer, buffer_size, *buffer_size * 2, 1)))
return -ENOMEM;
- s.next_out = *buffer + *buffer_size - s.avail_out;
+ s.next_out = *(uint8_t**)buffer + *buffer_size - s.avail_out;
}
#else
@@ -323,7 +324,7 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size,
if (!(greedy_realloc(buffer, buffer_size, ALIGN_8(prefix_len + 1), 1)))
return -ENOMEM;
- r = LZ4_decompress_safe_partial(src + 8, *buffer, src_size - 8,
+ r = LZ4_decompress_safe_partial((char*)src + 8, *buffer, src_size - 8,
prefix_len + 1, *buffer_size);
if (r >= 0)
size = (unsigned) r;
@@ -498,7 +499,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) {
total_out += n;
if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) {
- log_debug("Compressed stream longer than %zd bytes", max_bytes);
+ log_debug("Compressed stream longer than %"PRIu64" bytes", max_bytes);
return -EFBIG;
}
@@ -649,7 +650,7 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) {
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);
+ log_debug("Decompressed stream longer than %"PRIu64" bytes", max_bytes);
r = -EFBIG;
goto cleanup;
}
diff --git a/src/libsystemd/libsystemd-journal-internal/fsprg.c b/src/libsystemd/libsystemd-journal-internal/fsprg.c
index 8f7e137e74..612b10f3a9 100644
--- a/src/libsystemd/libsystemd-journal-internal/fsprg.c
+++ b/src/libsystemd/libsystemd-journal-internal/fsprg.c
@@ -30,6 +30,7 @@
#include <string.h>
#include "fsprg.h"
+#include "gcrypt-util.h"
#define ISVALID_SECPAR(secpar) (((secpar) % 16 == 0) && ((secpar) >= 16) && ((secpar) <= 16384))
#define VALIDATE_SECPAR(secpar) assert(ISVALID_SECPAR(secpar));
@@ -57,7 +58,7 @@ static gcry_mpi_t mpi_import(const void *buf, size_t buflen) {
gcry_mpi_t h;
unsigned len;
- gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL);
+ assert_se(gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0);
len = (gcry_mpi_get_nbits(h) + 7) / 8;
assert(len <= buflen);
assert(gcry_mpi_cmp_ui(h, 0) >= 0);
@@ -206,20 +207,6 @@ static void CRT_compose(gcry_mpi_t *x, const gcry_mpi_t xp, const gcry_mpi_t xq,
gcry_mpi_release(u);
}
-static void initialize_libgcrypt(void) {
- const char *p;
- if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
- return;
-
- p = gcry_check_version("1.4.5");
- assert(p);
-
- /* Turn off "secmem". Clients which whish to make use of this
- * feature should initialize the library manually */
- gcry_control(GCRYCTL_DISABLE_SECMEM);
- gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
-}
-
/******************************************************************************/
size_t FSPRG_mskinbytes(unsigned _secpar) {
@@ -259,7 +246,7 @@ void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigne
VALIDATE_SECPAR(_secpar);
secpar = _secpar;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
if (!seed) {
gcry_randomize(iseed, FSPRG_RECOMMENDED_SEEDLEN, GCRY_STRONG_RANDOM);
@@ -295,7 +282,7 @@ void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seed
gcry_mpi_t n, x;
uint16_t secpar;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
secpar = read_secpar(mpk + 0);
n = mpi_import(mpk + 2, secpar / 8);
@@ -314,7 +301,7 @@ void FSPRG_Evolve(void *state) {
uint16_t secpar;
uint64_t epoch;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
secpar = read_secpar(state + 0);
n = mpi_import(state + 2 + 0 * secpar / 8, secpar / 8);
@@ -341,7 +328,7 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed,
gcry_mpi_t p, q, n, x, xp, xq, kp, kq, xm;
uint16_t secpar;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
secpar = read_secpar(msk + 0);
p = mpi_import(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8);
@@ -380,7 +367,7 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed,
void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx) {
uint16_t secpar;
- initialize_libgcrypt();
+ initialize_libgcrypt(false);
secpar = read_secpar(state + 0);
det_randomize(key, keylen, state + 2, 2 * secpar / 8 + 8, idx);
diff --git a/src/libsystemd/libsystemd-journal-internal/journal-authenticate.c b/src/libsystemd/libsystemd-journal-internal/journal-authenticate.c
index 49f3c8f0f4..d8af113d3f 100644
--- a/src/libsystemd/libsystemd-journal-internal/journal-authenticate.c
+++ b/src/libsystemd/libsystemd-journal-internal/journal-authenticate.c
@@ -22,6 +22,7 @@
#include "fd-util.h"
#include "fsprg.h"
+#include "gcrypt-util.h"
#include "hexdecoct.h"
#include "journal-authenticate.h"
#include "journal-def.h"
@@ -424,25 +425,13 @@ finish:
return r;
}
-static void initialize_libgcrypt(void) {
- const char *p;
-
- if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
- return;
-
- p = gcry_check_version("1.4.5");
- assert(p);
-
- gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
-}
-
int journal_file_hmac_setup(JournalFile *f) {
gcry_error_t e;
if (!f->seal)
return 0;
- initialize_libgcrypt();
+ initialize_libgcrypt(true);
e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
if (e != 0)
diff --git a/src/libsystemd/libsystemd-journal-internal/journal-file.c b/src/libsystemd/libsystemd-journal-internal/journal-file.c
index 4ea7013a53..13db5c53de 100644
--- a/src/libsystemd/libsystemd-journal-internal/journal-file.c
+++ b/src/libsystemd/libsystemd-journal-internal/journal-file.c
@@ -20,6 +20,7 @@
#include <errno.h>
#include <fcntl.h>
#include <linux/fs.h>
+#include <pthread.h>
#include <stddef.h>
#include <sys/mman.h>
#include <sys/statvfs.h>
@@ -36,8 +37,10 @@
#include "journal-file.h"
#include "lookup3.h"
#include "parse-util.h"
+#include "path-util.h"
#include "random-util.h"
#include <systemd/sd-event.h>
+#include "set.h"
#include "string-util.h"
#include "xattr-util.h"
@@ -86,33 +89,127 @@
/* The mmap context to use for the header we pick as one above the last defined typed */
#define CONTEXT_HEADER _OBJECT_TYPE_MAX
-static int journal_file_set_online(JournalFile *f) {
+/* This may be called from a separate thread to prevent blocking the caller for the duration of fsync().
+ * As a result we use atomic operations on f->offline_state for inter-thread communications with
+ * journal_file_set_offline() and journal_file_set_online(). */
+static void journal_file_set_offline_internal(JournalFile *f) {
assert(f);
+ assert(f->fd >= 0);
+ assert(f->header);
- if (!f->writable)
- return -EPERM;
+ for (;;) {
+ switch (f->offline_state) {
+ case OFFLINE_CANCEL:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_CANCEL, OFFLINE_DONE))
+ continue;
+ return;
- if (!(f->fd >= 0 && f->header))
- return -EINVAL;
+ case OFFLINE_AGAIN_FROM_SYNCING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_SYNCING, OFFLINE_SYNCING))
+ continue;
+ break;
+
+ case OFFLINE_AGAIN_FROM_OFFLINING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_OFFLINING, OFFLINE_SYNCING))
+ continue;
+ break;
+
+ case OFFLINE_SYNCING:
+ (void) fsync(f->fd);
+
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_OFFLINING))
+ continue;
+
+ f->header->state = f->archive ? STATE_ARCHIVED : STATE_OFFLINE;
+ (void) fsync(f->fd);
+ break;
+
+ case OFFLINE_OFFLINING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_OFFLINING, OFFLINE_DONE))
+ continue;
+ /* fall through */
+
+ case OFFLINE_DONE:
+ return;
+
+ case OFFLINE_JOINED:
+ log_debug("OFFLINE_JOINED unexpected offline state for journal_file_set_offline_internal()");
+ return;
+ }
+ }
+}
+
+static void * journal_file_set_offline_thread(void *arg) {
+ JournalFile *f = arg;
+
+ journal_file_set_offline_internal(f);
+
+ return NULL;
+}
+
+static int journal_file_set_offline_thread_join(JournalFile *f) {
+ int r;
+
+ assert(f);
+
+ if (f->offline_state == OFFLINE_JOINED)
+ return 0;
+
+ r = pthread_join(f->offline_thread, NULL);
+ if (r)
+ return -r;
+
+ f->offline_state = OFFLINE_JOINED;
if (mmap_cache_got_sigbus(f->mmap, f->fd))
return -EIO;
- switch (f->header->state) {
- case STATE_ONLINE:
- return 0;
+ return 0;
+}
- case STATE_OFFLINE:
- f->header->state = STATE_ONLINE;
- fsync(f->fd);
- return 0;
+/* Trigger a restart if the offline thread is mid-flight in a restartable state. */
+static bool journal_file_set_offline_try_restart(JournalFile *f) {
+ for (;;) {
+ switch (f->offline_state) {
+ case OFFLINE_AGAIN_FROM_SYNCING:
+ case OFFLINE_AGAIN_FROM_OFFLINING:
+ return true;
+
+ case OFFLINE_CANCEL:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_CANCEL, OFFLINE_AGAIN_FROM_SYNCING))
+ continue;
+ return true;
+
+ case OFFLINE_SYNCING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_AGAIN_FROM_SYNCING))
+ continue;
+ return true;
+
+ case OFFLINE_OFFLINING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_OFFLINING, OFFLINE_AGAIN_FROM_OFFLINING))
+ continue;
+ return true;
default:
- return -EINVAL;
+ return false;
+ }
}
}
-int journal_file_set_offline(JournalFile *f) {
+/* Sets a journal offline.
+ *
+ * If wait is false then an offline is dispatched in a separate thread for a
+ * subsequent journal_file_set_offline() or journal_file_set_online() of the
+ * same journal to synchronize with.
+ *
+ * If wait is true, then either an existing offline thread will be restarted
+ * and joined, or if none exists the offline is simply performed in this
+ * context without involving another thread.
+ */
+int journal_file_set_offline(JournalFile *f, bool wait) {
+ bool restarted;
+ int r;
+
assert(f);
if (!f->writable)
@@ -121,22 +218,114 @@ int journal_file_set_offline(JournalFile *f) {
if (!(f->fd >= 0 && f->header))
return -EINVAL;
- if (f->header->state != STATE_ONLINE)
+ /* An offlining journal is implicitly online and may modify f->header->state,
+ * we must also join any potentially lingering offline thread when not online. */
+ if (!journal_file_is_offlining(f) && f->header->state != STATE_ONLINE)
+ return journal_file_set_offline_thread_join(f);
+
+ /* Restart an in-flight offline thread and wait if needed, or join a lingering done one. */
+ restarted = journal_file_set_offline_try_restart(f);
+ if ((restarted && wait) || !restarted) {
+ r = journal_file_set_offline_thread_join(f);
+ if (r < 0)
+ return r;
+ }
+
+ if (restarted)
return 0;
- fsync(f->fd);
+ /* Initiate a new offline. */
+ f->offline_state = OFFLINE_SYNCING;
- if (mmap_cache_got_sigbus(f->mmap, f->fd))
- return -EIO;
+ if (wait) /* Without using a thread if waiting. */
+ journal_file_set_offline_internal(f);
+ else {
+ r = pthread_create(&f->offline_thread, NULL, journal_file_set_offline_thread, f);
+ if (r > 0) {
+ f->offline_state = OFFLINE_JOINED;
+ return -r;
+ }
+ }
- f->header->state = STATE_OFFLINE;
+ return 0;
+}
+
+static int journal_file_set_online(JournalFile *f) {
+ bool joined = false;
+
+ assert(f);
+
+ if (!f->writable)
+ return -EPERM;
+
+ if (!(f->fd >= 0 && f->header))
+ return -EINVAL;
+
+ while (!joined) {
+ switch (f->offline_state) {
+ case OFFLINE_JOINED:
+ /* No offline thread, no need to wait. */
+ joined = true;
+ break;
+
+ case OFFLINE_SYNCING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_SYNCING, OFFLINE_CANCEL))
+ continue;
+ /* Canceled syncing prior to offlining, no need to wait. */
+ break;
+
+ case OFFLINE_AGAIN_FROM_SYNCING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_SYNCING, OFFLINE_CANCEL))
+ continue;
+ /* Canceled restart from syncing, no need to wait. */
+ break;
+
+ case OFFLINE_AGAIN_FROM_OFFLINING:
+ if (!__sync_bool_compare_and_swap(&f->offline_state, OFFLINE_AGAIN_FROM_OFFLINING, OFFLINE_CANCEL))
+ continue;
+ /* Canceled restart from offlining, must wait for offlining to complete however. */
+
+ /* fall through to wait */
+ default: {
+ int r;
+
+ r = journal_file_set_offline_thread_join(f);
+ if (r < 0)
+ return r;
+
+ joined = true;
+ break;
+ }
+ }
+ }
if (mmap_cache_got_sigbus(f->mmap, f->fd))
return -EIO;
- fsync(f->fd);
+ switch (f->header->state) {
+ case STATE_ONLINE:
+ return 0;
- return 0;
+ case STATE_OFFLINE:
+ f->header->state = STATE_ONLINE;
+ (void) fsync(f->fd);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+bool journal_file_is_offlining(JournalFile *f) {
+ assert(f);
+
+ __sync_synchronize();
+
+ if (f->offline_state == OFFLINE_DONE ||
+ f->offline_state == OFFLINE_JOINED)
+ return false;
+
+ return true;
}
JournalFile* journal_file_close(JournalFile *f) {
@@ -159,7 +348,7 @@ JournalFile* journal_file_close(JournalFile *f) {
sd_event_source_unref(f->post_change_timer);
}
- journal_file_set_offline(f);
+ journal_file_set_offline(f, true);
if (f->mmap && f->fd >= 0)
mmap_cache_close_fd(f->mmap, f->fd);
@@ -176,7 +365,8 @@ JournalFile* journal_file_close(JournalFile *f) {
(void) btrfs_defrag_fd(f->fd);
}
- safe_close(f->fd);
+ if (f->close_fd)
+ safe_close(f->fd);
free(f->path);
mmap_cache_unref(f->mmap);
@@ -203,6 +393,15 @@ JournalFile* journal_file_close(JournalFile *f) {
return NULL;
}
+void journal_file_close_set(Set *s) {
+ JournalFile *f;
+
+ assert(s);
+
+ while ((f = set_steal_first(s)))
+ (void) journal_file_close(f);
+}
+
static int journal_file_init_header(JournalFile *f, JournalFile *template) {
Header h = {};
ssize_t k;
@@ -240,6 +439,39 @@ static int journal_file_init_header(JournalFile *f, JournalFile *template) {
return 0;
}
+static int fsync_directory_of_file(int fd) {
+ _cleanup_free_ char *path = NULL, *dn = NULL;
+ _cleanup_close_ int dfd = -1;
+ struct stat st;
+ int r;
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISREG(st.st_mode))
+ return -EBADFD;
+
+ r = fd_get_path(fd, &path);
+ if (r < 0)
+ return r;
+
+ if (!path_is_absolute(path))
+ return -EINVAL;
+
+ dn = dirname_malloc(path);
+ if (!dn)
+ return -ENOMEM;
+
+ dfd = open(dn, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
+ if (dfd < 0)
+ return -errno;
+
+ if (fsync(dfd) < 0)
+ return -errno;
+
+ return 0;
+}
+
static int journal_file_refresh_header(JournalFile *f) {
sd_id128_t boot_id;
int r;
@@ -263,7 +495,10 @@ static int journal_file_refresh_header(JournalFile *f) {
r = journal_file_set_online(f);
/* Sync the online state to disk */
- fsync(f->fd);
+ (void) fsync(f->fd);
+
+ /* We likely just created a new file, also sync the directory this file is located in. */
+ (void) fsync_directory_of_file(f->fd);
return r;
}
@@ -508,7 +743,11 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset
/* Objects may only be located at multiple of 64 bit */
if (!VALID64(offset))
- return -EFAULT;
+ return -EBADMSG;
+
+ /* Object may not be located in the file header */
+ if (offset < le64toh(f->header->header_size))
+ return -EBADMSG;
r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t);
if (r < 0)
@@ -1123,8 +1362,8 @@ static int journal_file_append_data(
}
#endif
- if (compression == 0 && size > 0)
- memcpy(o->data.payload, data, size);
+ if (compression == 0)
+ memcpy_safe(o->data.payload, data, size);
r = journal_file_link_data(f, o, p, hash);
if (r < 0)
@@ -1389,7 +1628,7 @@ static int journal_file_append_entry_internal(
return r;
o->entry.seqnum = htole64(journal_file_entry_seqnum(f, seqnum));
- memcpy(o->entry.items, items, n_items * sizeof(EntryItem));
+ memcpy_safe(o->entry.items, items, n_items * sizeof(EntryItem));
o->entry.realtime = htole64(ts->realtime);
o->entry.monotonic = htole64(ts->monotonic);
o->entry.xor_hash = htole64(xor_hash);
@@ -1781,9 +2020,14 @@ static int generic_array_bisect(
i = right - 1;
lp = p = le64toh(array->entry_array.items[i]);
if (p <= 0)
- return -EBADMSG;
-
- r = test_object(f, p, needle);
+ r = -EBADMSG;
+ else
+ r = test_object(f, p, needle);
+ if (r == -EBADMSG) {
+ log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (1)");
+ n = i;
+ continue;
+ }
if (r < 0)
return r;
@@ -1859,9 +2103,14 @@ static int generic_array_bisect(
p = le64toh(array->entry_array.items[i]);
if (p <= 0)
- return -EBADMSG;
-
- r = test_object(f, p, needle);
+ r = -EBADMSG;
+ else
+ r = test_object(f, p, needle);
+ if (r == -EBADMSG) {
+ log_debug_errno(r, "Encountered invalid entry while bisecting, cutting algorithm short. (2)");
+ right = n = i;
+ continue;
+ }
if (r < 0)
return r;
@@ -1977,7 +2226,7 @@ static int generic_array_bisect_plus_one(
goto found;
if (r > 0 && idx)
- (*idx) ++;
+ (*idx)++;
return r;
@@ -2266,13 +2515,18 @@ int journal_file_next_entry(
le64toh(f->header->entry_array_offset),
i,
ret, &ofs);
+ if (r == -EBADMSG && direction == DIRECTION_DOWN) {
+ /* Special case: when we iterate throught the journal file linearly, and hit an entry we can't read,
+ * consider this the end of the journal file. */
+ log_debug_errno(r, "Encountered entry we can't read while iterating through journal file. Considering this the end of the file.");
+ return 0;
+ }
if (r <= 0)
return r;
if (p > 0 &&
(direction == DIRECTION_DOWN ? ofs <= p : ofs >= p)) {
- log_debug("%s: entry array corrupted at entry %"PRIu64,
- f->path, i);
+ log_debug("%s: entry array corrupted at entry %" PRIu64, f->path, i);
return -EBADMSG;
}
@@ -2611,11 +2865,11 @@ void journal_file_print_header(JournalFile *f) {
"Data Hash Table Size: %"PRIu64"\n"
"Field Hash Table Size: %"PRIu64"\n"
"Rotate Suggested: %s\n"
- "Head Sequential Number: %"PRIu64"\n"
- "Tail Sequential Number: %"PRIu64"\n"
- "Head Realtime Timestamp: %s\n"
- "Tail Realtime Timestamp: %s\n"
- "Tail Monotonic Timestamp: %s\n"
+ "Head Sequential Number: %"PRIu64" (%"PRIx64")\n"
+ "Tail Sequential Number: %"PRIu64" (%"PRIx64")\n"
+ "Head Realtime Timestamp: %s (%"PRIx64")\n"
+ "Tail Realtime Timestamp: %s (%"PRIx64")\n"
+ "Tail Monotonic Timestamp: %s (%"PRIx64")\n"
"Objects: %"PRIu64"\n"
"Entry Objects: %"PRIu64"\n",
f->path,
@@ -2636,11 +2890,11 @@ void journal_file_print_header(JournalFile *f) {
le64toh(f->header->data_hash_table_size) / sizeof(HashItem),
le64toh(f->header->field_hash_table_size) / sizeof(HashItem),
yes_no(journal_file_rotate_suggested(f, 0)),
- le64toh(f->header->head_entry_seqnum),
- le64toh(f->header->tail_entry_seqnum),
- format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)),
- format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)),
- format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC),
+ le64toh(f->header->head_entry_seqnum), le64toh(f->header->head_entry_seqnum),
+ le64toh(f->header->tail_entry_seqnum), le64toh(f->header->tail_entry_seqnum),
+ format_timestamp_safe(x, sizeof(x), le64toh(f->header->head_entry_realtime)), le64toh(f->header->head_entry_realtime),
+ format_timestamp_safe(y, sizeof(y), le64toh(f->header->tail_entry_realtime)), le64toh(f->header->tail_entry_realtime),
+ format_timespan(z, sizeof(z), le64toh(f->header->tail_entry_monotonic), USEC_PER_MSEC), le64toh(f->header->tail_entry_monotonic),
le64toh(f->header->n_objects),
le64toh(f->header->n_entries));
@@ -2703,6 +2957,7 @@ static int journal_file_warn_btrfs(JournalFile *f) {
}
int journal_file_open(
+ int fd,
const char *fname,
int flags,
mode_t mode,
@@ -2710,6 +2965,7 @@ int journal_file_open(
bool seal,
JournalMetrics *metrics,
MMapCache *mmap_cache,
+ Set *deferred_closes,
JournalFile *template,
JournalFile **ret) {
@@ -2718,22 +2974,24 @@ int journal_file_open(
void *h;
int r;
- assert(fname);
assert(ret);
+ assert(fd >= 0 || fname);
if ((flags & O_ACCMODE) != O_RDONLY &&
(flags & O_ACCMODE) != O_RDWR)
return -EINVAL;
- if (!endswith(fname, ".journal") &&
- !endswith(fname, ".journal~"))
- return -EINVAL;
+ if (fname) {
+ if (!endswith(fname, ".journal") &&
+ !endswith(fname, ".journal~"))
+ return -EINVAL;
+ }
f = new0(JournalFile, 1);
if (!f)
return -ENOMEM;
- f->fd = -1;
+ f->fd = fd;
f->mode = mode;
f->flags = flags;
@@ -2758,7 +3016,10 @@ int journal_file_open(
}
}
- f->path = strdup(fname);
+ if (fname)
+ f->path = strdup(fname);
+ else /* If we don't know the path, fill in something explanatory and vaguely useful */
+ asprintf(&f->path, "/proc/self/%i", fd);
if (!f->path) {
r = -ENOMEM;
goto fail;
@@ -2770,10 +3031,15 @@ int journal_file_open(
goto fail;
}
- f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
if (f->fd < 0) {
- r = -errno;
- goto fail;
+ f->fd = open(f->path, f->flags|O_CLOEXEC, f->mode);
+ if (f->fd < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ /* fds we opened here by us should also be closed by us. */
+ f->close_fd = true;
}
r = journal_file_fstat(f);
@@ -2829,6 +3095,9 @@ int journal_file_open(
f->header = h;
if (!newly_created) {
+ if (deferred_closes)
+ journal_file_close_set(deferred_closes);
+
r = journal_file_verify_header(f);
if (r < 0)
goto fail;
@@ -2891,6 +3160,9 @@ int journal_file_open(
goto fail;
}
+ /* The file is opened now successfully, thus we take possession of any passed in fd. */
+ f->close_fd = true;
+
*ret = f;
return 0;
@@ -2898,12 +3170,12 @@ fail:
if (f->fd >= 0 && mmap_cache_got_sigbus(f->mmap, f->fd))
r = -EIO;
- journal_file_close(f);
+ (void) journal_file_close(f);
return r;
}
-int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
+int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred_closes) {
_cleanup_free_ char *p = NULL;
size_t l;
JournalFile *old_file, *new_file = NULL;
@@ -2917,6 +3189,11 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
if (!old_file->writable)
return -EINVAL;
+ /* Is this a journal file that was passed to us as fd? If so, we synthesized a path name for it, and we refuse
+ * rotation, since we don't know the actual path, and couldn't rename the file hence.*/
+ if (path_startswith(old_file->path, "/proc/self/fd"))
+ return -EINVAL;
+
if (!endswith(old_file->path, ".journal"))
return -EINVAL;
@@ -2936,15 +3213,29 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal) {
if (r < 0 && errno != ENOENT)
return -errno;
- old_file->header->state = STATE_ARCHIVED;
+ /* Sync the rename to disk */
+ (void) fsync_directory_of_file(old_file->fd);
+
+ /* Set as archive so offlining commits w/state=STATE_ARCHIVED.
+ * Previously we would set old_file->header->state to STATE_ARCHIVED directly here,
+ * but journal_file_set_offline() short-circuits when state != STATE_ONLINE, which
+ * would result in the rotated journal never getting fsync() called before closing.
+ * Now we simply queue the archive state by setting an archive bit, leaving the state
+ * as STATE_ONLINE so proper offlining occurs. */
+ old_file->archive = true;
/* Currently, btrfs is not very good with out write patterns
* and fragments heavily. Let's defrag our journal files when
* we archive them */
old_file->defrag_on_close = true;
- r = journal_file_open(old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, old_file, &new_file);
- journal_file_close(old_file);
+ r = journal_file_open(-1, old_file->path, old_file->flags, old_file->mode, compress, seal, NULL, old_file->mmap, deferred_closes, old_file, &new_file);
+
+ if (deferred_closes &&
+ set_put(deferred_closes, old_file) >= 0)
+ (void) journal_file_set_offline(old_file, false);
+ else
+ (void) journal_file_close(old_file);
*f = new_file;
return r;
@@ -2958,6 +3249,7 @@ int journal_file_open_reliably(
bool seal,
JournalMetrics *metrics,
MMapCache *mmap_cache,
+ Set *deferred_closes,
JournalFile *template,
JournalFile **ret) {
@@ -2965,7 +3257,7 @@ int journal_file_open_reliably(
size_t l;
_cleanup_free_ char *p = NULL;
- r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret);
+ r = journal_file_open(-1, fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret);
if (!IN_SET(r,
-EBADMSG, /* corrupted */
-ENODATA, /* truncated */
@@ -3001,12 +3293,12 @@ int journal_file_open_reliably(
/* btrfs doesn't cope well with our write pattern and
* fragments heavily. Let's defrag all files we rotate */
- (void) chattr_path(p, false, FS_NOCOW_FL);
+ (void) chattr_path(p, 0, FS_NOCOW_FL);
(void) btrfs_defrag(p);
log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname);
- return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret);
+ return journal_file_open(-1, fname, flags, mode, compress, seal, metrics, mmap_cache, deferred_closes, template, ret);
}
int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) {
diff --git a/src/libsystemd/libsystemd-journal-internal/journal-file.h b/src/libsystemd/libsystemd-journal-internal/journal-file.h
index 0414117d98..e48e98f424 100644
--- a/src/libsystemd/libsystemd-journal-internal/journal-file.h
+++ b/src/libsystemd/libsystemd-journal-internal/journal-file.h
@@ -63,6 +63,16 @@ typedef enum LocationType {
LOCATION_SEEK
} LocationType;
+typedef enum OfflineState {
+ OFFLINE_JOINED,
+ OFFLINE_SYNCING,
+ OFFLINE_OFFLINING,
+ OFFLINE_CANCEL,
+ OFFLINE_AGAIN_FROM_SYNCING,
+ OFFLINE_AGAIN_FROM_OFFLINING,
+ OFFLINE_DONE
+} OfflineState;
+
typedef struct JournalFile {
int fd;
@@ -75,6 +85,8 @@ typedef struct JournalFile {
bool compress_lz4:1;
bool seal:1;
bool defrag_on_close:1;
+ bool close_fd:1;
+ bool archive:1;
bool tail_entry_monotonic_valid:1;
@@ -105,6 +117,9 @@ typedef struct JournalFile {
OrderedHashmap *chain_cache;
+ pthread_t offline_thread;
+ volatile OfflineState offline_state;
+
#if defined(HAVE_XZ) || defined(HAVE_LZ4)
void *compress_buffer;
size_t compress_buffer_size;
@@ -129,6 +144,7 @@ typedef struct JournalFile {
} JournalFile;
int journal_file_open(
+ int fd,
const char *fname,
int flags,
mode_t mode,
@@ -136,11 +152,14 @@ int journal_file_open(
bool seal,
JournalMetrics *metrics,
MMapCache *mmap_cache,
+ Set *deferred_closes,
JournalFile *template,
JournalFile **ret);
-int journal_file_set_offline(JournalFile *f);
+int journal_file_set_offline(JournalFile *f, bool wait);
+bool journal_file_is_offlining(JournalFile *f);
JournalFile* journal_file_close(JournalFile *j);
+void journal_file_close_set(Set *s);
int journal_file_open_reliably(
const char *fname,
@@ -150,6 +169,7 @@ int journal_file_open_reliably(
bool seal,
JournalMetrics *metrics,
MMapCache *mmap_cache,
+ Set *deferred_closes,
JournalFile *template,
JournalFile **ret);
@@ -223,7 +243,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6
void journal_file_dump(JournalFile *f);
void journal_file_print_header(JournalFile *f);
-int journal_file_rotate(JournalFile **f, bool compress, bool seal);
+int journal_file_rotate(JournalFile **f, bool compress, bool seal, Set *deferred_closes);
void journal_file_post_change(JournalFile *f);
int journal_file_enable_post_change_timer(JournalFile *f, sd_event *e, usec_t t);
diff --git a/src/libsystemd/libsystemd-journal-internal/journal-internal.h b/src/libsystemd/libsystemd-journal-internal/journal-internal.h
index 8f21544ae1..d8eb11ad06 100644
--- a/src/libsystemd/libsystemd-journal-internal/journal-internal.h
+++ b/src/libsystemd/libsystemd-journal-internal/journal-internal.h
@@ -82,6 +82,8 @@ struct Directory {
};
struct sd_journal {
+ int toplevel_fd;
+
char *path;
char *prefix;
@@ -117,6 +119,7 @@ struct sd_journal {
bool on_network:1;
bool no_new_files:1;
+ bool no_inotify:1;
bool unique_file_lost:1; /* File we were iterating over got
removed, and there were no more
files, so sd_j_enumerate_unique
diff --git a/src/libsystemd/libsystemd-journal-internal/journal-send.c b/src/libsystemd/libsystemd-journal-internal/journal-send.c
index b85d9d3c61..5a49211f85 100644
--- a/src/libsystemd/libsystemd-journal-internal/journal-send.c
+++ b/src/libsystemd/libsystemd-journal-internal/journal-send.c
@@ -50,7 +50,7 @@
*_f = alloca(_fl + 10); \
memcpy(*_f, "CODE_FUNC=", 10); \
memcpy(*_f + 10, _func, _fl); \
- } while(false)
+ } while (false)
/* We open a single fd, and we'll share it with the current process,
* all its threads, and all its subprocesses. This means we need to
@@ -208,13 +208,13 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
struct iovec *w;
uint64_t *l;
int i, j = 0;
- struct sockaddr_un sa = {
- .sun_family = AF_UNIX,
- .sun_path = "/run/systemd/journal/socket",
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/journal/socket",
};
struct msghdr mh = {
- .msg_name = &sa,
- .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path),
+ .msg_name = (struct sockaddr*) &sa.sa,
+ .msg_namelen = SOCKADDR_UN_LEN(sa.un),
};
ssize_t k;
bool have_syslog_identifier = false;
@@ -316,7 +316,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
buffer_fd = memfd_new(NULL);
if (buffer_fd < 0) {
if (buffer_fd == -ENOSYS) {
- buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
+ buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC);
if (buffer_fd < 0)
return buffer_fd;
@@ -392,7 +392,7 @@ _public_ int sd_journal_perror(const char *message) {
}
_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
- union sockaddr_union sa = {
+ static const union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
.un.sun_path = "/run/systemd/journal/stdout",
};
@@ -408,7 +408,7 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
if (fd < 0)
return -errno;
- r = connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
diff --git a/src/libsystemd/libsystemd-journal-internal/journal-vacuum.c b/src/libsystemd/libsystemd-journal-internal/journal-vacuum.c
index 3650ab3865..cd2676ab63 100644
--- a/src/libsystemd/libsystemd-journal-internal/journal-vacuum.c
+++ b/src/libsystemd/libsystemd-journal-internal/journal-vacuum.c
@@ -239,13 +239,13 @@ int journal_directory_vacuum(
/* Vacuum corrupted files */
if (q < 1 + 16 + 1 + 16 + 8 + 1) {
- n_active_files ++;
+ n_active_files++;
continue;
}
if (de->d_name[q-1-8-16-1] != '-' ||
de->d_name[q-1-8-16-1-16-1] != '@') {
- n_active_files ++;
+ n_active_files++;
continue;
}
@@ -256,7 +256,7 @@ int journal_directory_vacuum(
}
if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
- n_active_files ++;
+ n_active_files++;
continue;
}
@@ -302,7 +302,7 @@ int journal_directory_vacuum(
list[n_list].realtime = realtime;
list[n_list].seqnum_id = seqnum_id;
list[n_list].have_seqnum = have_seqnum;
- n_list ++;
+ n_list++;
p = NULL;
sum += size;
diff --git a/src/libsystemd/libsystemd-journal-internal/journal-verify.c b/src/libsystemd/libsystemd-journal-internal/journal-verify.c
index b968e89bb8..26572ddd76 100644
--- a/src/libsystemd/libsystemd-journal-internal/journal-verify.c
+++ b/src/libsystemd/libsystemd-journal-internal/journal-verify.c
@@ -97,20 +97,20 @@ static void flush_progress(void) {
fflush(stdout);
}
-#define debug(_offset, _fmt, ...) do{ \
+#define debug(_offset, _fmt, ...) do { \
flush_progress(); \
log_debug(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
- } while(0)
+ } while (0)
-#define warning(_offset, _fmt, ...) do{ \
+#define warning(_offset, _fmt, ...) do { \
flush_progress(); \
log_warning(OFSfmt": " _fmt, _offset, ##__VA_ARGS__); \
- } while(0)
+ } while (0)
-#define error(_offset, _fmt, ...) do{ \
+#define error(_offset, _fmt, ...) do { \
flush_progress(); \
log_error(OFSfmt": " _fmt, (uint64_t)_offset, ##__VA_ARGS__); \
- } while(0)
+ } while (0)
static int journal_file_object_verify(JournalFile *f, uint64_t offset, Object *o) {
uint64_t i;
@@ -838,19 +838,19 @@ int journal_file_verify(
} else if (f->seal)
return -ENOKEY;
- data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+ data_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
if (data_fd < 0) {
r = log_error_errno(data_fd, "Failed to create data file: %m");
goto fail;
}
- entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+ entry_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_fd < 0) {
r = log_error_errno(entry_fd, "Failed to create entry file: %m");
goto fail;
}
- entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
+ entry_array_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_array_fd < 0) {
r = log_error_errno(entry_array_fd,
"Failed to create entry array file: %m");
@@ -894,7 +894,7 @@ int journal_file_verify(
goto fail;
}
- n_objects ++;
+ n_objects++;
r = journal_file_object_verify(f, p, o);
if (r < 0) {
@@ -991,7 +991,7 @@ int journal_file_verify(
entry_realtime = le64toh(o->entry.realtime);
entry_realtime_set = true;
- n_entries ++;
+ n_entries++;
break;
case OBJECT_DATA_HASH_TABLE:
@@ -1131,11 +1131,11 @@ int journal_file_verify(
last_epoch = le64toh(o->tag.epoch);
- n_tags ++;
+ n_tags++;
break;
default:
- n_weird ++;
+ n_weird++;
}
if (p == le64toh(f->header->tail_object_offset)) {
diff --git a/src/libsystemd/libsystemd-journal-internal/mmap-cache.c b/src/libsystemd/libsystemd-journal-internal/mmap-cache.c
index 9c0ce8ccbf..6bcd9b6ac8 100644
--- a/src/libsystemd/libsystemd-journal-internal/mmap-cache.c
+++ b/src/libsystemd/libsystemd-journal-internal/mmap-cache.c
@@ -107,7 +107,7 @@ MMapCache* mmap_cache_ref(MMapCache *m) {
assert(m);
assert(m->n_ref > 0);
- m->n_ref ++;
+ m->n_ref++;
return m;
}
@@ -361,7 +361,7 @@ MMapCache* mmap_cache_unref(MMapCache *m) {
assert(m->n_ref > 0);
- m->n_ref --;
+ m->n_ref--;
if (m->n_ref == 0)
mmap_cache_free(m);
@@ -598,14 +598,14 @@ int mmap_cache_get(
/* Check whether the current context is the right one already */
r = try_context(m, fd, prot, context, keep_always, offset, size, ret);
if (r != 0) {
- m->n_hit ++;
+ m->n_hit++;
return r;
}
/* Search for a matching mmap */
r = find_mmap(m, fd, prot, context, keep_always, offset, size, ret);
if (r != 0) {
- m->n_hit ++;
+ m->n_hit++;
return r;
}
diff --git a/src/libsystemd/libsystemd-journal-internal/sd-journal.c b/src/libsystemd/libsystemd-journal-internal/sd-journal.c
index 1493f0348d..930486d65f 100644
--- a/src/libsystemd/libsystemd-journal-internal/sd-journal.c
+++ b/src/libsystemd/libsystemd-journal-internal/sd-journal.c
@@ -19,6 +19,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
#include <linux/magic.h>
#include <poll.h>
#include <stddef.h>
@@ -1063,7 +1064,7 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) {
if (r < 0)
return r;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *item = NULL;
unsigned long long ll;
sd_id128_t id;
@@ -1232,14 +1233,37 @@ static bool file_type_wanted(int flags, const char *filename) {
return false;
}
-static int add_any_file(sd_journal *j, const char *path) {
+static bool path_has_prefix(sd_journal *j, const char *path, const char *prefix) {
+ assert(j);
+ assert(path);
+ assert(prefix);
+
+ if (j->toplevel_fd >= 0)
+ return false;
+
+ return path_startswith(path, prefix);
+}
+
+static const char *skip_slash(const char *p) {
+
+ if (!p)
+ return NULL;
+
+ while (*p == '/')
+ p++;
+
+ return p;
+}
+
+static int add_any_file(sd_journal *j, int fd, const char *path) {
JournalFile *f = NULL;
+ bool close_fd = false;
int r, k;
assert(j);
- assert(path);
+ assert(fd >= 0 || path);
- if (ordered_hashmap_get(j->files, path))
+ if (path && ordered_hashmap_get(j->files, path))
return 0;
if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) {
@@ -1248,8 +1272,24 @@ static int add_any_file(sd_journal *j, const char *path) {
goto fail;
}
- r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f);
+ if (fd < 0 && j->toplevel_fd >= 0) {
+
+ /* If there's a top-level fd defined, open the file relative to this now. (Make the path relative,
+ * explicitly, since otherwise openat() ignores the first argument.) */
+
+ fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC);
+ if (fd < 0) {
+ r = log_debug_errno(errno, "Failed to open journal file %s: %m", path);
+ goto fail;
+ }
+
+ close_fd = true;
+ }
+
+ r = journal_file_open(fd, path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, NULL, &f);
if (r < 0) {
+ if (close_fd)
+ safe_close(fd);
log_debug_errno(r, "Failed to open journal file %s: %m", path);
goto fail;
}
@@ -1258,15 +1298,21 @@ static int add_any_file(sd_journal *j, const char *path) {
r = ordered_hashmap_put(j->files, f->path, f);
if (r < 0) {
- journal_file_close(f);
+ f->close_fd = close_fd;
+ (void) journal_file_close(f);
goto fail;
}
+ if (!j->has_runtime_files && path_has_prefix(j, f->path, "/run"))
+ j->has_runtime_files = true;
+ else if (!j->has_persistent_files && path_has_prefix(j, f->path, "/var"))
+ j->has_persistent_files = true;
+
log_debug("File %s added.", f->path);
check_network(j, f->fd);
- j->current_invalidate_counter ++;
+ j->current_invalidate_counter++;
return 0;
@@ -1285,18 +1331,14 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) {
assert(prefix);
assert(filename);
- if (j->no_new_files ||
- !file_type_wanted(j->flags, filename))
+ if (j->no_new_files)
return 0;
- path = strjoina(prefix, "/", filename);
-
- if (!j->has_runtime_files && path_startswith(path, "/run/log/journal"))
- j->has_runtime_files = true;
- else if (!j->has_persistent_files && path_startswith(path, "/var/log/journal"))
- j->has_persistent_files = true;
+ if (!file_type_wanted(j->flags, filename))
+ return 0;
- return add_any_file(j, path);
+ path = strjoina(prefix, "/", filename);
+ return add_any_file(j, -1, path);
}
static void remove_file(sd_journal *j, const char *prefix, const char *filename) {
@@ -1343,9 +1385,9 @@ static void remove_file_real(sd_journal *j, JournalFile *f) {
j->fields_file_lost = true;
}
- journal_file_close(f);
+ (void) journal_file_close(f);
- j->current_invalidate_counter ++;
+ j->current_invalidate_counter++;
}
static int dirname_is_machine_id(const char *fn) {
@@ -1372,21 +1414,33 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
assert(j);
assert(prefix);
- assert(dirname);
- log_debug("Considering %s/%s.", prefix, dirname);
-
- if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
- !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run")))
- return 0;
+ /* Adds a journal file directory to watch. If the directory is already tracked this updates the inotify watch
+ * and reenumerates directory contents */
- path = strjoin(prefix, "/", dirname, NULL);
+ if (dirname)
+ path = strjoin(prefix, "/", dirname, NULL);
+ else
+ path = strdup(prefix);
if (!path) {
r = -ENOMEM;
goto fail;
}
- d = opendir(path);
+ log_debug("Considering directory %s.", path);
+
+ /* We consider everything local that is in a directory for the local machine ID, or that is stored in /run */
+ if ((j->flags & SD_JOURNAL_LOCAL_ONLY) &&
+ !((dirname && dirname_is_machine_id(dirname) > 0) || path_has_prefix(j, path, "/run")))
+ return 0;
+
+
+ if (j->toplevel_fd < 0)
+ d = opendir(path);
+ else
+ /* Open the specified directory relative to the the toplevel fd. Enforce that the path specified is
+ * relative, by dropping the initial slash */
+ d = xopendirat(j->toplevel_fd, skip_slash(path), 0);
if (!d) {
r = log_debug_errno(errno, "Failed to open directory %s: %m", path);
goto fail;
@@ -1410,7 +1464,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
}
path = NULL; /* avoid freeing in cleanup */
- j->current_invalidate_counter ++;
+ j->current_invalidate_counter++;
log_debug("Directory %s added.", m->path);
@@ -1418,17 +1472,18 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
return 0;
if (m->wd <= 0 && j->inotify_fd >= 0) {
+ /* Watch this directory, if it not being watched yet. */
- m->wd = inotify_add_watch(j->inotify_fd, m->path,
- IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
- IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
- IN_ONLYDIR);
+ m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d),
+ IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
+ IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT|IN_MOVED_FROM|
+ IN_ONLYDIR);
if (m->wd > 0 && hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m) < 0)
inotify_rm_watch(j->inotify_fd, m->wd);
}
- FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
+ FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) {
if (dirent_is_file_with_suffix(de, ".journal") ||
dirent_is_file_with_suffix(de, ".journal~"))
@@ -1440,7 +1495,7 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname)
return 0;
fail:
- k = journal_put_error(j, r, path ?: dirname);
+ k = journal_put_error(j, r, path ?: prefix);
if (k < 0)
return k;
@@ -1448,28 +1503,62 @@ fail:
}
static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
+
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
Directory *m;
int r, k;
assert(j);
- assert(p);
- if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
- !path_startswith(p, "/run"))
- return -EINVAL;
+ /* Adds a root directory to our set of directories to use. If the root directory is already in the set, we
+ * update the inotify logic, and renumerate the directory entries. This call may hence be called to initially
+ * populate the set, as well as to update it later. */
- if (j->prefix)
- p = strjoina(j->prefix, p);
+ if (p) {
+ /* If there's a path specified, use it. */
- d = opendir(p);
- if (!d) {
- if (errno == ENOENT && missing_ok)
- return 0;
+ if ((j->flags & SD_JOURNAL_RUNTIME_ONLY) &&
+ !path_has_prefix(j, p, "/run"))
+ return -EINVAL;
- r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
- goto fail;
+ if (j->prefix)
+ p = strjoina(j->prefix, p);
+
+ if (j->toplevel_fd < 0)
+ d = opendir(p);
+ else
+ d = xopendirat(j->toplevel_fd, skip_slash(p), 0);
+
+ if (!d) {
+ if (errno == ENOENT && missing_ok)
+ return 0;
+
+ r = log_debug_errno(errno, "Failed to open root directory %s: %m", p);
+ goto fail;
+ }
+ } else {
+ int dfd;
+
+ /* If there's no path specified, then we use the top-level fd itself. We duplicate the fd here, since
+ * opendir() will take possession of the fd, and close it, which we don't want. */
+
+ p = "."; /* store this as "." in the directories hashmap */
+
+ dfd = fcntl(j->toplevel_fd, F_DUPFD_CLOEXEC, 3);
+ if (dfd < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ d = fdopendir(dfd);
+ if (!d) {
+ r = -errno;
+ safe_close(dfd);
+ goto fail;
+ }
+
+ rewinddir(d);
}
m = hashmap_get(j->directories_by_path, p);
@@ -1481,6 +1570,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
}
m->is_root = true;
+
m->path = strdup(p);
if (!m->path) {
free(m);
@@ -1495,7 +1585,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
goto fail;
}
- j->current_invalidate_counter ++;
+ j->current_invalidate_counter++;
log_debug("Root directory %s added.", m->path);
@@ -1504,7 +1594,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
if (m->wd <= 0 && j->inotify_fd >= 0) {
- m->wd = inotify_add_watch(j->inotify_fd, m->path,
+ m->wd = inotify_add_watch_fd(j->inotify_fd, dirfd(d),
IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB|IN_DELETE|
IN_ONLYDIR);
@@ -1515,7 +1605,7 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
if (j->no_new_files)
return 0;
- FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) {
+ FOREACH_DIRENT_ALL(de, d, r = log_debug_errno(errno, "Failed to read directory %s: %m", m->path); goto fail) {
sd_id128_t id;
if (dirent_is_file_with_suffix(de, ".journal") ||
@@ -1584,8 +1674,7 @@ static int add_current_paths(sd_journal *j) {
assert(j);
assert(j->no_new_files);
- /* Simply adds all directories for files we have open as
- * "root" directories. We don't expect errors here, so we
+ /* Simply adds all directories for files we have open as directories. We don't expect errors here, so we
* treat them as fatal. */
ORDERED_HASHMAP_FOREACH(f, j->files, i) {
@@ -1596,7 +1685,7 @@ static int add_current_paths(sd_journal *j) {
if (!dir)
return -ENOMEM;
- r = add_root_directory(j, dir, true);
+ r = add_directory(j, dir, NULL);
if (r < 0)
return r;
}
@@ -1613,13 +1702,7 @@ static int allocate_inotify(sd_journal *j) {
return -errno;
}
- if (!j->directories_by_wd) {
- j->directories_by_wd = hashmap_new(NULL);
- if (!j->directories_by_wd)
- return -ENOMEM;
- }
-
- return 0;
+ return hashmap_ensure_allocated(&j->directories_by_wd, NULL);
}
static sd_journal *journal_new(int flags, const char *path) {
@@ -1630,6 +1713,7 @@ static sd_journal *journal_new(int flags, const char *path) {
return NULL;
j->original_pid = getpid();
+ j->toplevel_fd = -1;
j->inotify_fd = -1;
j->flags = flags;
j->data_threshold = DEFAULT_DATA_THRESHOLD;
@@ -1683,6 +1767,9 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
char *p;
int r;
+ /* This is pretty much deprecated, people should use machined's OpenMachineRootDirectory() call instead in
+ * combination with sd_journal_open_directory_fd(). */
+
assert_return(machine, -EINVAL);
assert_return(ret, -EINVAL);
assert_return((flags & ~(SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM)) == 0, -EINVAL);
@@ -1725,13 +1812,16 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
assert_return(ret, -EINVAL);
assert_return(path, -EINVAL);
- assert_return(flags == 0, -EINVAL);
+ assert_return((flags & ~SD_JOURNAL_OS_ROOT) == 0, -EINVAL);
j = journal_new(flags, path);
if (!j)
return -ENOMEM;
- r = add_root_directory(j, path, false);
+ if (flags & SD_JOURNAL_OS_ROOT)
+ r = add_search_paths(j);
+ else
+ r = add_root_directory(j, path, false);
if (r < 0)
goto fail;
@@ -1740,7 +1830,6 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
fail:
sd_journal_close(j);
-
return r;
}
@@ -1757,7 +1846,7 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
return -ENOMEM;
STRV_FOREACH(path, paths) {
- r = add_any_file(j, *path);
+ r = add_any_file(j, -1, *path);
if (r < 0)
goto fail;
}
@@ -1769,7 +1858,96 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
fail:
sd_journal_close(j);
+ return r;
+}
+
+_public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
+ sd_journal *j;
+ struct stat st;
+ int r;
+
+ assert_return(ret, -EINVAL);
+ assert_return(fd >= 0, -EBADF);
+ assert_return((flags & ~SD_JOURNAL_OS_ROOT) == 0, -EINVAL);
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+
+ if (!S_ISDIR(st.st_mode))
+ return -EBADFD;
+
+ j = journal_new(flags, NULL);
+ if (!j)
+ return -ENOMEM;
+
+ j->toplevel_fd = fd;
+
+ if (flags & SD_JOURNAL_OS_ROOT)
+ r = add_search_paths(j);
+ else
+ r = add_root_directory(j, NULL, false);
+ if (r < 0)
+ goto fail;
+ *ret = j;
+ return 0;
+
+fail:
+ sd_journal_close(j);
+ return r;
+}
+
+_public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags) {
+ Iterator iterator;
+ JournalFile *f;
+ sd_journal *j;
+ unsigned i;
+ int r;
+
+ assert_return(ret, -EINVAL);
+ assert_return(n_fds > 0, -EBADF);
+ assert_return(flags == 0, -EINVAL);
+
+ j = journal_new(flags, NULL);
+ if (!j)
+ return -ENOMEM;
+
+ for (i = 0; i < n_fds; i++) {
+ struct stat st;
+
+ if (fds[i] < 0) {
+ r = -EBADF;
+ goto fail;
+ }
+
+ if (fstat(fds[i], &st) < 0) {
+ r = -errno;
+ goto fail;
+ }
+
+ if (!S_ISREG(st.st_mode)) {
+ r = -EBADFD;
+ goto fail;
+ }
+
+ r = add_any_file(j, fds[i], NULL);
+ if (r < 0)
+ goto fail;
+ }
+
+ j->no_new_files = true;
+ j->no_inotify = true;
+
+ *ret = j;
+ return 0;
+
+fail:
+ /* If we fail, make sure we don't take possession of the files we managed to make use of successfully, and they
+ * remain open */
+ ORDERED_HASHMAP_FOREACH(f, j->files, iterator)
+ f->close_fd = false;
+
+ sd_journal_close(j);
return r;
}
@@ -1784,7 +1962,7 @@ _public_ void sd_journal_close(sd_journal *j) {
sd_journal_flush_matches(j);
while ((f = ordered_hashmap_steal_first(j->files)))
- journal_file_close(f);
+ (void) journal_file_close(f);
ordered_hashmap_free(j->files);
@@ -1957,7 +2135,7 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void **
&f->compress_buffer, &f->compress_buffer_size,
field, field_length, '=');
if (r < 0)
- log_debug_errno(r, "Cannot decompress %s object of length %zu at offset "OFSfmt": %m",
+ log_debug_errno(r, "Cannot decompress %s object of length %"PRIu64" at offset "OFSfmt": %m",
object_compressed_to_string(compression), l, p);
else if (r > 0) {
@@ -2078,7 +2256,7 @@ _public_ int sd_journal_enumerate_data(sd_journal *j, const void **data, size_t
if (r < 0)
return r;
- j->current_field ++;
+ j->current_field++;
return 1;
}
@@ -2096,6 +2274,9 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
assert_return(j, -EINVAL);
assert_return(!journal_pid_changed(j), -ECHILD);
+ if (j->no_inotify)
+ return -EMEDIUMTYPE;
+
if (j->inotify_fd >= 0)
return j->inotify_fd;
@@ -2103,10 +2284,14 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
if (r < 0)
return r;
+ log_debug("Reiterating files to get inotify watches established");
+
/* Iterate through all dirs again, to add them to the
* inotify */
if (j->no_new_files)
r = add_current_paths(j);
+ else if (j->toplevel_fd >= 0)
+ r = add_root_directory(j, NULL, false);
else if (j->path)
r = add_root_directory(j, j->path, true);
else
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 4ab637b686..0b3a1708dc 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -489,3 +489,9 @@ global:
sd_journal_enumerate_fields;
sd_journal_restart_fields;
} LIBSYSTEMD_227;
+
+LIBSYSTEMD_230 {
+global:
+ sd_journal_open_directory_fd;
+ sd_journal_open_files_fd;
+} LIBSYSTEMD_229;
diff --git a/src/libudev/include/libudev.h b/src/libudev/include/libudev.h
index eb58740d26..3f6d0ed16c 100644
--- a/src/libudev/include/libudev.h
+++ b/src/libudev/include/libudev.h
@@ -21,6 +21,7 @@
#define _LIBUDEV_H_
#include <stdarg.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#ifdef __cplusplus
diff --git a/src/libudev/src/libudev-device-internal.h b/src/libudev/src/libudev-device-internal.h
index de6f680819..f76da09407 100644
--- a/src/libudev/src/libudev-device-internal.h
+++ b/src/libudev/src/libudev-device-internal.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -18,8 +20,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "libudev.h"
#include <systemd/sd-device.h>
diff --git a/src/libudev/src/libudev-enumerate.c b/src/libudev/src/libudev-enumerate.c
index c784da5715..9910cea957 100644
--- a/src/libudev/src/libudev-enumerate.c
+++ b/src/libudev/src/libudev-enumerate.c
@@ -112,7 +112,7 @@ _public_ struct udev_enumerate *udev_enumerate_new(struct udev *udev) {
**/
_public_ struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) {
if (udev_enumerate)
- udev_enumerate->refcount ++;
+ udev_enumerate->refcount++;
return udev_enumerate;
}
diff --git a/src/libudev/src/udev.h b/src/libudev/src/udev.h
index 91dfc950b4..00de88972a 100644
--- a/src/libudev/src/udev.h
+++ b/src/libudev/src/udev.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 2003-2010 Kay Sievers <kay@vrfy.org>
@@ -16,9 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
-
#include <sys/param.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include "libudev.h"
@@ -71,9 +72,9 @@ struct udev_rules;
struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names);
struct udev_rules *udev_rules_unref(struct udev_rules *rules);
bool udev_rules_check_timestamp(struct udev_rules *rules);
-int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event,
- usec_t timeout_usec, usec_t timeout_warn_usec,
- struct udev_list *properties_list);
+void udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event,
+ usec_t timeout_usec, usec_t timeout_warn_usec,
+ struct udev_list *properties_list);
int udev_rules_apply_static_dev_perms(struct udev_rules *rules);
/* udev-event.c */
diff --git a/src/locale/Makefile b/src/locale/Makefile
index cda2d17d4c..ad60553af9 100644
--- a/src/locale/Makefile
+++ b/src/locale/Makefile
@@ -29,7 +29,7 @@ systemd_localed_SOURCES = \
systemd_localed_LDADD = \
libshared.la \
- $(XKBCOMMON_LIBS)
+ -ldl
systemd_localed_CFLAGS = \
$(AM_CFLAGS) \
diff --git a/src/locale/language-fallback-map b/src/locale/language-fallback-map
index 6aadda091a..d0b02a6b98 100644
--- a/src/locale/language-fallback-map
+++ b/src/locale/language-fallback-map
@@ -3,6 +3,10 @@ en_AU en_AU:en_GB
en_IE en_IE:en_GB
en_NZ en_NZ:en_GB
en_ZA en_ZA:en_GB
+fr_BE fr_BE:fr_FR
+fr_CA fr_CA:fr_FR
+fr_CH fr_CH:fr_FR
+fr_LU fr_LU:fr_FR
it_CH it_CH:it_IT
mai_IN mai:hi
nds_DE nds:de
diff --git a/src/locale/localectl.c b/src/locale/localectl.c
index c684ff7d90..c1b0a56346 100644
--- a/src/locale/localectl.c
+++ b/src/locale/localectl.c
@@ -46,14 +46,6 @@ static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
static char *arg_host = NULL;
static bool arg_convert = true;
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
static void polkit_agent_open_if_enabled(void) {
/* Open the polkit agent as a child process if necessary */
@@ -124,11 +116,11 @@ static void print_overridden_variables(void) {
if (variables[j]) {
if (print_warning) {
log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n"
- " Command Line: %s=%s", locale_variable_to_string(j), variables[j]);
+ " Command Line: %s=%s", locale_variable_to_string(j), variables[j]);
print_warning = false;
} else
- log_warning(" %s=%s", locale_variable_to_string(j), variables[j]);
+ log_warning(" %s=%s", locale_variable_to_string(j), variables[j]);
}
finish:
for (j = 0; j < _VARIABLE_LC_MAX; j++)
@@ -139,7 +131,7 @@ static void print_status_info(StatusInfo *i) {
assert(i);
if (strv_isempty(i->locale))
- puts(" System Locale: n/a\n");
+ puts(" System Locale: n/a");
else {
char **j;
@@ -239,7 +231,7 @@ static int list_locales(sd_bus *bus, char **args, unsigned n) {
if (r < 0)
return log_error_errno(r, "Failed to read list of locales: %m");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
strv_print(l);
return 0;
@@ -341,7 +333,7 @@ static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) {
strv_sort(l);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
strv_print(l);
@@ -479,7 +471,7 @@ static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
strv_sort(list);
strv_uniq(list);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
strv_print(list);
return 0;
diff --git a/src/locale/localed.c b/src/locale/localed.c
index eb6c0565f0..7b4cbadfd0 100644
--- a/src/locale/localed.c
+++ b/src/locale/localed.c
@@ -24,6 +24,7 @@
#ifdef HAVE_XKBCOMMON
#include <xkbcommon/xkbcommon.h>
+#include <dlfcn.h>
#endif
#include <systemd/sd-bus.h>
@@ -542,7 +543,7 @@ static int read_next_mapping(const char* filename,
return 0;
}
- (*n) ++;
+ (*n)++;
l = strstrip(line);
if (l[0] == 0 || l[0] == '#')
@@ -1101,6 +1102,7 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro
}
#ifdef HAVE_XKBCOMMON
+
_printf_(3, 0)
static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) {
const char *fmt;
@@ -1109,7 +1111,24 @@ static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char
log_internalv(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, fmt, args);
}
+#define LOAD_SYMBOL(symbol, dl, name) \
+ ({ \
+ (symbol) = (typeof(symbol)) dlvsym((dl), (name), "V_0.5.0"); \
+ (symbol) ? 0 : -EOPNOTSUPP; \
+ })
+
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
+
+ /* We dlopen() the library in order to make the dependency soft. The library (and what it pulls in) is huge
+ * after all, hence let's support XKB maps when the library is around, and refuse otherwise. The function
+ * pointers to the shared library are below: */
+
+ struct xkb_context* (*symbol_xkb_context_new)(enum xkb_context_flags flags) = NULL;
+ void (*symbol_xkb_context_unref)(struct xkb_context *context) = NULL;
+ void (*symbol_xkb_context_set_log_fn)(struct xkb_context *context, void (*log_fn)(struct xkb_context *context, enum xkb_log_level level, const char *format, va_list args)) = NULL;
+ struct xkb_keymap* (*symbol_xkb_keymap_new_from_names)(struct xkb_context *context, const struct xkb_rule_names *names, enum xkb_keymap_compile_flags flags) = NULL;
+ void (*symbol_xkb_keymap_unref)(struct xkb_keymap *keymap) = NULL;
+
const struct xkb_rule_names rmlvo = {
.model = model,
.layout = layout,
@@ -1118,35 +1137,68 @@ static int verify_xkb_rmlvo(const char *model, const char *layout, const char *v
};
struct xkb_context *ctx = NULL;
struct xkb_keymap *km = NULL;
+ void *dl;
int r;
- /* compile keymap from RMLVO information to check out its validity */
+ /* Compile keymap from RMLVO information to check out its validity */
+
+ dl = dlopen("libxkbcommon.so.0", RTLD_LAZY);
+ if (!dl)
+ return -EOPNOTSUPP;
+
+ r = LOAD_SYMBOL(symbol_xkb_context_new, dl, "xkb_context_new");
+ if (r < 0)
+ goto finish;
+
+ r = LOAD_SYMBOL(symbol_xkb_context_unref, dl, "xkb_context_unref");
+ if (r < 0)
+ goto finish;
+
+ r = LOAD_SYMBOL(symbol_xkb_context_set_log_fn, dl, "xkb_context_set_log_fn");
+ if (r < 0)
+ goto finish;
- ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
+ r = LOAD_SYMBOL(symbol_xkb_keymap_new_from_names, dl, "xkb_keymap_new_from_names");
+ if (r < 0)
+ goto finish;
+
+ r = LOAD_SYMBOL(symbol_xkb_keymap_unref, dl, "xkb_keymap_unref");
+ if (r < 0)
+ goto finish;
+
+ ctx = symbol_xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
if (!ctx) {
r = -ENOMEM;
- goto exit;
+ goto finish;
}
- xkb_context_set_log_fn(ctx, log_xkb);
+ symbol_xkb_context_set_log_fn(ctx, log_xkb);
- km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
+ km = symbol_xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!km) {
r = -EINVAL;
- goto exit;
+ goto finish;
}
r = 0;
-exit:
- xkb_keymap_unref(km);
- xkb_context_unref(ctx);
+finish:
+ if (symbol_xkb_keymap_unref && km)
+ symbol_xkb_keymap_unref(km);
+
+ if (symbol_xkb_context_unref && ctx)
+ symbol_xkb_context_unref(ctx);
+
+ (void) dlclose(dl);
return r;
}
+
#else
+
static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) {
return 0;
}
+
#endif
static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) {
@@ -1203,7 +1255,11 @@ static int method_set_x11_keyboard(sd_bus_message *m, void *userdata, sd_bus_err
if (r < 0) {
log_error_errno(r, "Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %m",
strempty(model), strempty(layout), strempty(variant), strempty(options));
- return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot compile XKB keymap, refusing");
+
+ if (r == -EOPNOTSUPP)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Local keyboard configuration not supported on this system.");
+
+ return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Specified keymap cannot be compiled, refusing as invalid.");
}
if (free_and_strdup(&c->x11_layout, layout) < 0 ||
@@ -1296,7 +1352,7 @@ int main(int argc, char *argv[]) {
log_open();
umask(0022);
- mac_selinux_init("/etc");
+ mac_selinux_init();
if (argc != 1) {
log_error("This program takes no arguments.");
diff --git a/src/login/.gitignore b/src/login/.gitignore
index 39088ec252..3a8ba497c1 100644
--- a/src/login/.gitignore
+++ b/src/login/.gitignore
@@ -1,4 +1,5 @@
/logind-gperf.c
+/logind.conf
/org.freedesktop.login1.policy
/71-seat.rules
/73-seat-late.rules
diff --git a/src/login/70-uaccess.rules b/src/login/70-uaccess.rules
index 694df2cfc8..50dcd2e275 100644
--- a/src/login/70-uaccess.rules
+++ b/src/login/70-uaccess.rules
@@ -75,4 +75,7 @@ SUBSYSTEM=="usb", ENV{ID_MEDIA_PLAYER}=="?*", TAG+="uaccess"
# software-defined radio communication devices
ENV{ID_SOFTWARE_RADIO}=="?*", TAG+="uaccess"
+# 3D printers, CNC machines, laser cutters, 3D scanners, etc.
+ENV{ID_MAKER_TOOL}=="?*", TAG+="uaccess"
+
LABEL="uaccess_end"
diff --git a/src/login/Makefile b/src/login/Makefile
index 54353cbbbe..9879cecbd3 100644
--- a/src/login/Makefile
+++ b/src/login/Makefile
@@ -178,7 +178,7 @@ dist_dbussystemservice_DATA += \
dist_dbuspolicy_DATA += \
src/login/org.freedesktop.login1.conf
-dist_pkgsysconf_DATA += \
+nodist_pkgsysconf_DATA += \
src/login/logind.conf
polkitpolicy_files += \
@@ -215,7 +215,8 @@ gperf_gperf_sources += \
EXTRA_DIST += \
src/login/71-seat.rules.in \
src/login/73-seat-late.rules.in \
- units/systemd-logind.service.in
+ units/systemd-logind.service.in \
+ src/login/logind.conf.in
# ------------------------------------------------------------------------------
ifneq ($(HAVE_PAM),)
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index fd8dcdc22c..f3f57b4b13 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -27,6 +27,7 @@
#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
@@ -48,6 +49,7 @@
static char **arg_property = NULL;
static bool arg_all = false;
+static bool arg_value = false;
static bool arg_full = false;
static bool arg_no_pager = false;
static bool arg_legend = true;
@@ -59,14 +61,6 @@ static bool arg_ask_password = true;
static unsigned arg_lines = 10;
static OutputMode arg_output = OUTPUT_SHORT;
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
static void polkit_agent_open_if_enabled(void) {
/* Open the polkit agent as a child process if necessary */
@@ -101,7 +95,7 @@ static int list_sessions(int argc, char *argv[], void *userdata) {
assert(bus);
assert(argv);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = sd_bus_call_method(
bus,
@@ -148,7 +142,7 @@ static int list_users(int argc, char *argv[], void *userdata) {
assert(bus);
assert(argv);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = sd_bus_call_method(
bus,
@@ -194,7 +188,7 @@ static int list_seats(int argc, char *argv[], void *userdata) {
assert(bus);
assert(argv);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = sd_bus_call_method(
bus,
@@ -234,18 +228,15 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *path = NULL;
const char *cgroup;
- int r;
unsigned c;
+ int r;
assert(bus);
assert(unit);
- if (arg_transport != BUS_TRANSPORT_LOCAL)
- return 0;
-
path = unit_dbus_path_from_name(unit);
if (!path)
- return -ENOMEM;
+ return log_oom();
r = sd_bus_get_property(
bus,
@@ -253,27 +244,40 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
path,
interface,
"ControlGroup",
- &error, &reply, "s");
+ &error,
+ &reply,
+ "s");
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &cgroup);
if (r < 0)
- return r;
+ return bus_log_parse_error(r);
if (isempty(cgroup))
return 0;
- if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
- return 0;
-
c = columns();
if (c > 18)
c -= 18;
else
c = 0;
- show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
+ r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
+ if (r == -EBADR) {
+
+ if (arg_transport == BUS_TRANSPORT_REMOTE)
+ return 0;
+
+ /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
+
+ if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
+ return 0;
+
+ show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
+ } else if (r < 0)
+ return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
+
return 0;
}
@@ -300,6 +304,7 @@ typedef struct SessionStatusInfo {
typedef struct UserStatusInfo {
uid_t uid;
+ bool linger;
char *name;
struct dual_timestamp timestamp;
char *state;
@@ -558,6 +563,7 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(UserStatusInfo, name) },
+ { "Linger", "b", NULL, offsetof(UserStatusInfo, linger) },
{ "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
{ "State", "s", NULL, offsetof(UserStatusInfo, state) },
{ "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
@@ -602,16 +608,16 @@ static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line)
char **l;
printf("\tSessions:");
- STRV_FOREACH(l, i.sessions) {
- if (streq_ptr(*l, i.display))
- printf(" *%s", *l);
- else
- printf(" %s", *l);
- }
+ STRV_FOREACH(l, i.sessions)
+ printf(" %s%s",
+ streq_ptr(*l, i.display) ? "*" : "",
+ *l);
printf("\n");
}
+ printf("\t Linger: %s\n", yes_no(i.linger));
+
if (i.slice) {
printf("\t Unit: %s\n", i.slice);
show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
@@ -687,6 +693,14 @@ static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line)
return 0;
}
+#define property(name, fmt, ...) \
+ do { \
+ if (arg_value) \
+ printf(fmt "\n", __VA_ARGS__); \
+ else \
+ printf("%s=" fmt "\n", name, __VA_ARGS__); \
+ } while(0)
+
static int print_property(const char *name, sd_bus_message *m, const char *contents) {
int r;
@@ -710,7 +724,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
if (arg_all || !isempty(s))
- printf("%s=%s\n", name, s);
+ property(name, "%s", s);
return 0;
@@ -726,8 +740,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return -EINVAL;
}
- printf("%s=" UID_FMT "\n", name, uid);
-
+ property(name, UID_FMT, uid);
return 0;
}
@@ -743,14 +756,16 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
if (r < 0)
return bus_log_parse_error(r);
- printf("%s=", name);
+ if (!arg_value)
+ printf("%s=", name);
while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
printf("%s%s", space ? " " : "", s);
space = true;
}
- printf("\n");
+ if (space || !arg_value)
+ printf("\n");
if (r < 0)
return bus_log_parse_error(r);
@@ -765,7 +780,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
break;
}
- r = bus_print_property(name, m, arg_all);
+ r = bus_print_property(name, m, arg_value, arg_all);
if (r < 0)
return bus_log_parse_error(r);
@@ -858,7 +873,7 @@ static int show_session(int argc, char *argv[], void *userdata) {
properties = !strstr(argv[0], "status");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (argc <= 1) {
/* If not argument is specified inspect the manager
@@ -914,7 +929,7 @@ static int show_user(int argc, char *argv[], void *userdata) {
properties = !strstr(argv[0], "status");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (argc <= 1) {
/* If not argument is specified inspect the manager
@@ -974,7 +989,7 @@ static int show_seat(int argc, char *argv[], void *userdata) {
properties = !strstr(argv[0], "status");
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (argc <= 1) {
/* If not argument is specified inspect the manager
@@ -1338,6 +1353,7 @@ static int help(int argc, char *argv[], void *userdata) {
" -M --machine=CONTAINER Operate on local container\n"
" -p --property=NAME Show only properties by this name\n"
" -a --all Show all properties, including empty ones\n"
+ " --value When showing properties, only print the value\n"
" -l --full Do not ellipsize output\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
@@ -1379,6 +1395,7 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
+ ARG_VALUE,
ARG_NO_PAGER,
ARG_NO_LEGEND,
ARG_KILL_WHO,
@@ -1390,6 +1407,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "version", no_argument, NULL, ARG_VERSION },
{ "property", required_argument, NULL, 'p' },
{ "all", no_argument, NULL, 'a' },
+ { "value", no_argument, NULL, ARG_VALUE },
{ "full", no_argument, NULL, 'l' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
@@ -1435,6 +1453,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_all = true;
break;
+ case ARG_VALUE:
+ arg_value = true;
+ break;
+
case 'l':
arg_full = true;
break;
diff --git a/src/login/logind-core.c b/src/login/logind-core.c
index 8bdb3a9a38..cbf8d757fe 100644
--- a/src/login/logind-core.c
+++ b/src/login/logind-core.c
@@ -364,16 +364,16 @@ bool manager_shall_kill(Manager *m, const char *user) {
assert(m);
assert(user);
- if (!m->kill_user_processes)
+ if (!m->kill_exclude_users && streq(user, "root"))
return false;
if (strv_contains(m->kill_exclude_users, user))
return false;
- if (strv_isempty(m->kill_only_users))
- return true;
+ if (!strv_isempty(m->kill_only_users))
+ return strv_contains(m->kill_only_users, user);
- return strv_contains(m->kill_only_users, user);
+ return m->kill_user_processes;
}
static int vt_is_busy(unsigned int vtnr) {
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index efcc386dce..90dcd94710 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -265,6 +265,42 @@ static int property_get_docked(
return sd_bus_message_append(reply, "b", manager_is_docked_or_external_displays(m));
}
+static int property_get_current_sessions(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->sessions));
+}
+
+static int property_get_current_inhibitors(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Manager *m = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(m);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) hashmap_size(m->inhibitors));
+}
+
static int method_get_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *p = NULL;
Manager *m = userdata;
@@ -725,6 +761,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
m->seat0->positions[vtnr]->class != SESSION_GREETER)
return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
+ if (hashmap_size(m->sessions) >= m->sessions_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max);
+
audit_session_from_pid(leader, &audit_id);
if (audit_id > 0) {
/* Keep our session IDs and the audit session IDs in sync */
@@ -1077,11 +1116,11 @@ static int method_terminate_seat(sd_bus_message *message, void *userdata, sd_bus
static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *cc = NULL;
Manager *m = userdata;
- int b, r;
+ int r, b, interactive;
struct passwd *pw;
const char *path;
uint32_t uid;
- int interactive;
+ bool self = false;
assert(message);
assert(m);
@@ -1102,6 +1141,8 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
if (r < 0)
return r;
+ self = true;
+
} else if (!uid_is_valid(uid))
return -EINVAL;
@@ -1113,7 +1154,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
r = bus_verify_polkit_async(
message,
CAP_SYS_ADMIN,
- "org.freedesktop.login1.set-user-linger",
+ self ? "org.freedesktop.login1.set-self-linger" : "org.freedesktop.login1.set-user-linger",
NULL,
interactive,
UID_INVALID,
@@ -2440,6 +2481,9 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
if (r < 0)
return r;
+ if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max);
+
do {
id = mfree(id);
@@ -2510,6 +2554,13 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_PROPERTY("PreparingForSleep", "b", property_get_preparing, 0, 0),
SD_BUS_PROPERTY("ScheduledShutdown", "(st)", property_get_scheduled_shutdown, 0, 0),
SD_BUS_PROPERTY("Docked", "b", property_get_docked, 0, 0),
+ SD_BUS_PROPERTY("RemoveIPC", "b", bus_property_get_bool, offsetof(Manager, remove_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RuntimeDirectorySize", "t", bus_property_get_size, offsetof(Manager, runtime_dir_size), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("InhibitorsMax", "t", NULL, offsetof(Manager, inhibitors_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentInhibitors", "t", property_get_current_inhibitors, 0, 0),
+ SD_BUS_PROPERTY("SessionsMax", "t", NULL, offsetof(Manager, sessions_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NCurrentSessions", "t", property_get_current_sessions, 0, 0),
+ SD_BUS_PROPERTY("UserTasksMax", "t", NULL, offsetof(Manager, user_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetSession", "s", "o", method_get_session, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetSessionByPID", "u", "o", method_get_session_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf
index 8552c464cc..6bd08adc05 100644
--- a/src/login/logind-gperf.gperf
+++ b/src/login/logind-gperf.gperf
@@ -34,4 +34,6 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag
Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec)
Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size)
Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc)
+Login.InhibitorsMax, config_parse_uint64, 0, offsetof(Manager, inhibitors_max)
+Login.SessionsMax, config_parse_uint64, 0, offsetof(Manager, sessions_max)
Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max)
diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c
index a0e3ba2b7c..6c78e0dddc 100644
--- a/src/login/logind-inhibit.c
+++ b/src/login/logind-inhibit.c
@@ -317,7 +317,7 @@ int inhibitor_create_fifo(Inhibitor *i) {
if (r < 0)
return r;
- r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
+ r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10);
if (r < 0)
return r;
}
diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c
index 3cee10d009..f934a5326a 100644
--- a/src/login/logind-seat-dbus.c
+++ b/src/login/logind-seat-dbus.c
@@ -306,7 +306,7 @@ const sd_bus_vtable seat_vtable[] = {
SD_BUS_PROPERTY("CanMultiSession", "b", property_get_can_multi_session, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanTTY", "b", property_get_can_tty, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CanGraphical", "b", property_get_can_graphical, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c
index ff9170683b..22dea5db1f 100644
--- a/src/login/logind-session-dbus.c
+++ b/src/login/logind-session-dbus.c
@@ -28,6 +28,7 @@
#include "logind-session-device.h"
#include "logind-session.h"
#include "logind.h"
+#include "signal-util.h"
#include "strv.h"
#include "util.h"
@@ -179,6 +180,24 @@ static int property_get_idle_since_hint(
return sd_bus_message_append(reply, "t", u);
}
+static int property_get_locked_hint(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Session *s = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(s);
+
+ return sd_bus_message_append(reply, "b", session_get_locked_hint(s) > 0);
+}
+
int bus_session_method_terminate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
int r;
@@ -278,6 +297,35 @@ static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_reply_method_return(message, NULL);
}
+static int method_set_locked_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
+ Session *s = userdata;
+ uid_t uid;
+ int r, b;
+
+ assert(message);
+ assert(s);
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_creds_get_euid(creds, &uid);
+ if (r < 0)
+ return r;
+
+ if (uid != 0 && uid != s->user->uid)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Only owner of session may set locked hint");
+
+ session_set_locked_hint(s, b);
+
+ return sd_bus_reply_method_return(message, NULL);
+}
+
int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Session *s = userdata;
const char *swho;
@@ -300,7 +348,7 @@ int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
}
- if (signo <= 0 || signo >= _NSIG)
+ if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
r = bus_verify_polkit_async(
@@ -486,12 +534,14 @@ const sd_bus_vtable session_vtable[] = {
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("LockedHint", "b", property_get_locked_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_METHOD("Terminate", NULL, NULL, bus_session_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Activate", NULL, NULL, bus_session_method_activate, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Lock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unlock", NULL, NULL, bus_session_method_lock, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetIdleHint", "b", NULL, method_set_idle_hint, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("SetLockedHint", "b", NULL, method_set_locked_hint, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Kill", "si", NULL, bus_session_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("TakeControl", "b", NULL, method_take_control, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ReleaseControl", NULL, NULL, method_release_control, SD_BUS_VTABLE_UNPRIVILEGED),
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index b22420deea..11a83106b1 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -446,17 +446,10 @@ int session_load(Session *s) {
safe_close(fd);
}
- if (realtime) {
- unsigned long long l;
- if (sscanf(realtime, "%llu", &l) > 0)
- s->timestamp.realtime = l;
- }
-
- if (monotonic) {
- unsigned long long l;
- if (sscanf(monotonic, "%llu", &l) > 0)
- s->timestamp.monotonic = l;
- }
+ if (realtime)
+ timestamp_deserialize(realtime, &s->timestamp.realtime);
+ if (monotonic)
+ timestamp_deserialize(monotonic, &s->timestamp.monotonic);
if (controller) {
if (bus_name_has_owner(s->manager->bus, controller, NULL) > 0)
@@ -520,7 +513,7 @@ static int session_start_scope(Session *s) {
if (!scope)
return log_oom();
- description = strjoina("Session ", s->id, " of user ", s->user->name, NULL);
+ description = strjoina("Session ", s->id, " of user ", s->user->name);
r = manager_start_scope(
s->manager,
@@ -804,7 +797,7 @@ int session_get_idle_hint(Session *s, dual_timestamp *t) {
/* Graphical sessions should really implement a real
* idle hint logic */
- if (s->display)
+ if (SESSION_TYPE_IS_GRAPHICAL(s->type))
goto dont_know;
/* For sessions with an explicitly configured tty, let's check
@@ -859,6 +852,23 @@ void session_set_idle_hint(Session *s, bool b) {
manager_send_changed(s->manager, "IdleHint", "IdleSinceHint", "IdleSinceHintMonotonic", NULL);
}
+int session_get_locked_hint(Session *s) {
+ assert(s);
+
+ return s->locked_hint;
+}
+
+void session_set_locked_hint(Session *s, bool b) {
+ assert(s);
+
+ if (s->locked_hint == b)
+ return;
+
+ s->locked_hint = b;
+
+ session_send_changed(s, "LockedHint", NULL);
+}
+
static int session_dispatch_fifo(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
Session *s = userdata;
@@ -904,7 +914,9 @@ int session_create_fifo(Session *s) {
if (r < 0)
return r;
- r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_IDLE);
+ /* Let's make sure we noticed dead sessions before we process new bus requests (which might create new
+ * sessions). */
+ r = sd_event_source_set_priority(s->fifo_event_source, SD_EVENT_PRIORITY_NORMAL-10);
if (r < 0)
return r;
}
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index e24b808474..ffb7cd2d41 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -105,6 +105,8 @@ struct Session {
bool idle_hint;
dual_timestamp idle_hint_timestamp;
+ bool locked_hint;
+
bool in_gc_queue:1;
bool started:1;
bool stopping:1;
@@ -132,6 +134,8 @@ int session_activate(Session *s);
bool session_is_active(Session *s);
int session_get_idle_hint(Session *s, dual_timestamp *t);
void session_set_idle_hint(Session *s, bool b);
+int session_get_locked_hint(Session *s);
+void session_set_locked_hint(Session *s, bool b);
int session_create_fifo(Session *s);
int session_start(Session *s);
int session_stop(Session *s, bool force);
diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c
index fd98c7beca..af6392e025 100644
--- a/src/login/logind-user-dbus.c
+++ b/src/login/logind-user-dbus.c
@@ -25,6 +25,7 @@
#include "formats-util.h"
#include "logind-user.h"
#include "logind.h"
+#include "signal-util.h"
#include "strv.h"
#include "user-util.h"
@@ -222,7 +223,7 @@ int bus_user_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *
if (r < 0)
return r;
- if (signo <= 0 || signo >= _NSIG)
+ if (!SIGNAL_VALID(signo))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
r = user_kill(u, signo);
@@ -244,7 +245,7 @@ const sd_bus_vtable user_vtable[] = {
SD_BUS_PROPERTY("Slice", "s", NULL, offsetof(User, slice), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Display", "(so)", property_get_display, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
- SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Sessions", "a(so)", property_get_sessions, 0, 0),
SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/login/logind-user.c b/src/login/logind-user.c
index 6b9c69cc45..a826321bf0 100644
--- a/src/login/logind-user.c
+++ b/src/login/logind-user.c
@@ -321,17 +321,10 @@ int user_load(User *u) {
if (s && s->display && display_is_local(s->display))
u->display = s;
- if (realtime) {
- unsigned long long l;
- if (sscanf(realtime, "%llu", &l) > 0)
- u->timestamp.realtime = l;
- }
-
- if (monotonic) {
- unsigned long long l;
- if (sscanf(monotonic, "%llu", &l) > 0)
- u->timestamp.monotonic = l;
- }
+ if (realtime)
+ timestamp_deserialize(realtime, &u->timestamp.realtime);
+ if (monotonic)
+ timestamp_deserialize(monotonic, &u->timestamp.monotonic);
return r;
}
diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c
index 5106821645..47599fd466 100644
--- a/src/login/logind-utmp.c
+++ b/src/login/logind-utmp.c
@@ -65,7 +65,7 @@ bool logind_wall_tty_filter(const char *tty, void *userdata) {
assert(m);
- if (!startswith(tty, "/dev/"))
+ if (!startswith(tty, "/dev/") || !m->scheduled_shutdown_tty)
return true;
return !streq(tty + 5, m->scheduled_shutdown_tty);
diff --git a/src/login/logind.c b/src/login/logind.c
index 34d0c04a2a..925c04a344 100644
--- a/src/login/logind.c
+++ b/src/login/logind.c
@@ -41,17 +41,7 @@
static void manager_free(Manager *m);
-static Manager *manager_new(void) {
- Manager *m;
- int r;
-
- m = new0(Manager, 1);
- if (!m)
- return NULL;
-
- m->console_active_fd = -1;
- m->reserve_vt_fd = -1;
-
+static void manager_reset_config(Manager *m) {
m->n_autovts = 6;
m->reserve_vt = 6;
m->remove_ipc = true;
@@ -61,15 +51,39 @@ static Manager *manager_new(void) {
m->handle_hibernate_key = HANDLE_HIBERNATE;
m->handle_lid_switch = HANDLE_SUSPEND;
m->handle_lid_switch_docked = HANDLE_IGNORE;
+ m->power_key_ignore_inhibited = false;
+ m->suspend_key_ignore_inhibited = false;
+ m->hibernate_key_ignore_inhibited = false;
m->lid_switch_ignore_inhibited = true;
+
m->holdoff_timeout_usec = 30 * USEC_PER_SEC;
m->idle_action_usec = 30 * USEC_PER_MINUTE;
m->idle_action = HANDLE_IGNORE;
- m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */
- m->user_tasks_max = UINT64_C(12288);
+ m->user_tasks_max = 12288;
+ m->sessions_max = 8192;
+ m->inhibitors_max = 8192;
+
+ m->kill_user_processes = KILL_USER_PROCESSES;
+
+ m->kill_only_users = strv_free(m->kill_only_users);
+ m->kill_exclude_users = strv_free(m->kill_exclude_users);
+}
+
+static Manager *manager_new(void) {
+ Manager *m;
+ int r;
+
+ m = new0(Manager, 1);
+ if (!m)
+ return NULL;
+
+ m->console_active_fd = -1;
+ m->reserve_vt_fd = -1;
+
+ m->idle_action_not_before_usec = now(CLOCK_MONOTONIC);
m->devices = hashmap_new(&string_hash_ops);
m->seats = hashmap_new(&string_hash_ops);
@@ -84,10 +98,6 @@ static Manager *manager_new(void) {
if (!m->devices || !m->seats || !m->sessions || !m->users || !m->inhibitors || !m->buttons || !m->user_units || !m->session_units)
goto fail;
- m->kill_exclude_users = strv_new("root", NULL);
- if (!m->kill_exclude_users)
- goto fail;
-
m->udev = udev_new();
if (!m->udev)
goto fail;
@@ -98,6 +108,8 @@ static Manager *manager_new(void) {
sd_event_set_watchdog(m->event, true);
+ manager_reset_config(m);
+
return m;
fail:
@@ -676,7 +688,7 @@ static int manager_connect_bus(Manager *m) {
if (r < 0)
return log_error_errno(r, "Failed to register name: %m");
- r = sd_bus_attach_event(m->bus, m->event, 0);
+ r = sd_bus_attach_event(m->bus, m->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
@@ -986,6 +998,30 @@ static int manager_dispatch_idle_action(sd_event_source *s, uint64_t t, void *us
return 0;
}
+static int manager_parse_config_file(Manager *m) {
+ assert(m);
+
+ return config_parse_many(PKGSYSCONFDIR "/logind.conf",
+ CONF_PATHS_NULSTR("systemd/logind.conf.d"),
+ "Login\0",
+ config_item_perf_lookup, logind_gperf_lookup,
+ false, m);
+}
+
+static int manager_dispatch_reload_signal(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+ Manager *m = userdata;
+ int r;
+
+ manager_reset_config(m);
+ r = manager_parse_config_file(m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse config file, using defaults: %m");
+ else
+ log_info("Config file reloaded.");
+
+ return 0;
+}
+
static int manager_startup(Manager *m) {
int r;
Seat *seat;
@@ -997,6 +1033,12 @@ static int manager_startup(Manager *m) {
assert(m);
+ assert_se(sigprocmask_many(SIG_SETMASK, NULL, SIGHUP, -1) >= 0);
+
+ r = sd_event_add_signal(m->event, NULL, SIGHUP, manager_dispatch_reload_signal, m);
+ if (r < 0)
+ return log_error_errno(r, "Failed to register SIGHUP handler: %m");
+
/* Connect to console */
r = manager_connect_console(m);
if (r < 0)
@@ -1099,16 +1141,6 @@ static int manager_run(Manager *m) {
}
}
-static int manager_parse_config_file(Manager *m) {
- assert(m);
-
- return config_parse_many(PKGSYSCONFDIR "/logind.conf",
- CONF_PATHS_NULSTR("systemd/logind.conf.d"),
- "Login\0",
- config_item_perf_lookup, logind_gperf_lookup,
- false, m);
-}
-
int main(int argc, char *argv[]) {
Manager *m = NULL;
int r;
@@ -1126,7 +1158,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- r = mac_selinux_init("/run");
+ r = mac_selinux_init();
if (r < 0) {
log_error_errno(r, "Could not initialize labelling: %m");
goto finish;
diff --git a/src/login/logind.conf b/src/login/logind.conf.in
index 6095e482ac..32c0844cb6 100644
--- a/src/login/logind.conf
+++ b/src/login/logind.conf.in
@@ -14,7 +14,7 @@
[Login]
#NAutoVTs=6
#ReserveVT=6
-#KillUserProcesses=no
+#KillUserProcesses=@KILL_USER_PROCESSES@
#KillOnlyUsers=
#KillExcludeUsers=root
#InhibitDelayMaxSec=5
@@ -32,4 +32,6 @@
#IdleActionSec=30min
#RuntimeDirectorySize=10%
#RemoveIPC=yes
+#InhibitorsMax=8192
+#SessionsMax=8192
#UserTasksMax=12288
diff --git a/src/login/logind.h b/src/login/logind.h
index c642d56413..9d43c2e7ee 100644
--- a/src/login/logind.h
+++ b/src/login/logind.h
@@ -133,6 +133,8 @@ struct Manager {
size_t runtime_dir_size;
uint64_t user_tasks_max;
+ uint64_t sessions_max;
+ uint64_t inhibitors_max;
};
int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device);
diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf
index 1662d4c428..c89e40457e 100644
--- a/src/login/org.freedesktop.login1.conf
+++ b/src/login/org.freedesktop.login1.conf
@@ -234,6 +234,10 @@
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Session"
+ send_member="SetLockedHint"/>
+
+ <allow send_destination="org.freedesktop.login1"
+ send_interface="org.freedesktop.login1.Session"
send_member="Kill"/>
<allow send_destination="org.freedesktop.login1"
diff --git a/src/login/org.freedesktop.login1.policy.in b/src/login/org.freedesktop.login1.policy.in
index 23326bb79f..1fa6441629 100644
--- a/src/login/org.freedesktop.login1.policy.in
+++ b/src/login/org.freedesktop.login1.policy.in
@@ -111,6 +111,14 @@
</defaults>
</action>
+ <action id="org.freedesktop.login1.set-self-linger">
+ <_description>Allow non-logged-in user to run programs</_description>
+ <_message>Explicit request is required to run programs as a non-logged-in user.</_message>
+ <defaults>
+ <allow_any>yes</allow_any>
+ </defaults>
+ </action>
+
<action id="org.freedesktop.login1.set-user-linger">
<_description>Allow non-logged-in users to run programs</_description>
<_message>Authentication is required to run programs as a non-logged-in user.</_message>
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 40e246bb06..98dc201340 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -150,7 +150,7 @@ static int get_seat_from_display(const char *display, const char **seat, uint32_
if (fd < 0)
return -errno;
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0)
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return -errno;
r = getpeercred(fd, &ucred);
diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c
index bd603e297d..29785e2f11 100644
--- a/src/login/sysfs-show.c
+++ b/src/login/sysfs-show.c
@@ -110,7 +110,7 @@ static int show_sysfs_one(
if (!k)
return -ENOMEM;
- printf("%s%s%s\n", prefix, draw_special_char(lookahead ? DRAW_TREE_BRANCH : DRAW_TREE_RIGHT), k);
+ printf("%s%s%s\n", prefix, special_glyph(lookahead ? TREE_BRANCH : TREE_RIGHT), k);
if (asprintf(&l,
"%s%s:%s%s%s%s",
@@ -124,13 +124,13 @@ static int show_sysfs_one(
if (!k)
return -ENOMEM;
- printf("%s%s%s\n", prefix, lookahead ? draw_special_char(DRAW_TREE_VERTICAL) : " ", k);
+ printf("%s%s%s\n", prefix, lookahead ? special_glyph(TREE_VERTICAL) : " ", k);
*item = next;
if (*item) {
_cleanup_free_ char *p = NULL;
- p = strappend(prefix, lookahead ? draw_special_char(DRAW_TREE_VERTICAL) : " ");
+ p = strappend(prefix, lookahead ? special_glyph(TREE_VERTICAL) : " ");
if (!p)
return -ENOMEM;
@@ -183,7 +183,7 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) {
if (first)
show_sysfs_one(udev, seat, &first, "/", prefix, n_columns);
else
- printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), "(none)");
+ printf("%s%s%s\n", prefix, special_glyph(TREE_RIGHT), "(none)");
return r;
}
diff --git a/src/login/systemd-user.m4 b/src/login/systemd-user.m4
index 7933508f2b..f188a8e548 100644
--- a/src/login/systemd-user.m4
+++ b/src/login/systemd-user.m4
@@ -8,4 +8,5 @@ m4_ifdef(`HAVE_SELINUX',
session required pam_selinux.so close
session required pam_selinux.so nottys open
)m4_dnl
+session required pam_loginuid.so
session include system-auth
diff --git a/src/network/.gitignore b/src/network/.gitignore
index 8858596489..aca55206b7 100644
--- a/src/network/.gitignore
+++ b/src/network/.gitignore
@@ -1,2 +1,3 @@
/networkd-network-gperf.c
/networkd-netdev-gperf.c
+/networkd-gperf.c
diff --git a/src/network/Makefile b/src/network/Makefile
index 3453a9c56d..d43dfdfca8 100644
--- a/src/network/Makefile
+++ b/src/network/Makefile
@@ -47,6 +47,8 @@ libnetworkd_core_la_CFLAGS = \
libnetworkd_core_la_SOURCES = \
src/libsystemd-network/network-internal.h \
src/network/networkd.h \
+ src/network/networkd-conf.h \
+ src/network/networkd-conf.c \
src/network/networkd-link.h \
src/network/networkd-link.c \
src/network/networkd-netdev.h \
@@ -90,9 +92,12 @@ libnetworkd_core_la_SOURCES = \
src/network/networkd-address-pool.h \
src/network/networkd-address-pool.c \
src/network/networkd-util.h \
- src/network/networkd-util.c
+ src/network/networkd-util.c \
+ src/network/networkd-lldp-tx.h \
+ src/network/networkd-lldp-tx.c
nodist_libnetworkd_core_la_SOURCES = \
+ src/network/networkd-gperf.c \
src/network/networkd-network-gperf.c \
src/network/networkd-netdev-gperf.c
@@ -131,6 +136,12 @@ networkctl_LDADD = \
dist_bashcompletion_data += \
shell-completion/bash/networkctl
+test_networkd_conf_SOURCES = \
+ src/network/test-networkd-conf.c
+
+test_networkd_conf_LDADD = \
+ libnetworkd-core.la
+
test_network_SOURCES = \
src/network/test-network.c
@@ -156,6 +167,7 @@ test_network_tables_LDADD += \
endif # HAVE_LIBIPTC
tests += \
+ test-networkd-conf \
test-network \
test-network-tables
@@ -189,6 +201,7 @@ BUSNAMES_TARGET_WANTS += \
endif # ENABLE_NETWORKD
gperf_gperf_sources += \
+ src/network/networkd-gperf.gperf \
src/network/networkd-network-gperf.gperf \
src/network/networkd-netdev-gperf.gperf
diff --git a/src/network/networkctl.c b/src/network/networkctl.c
index 6e436d2043..85635b59bc 100644
--- a/src/network/networkctl.c
+++ b/src/network/networkctl.c
@@ -23,6 +23,7 @@
#include <systemd/sd-device.h>
#include <systemd/sd-hwdb.h>
+#include <systemd/sd-lldp.h>
#include <systemd/sd-netlink.h>
#include <systemd/sd-network.h>
@@ -30,18 +31,20 @@
#include "arphrd-list.h"
#include "device-util.h"
#include "ether-addr-util.h"
+#include "fd-util.h"
#include "hwdb-util.h"
-#include "lldp.h"
#include "local-addresses.h"
#include "locale-util.h"
#include "netlink-util.h"
#include "pager.h"
#include "parse-util.h"
#include "socket-util.h"
+#include "sparse-endian.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
+#include "strxcpyx.h"
#include "terminal-util.h"
#include "util.h"
#include "verbs.h"
@@ -50,15 +53,7 @@ static bool arg_no_pager = false;
static bool arg_legend = true;
static bool arg_all = false;
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
-static int link_get_type_string(int iftype, sd_device *d, char **ret) {
+static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) {
const char *t;
char *p;
@@ -70,7 +65,7 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) {
* to show a more useful type string for
* them */
- (void)sd_device_get_devtype(d, &devtype);
+ (void) sd_device_get_devtype(d, &devtype);
if (streq_ptr(devtype, "wlan"))
id = "wlan";
@@ -103,10 +98,46 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) {
return 0;
}
+static void operational_state_to_color(const char *state, const char **on, const char **off) {
+ assert(on);
+ assert(off);
+
+ if (streq_ptr(state, "routable")) {
+ *on = ansi_highlight_green();
+ *off = ansi_normal();
+ } else if (streq_ptr(state, "degraded")) {
+ *on = ansi_highlight_yellow();
+ *off = ansi_normal();
+ } else
+ *on = *off = "";
+}
+
+static void setup_state_to_color(const char *state, const char **on, const char **off) {
+ assert(on);
+ assert(off);
+
+ if (streq_ptr(state, "configured")) {
+ *on = ansi_highlight_green();
+ *off = ansi_normal();
+ } else if (streq_ptr(state, "configuring")) {
+ *on = ansi_highlight_yellow();
+ *off = ansi_normal();
+ } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
+ *on = ansi_highlight_red();
+ *off = ansi_normal();
+ } else
+ *on = *off = "";
+}
+
typedef struct LinkInfo {
- const char *name;
+ char name[IFNAMSIZ+1];
int ifindex;
- unsigned iftype;
+ unsigned short iftype;
+ struct ether_addr mac_address;
+ uint32_t mtu;
+
+ bool has_mac_address:1;
+ bool has_mtu:1;
} LinkInfo;
static int link_info_compare(const void *a, const void *b) {
@@ -115,44 +146,84 @@ static int link_info_compare(const void *a, const void *b) {
return x->ifindex - y->ifindex;
}
-static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) {
+static int decode_link(sd_netlink_message *m, LinkInfo *info) {
+ const char *name;
+ uint16_t type;
+ int r;
+
+ assert(m);
+ assert(info);
+
+ r = sd_netlink_message_get_type(m, &type);
+ if (r < 0)
+ return r;
+
+ if (type != RTM_NEWLINK)
+ return 0;
+
+ r = sd_rtnl_message_link_get_ifindex(m, &info->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_read_string(m, IFLA_IFNAME, &name);
+ if (r < 0)
+ return r;
+
+ r = sd_rtnl_message_link_get_type(m, &info->iftype);
+ if (r < 0)
+ return r;
+
+ strscpy(info->name, sizeof info->name, name);
+
+ info->has_mac_address =
+ sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
+ memcmp(&info->mac_address, &ETHER_ADDR_NULL, sizeof(struct ether_addr)) != 0;
+
+ info->has_mtu =
+ sd_netlink_message_read_u32(m, IFLA_MTU, &info->mtu) &&
+ info->mtu > 0;
+
+ return 1;
+}
+
+static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) {
_cleanup_free_ LinkInfo *links = NULL;
- size_t size = 0, c = 0;
- sd_netlink_message *i;
+ char **i;
+ size_t c = 0;
int r;
- for (i = m; i; i = sd_netlink_message_next(i)) {
- const char *name;
- unsigned iftype;
- uint16_t type;
- int ifindex;
+ assert(rtnl);
+ assert(ret);
- r = sd_netlink_message_get_type(i, &type);
- if (r < 0)
- return r;
+ links = new(LinkInfo, strv_length(l));
+ if (!links)
+ return log_oom();
- if (type != RTM_NEWLINK)
- continue;
+ STRV_FOREACH(i, l) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
+ int ifindex;
+
+ if (parse_ifindex(*i, &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);
+ if (r < 0)
+ return rtnl_log_create_error(r);
- r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
+ r = sd_netlink_message_append_string(req, IFLA_IFNAME, *i);
+ }
if (r < 0)
- return r;
+ return rtnl_log_create_error(r);
- r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
+ r = sd_netlink_call(rtnl, req, 0, &reply);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to request link: %m");
- r = sd_rtnl_message_link_get_type(i, &iftype);
+ r = decode_link(reply, links + c);
if (r < 0)
return r;
-
- if (!GREEDY_REALLOC(links, size, c+1))
- return -ENOMEM;
-
- links[c].name = name;
- links[c].ifindex = ifindex;
- links[c].iftype = iftype;
- c++;
+ if (r > 0)
+ c++;
}
qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
@@ -163,48 +234,15 @@ static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) {
return (int) c;
}
-static void operational_state_to_color(const char *state, const char **on, const char **off) {
- assert(on);
- assert(off);
-
- if (streq_ptr(state, "routable")) {
- *on = ansi_highlight_green();
- *off = ansi_normal();
- } else if (streq_ptr(state, "degraded")) {
- *on = ansi_highlight_yellow();
- *off = ansi_normal();
- } else
- *on = *off = "";
-}
-
-static void setup_state_to_color(const char *state, const char **on, const char **off) {
- assert(on);
- assert(off);
-
- if (streq_ptr(state, "configured")) {
- *on = ansi_highlight_green();
- *off = ansi_normal();
- } else if (streq_ptr(state, "configuring")) {
- *on = ansi_highlight_yellow();
- *off = ansi_normal();
- } else if (streq_ptr(state, "failed") || streq_ptr(state, "linger")) {
- *on = ansi_highlight_red();
- *off = ansi_normal();
- } else
- *on = *off = "";
-}
-
-static int list_links(int argc, char *argv[], void *userdata) {
+static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_free_ LinkInfo *links = NULL;
- int r, c, i;
-
- pager_open_if_enabled();
+ size_t allocated = 0, c = 0;
+ sd_netlink_message *i;
+ int r;
- r = sd_netlink_open(&rtnl);
- if (r < 0)
- return log_error_errno(r, "Failed to connect to netlink: %m");
+ assert(rtnl);
+ assert(ret);
r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
if (r < 0)
@@ -218,12 +256,50 @@ static int list_links(int argc, char *argv[], void *userdata) {
if (r < 0)
return log_error_errno(r, "Failed to enumerate links: %m");
- if (arg_legend)
- printf("%3s %-16s %-18s %-11s %-10s\n", "IDX", "LINK", "TYPE", "OPERATIONAL", "SETUP");
+ for (i = reply; i; i = sd_netlink_message_next(i)) {
+ if (!GREEDY_REALLOC(links, allocated, c+1))
+ return -ENOMEM;
+
+ r = decode_link(i, links + c);
+ if (r < 0)
+ return r;
+ if (r > 0)
+ c++;
+ }
- c = decode_and_sort_links(reply, &links);
+ qsort_safe(links, c, sizeof(LinkInfo), link_info_compare);
+
+ *ret = links;
+ links = NULL;
+
+ return (int) c;
+}
+
+static int list_links(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_free_ LinkInfo *links = NULL;
+ int c, i, r;
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
+
+ if (argc > 1)
+ c = acquire_link_info_strv(rtnl, argv + 1, &links);
+ else
+ c = acquire_link_info_all(rtnl, &links);
if (c < 0)
- return rtnl_log_parse_error(c);
+ return c;
+
+ pager_open(arg_no_pager, false);
+
+ if (arg_legend)
+ printf("%3s %-16s %-18s %-11s %-10s\n",
+ "IDX",
+ "LINK",
+ "TYPE",
+ "OPERATIONAL",
+ "SETUP");
for (i = 0; i < c; i++) {
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL;
@@ -233,16 +309,18 @@ static int list_links(int argc, char *argv[], void *userdata) {
char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL;
- sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
+ (void) sd_network_link_get_operational_state(links[i].ifindex, &operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
+ r = sd_network_link_get_setup_state(links[i].ifindex, &setup_state);
+ if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
+ setup_state = strdup("unmanaged");
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
- sprintf(devid, "n%i", links[i].ifindex);
- (void)sd_device_new_from_device_id(&d, devid);
+ xsprintf(devid, "n%i", links[i].ifindex);
+ (void) sd_device_new_from_device_id(&d, devid);
- link_get_type_string(links[i].iftype, d, &t);
+ (void) link_get_type_string(links[i].iftype, d, &t);
printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
links[i].ifindex, links[i].name, strna(t),
@@ -257,7 +335,7 @@ static int list_links(int argc, char *argv[], void *userdata) {
}
/* IEEE Organizationally Unique Identifier vendor string */
-static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) {
+static int ieee_oui(sd_hwdb *hwdb, const struct ether_addr *mac, char **ret) {
const char *description;
char modalias[strlen("OUI:XXYYXXYYXXYY") + 1], *desc;
int r;
@@ -404,6 +482,9 @@ static int dump_gateways(
_cleanup_free_ struct local_address *local = NULL;
int r, n, i;
+ assert(rtnl);
+ assert(prefix);
+
n = local_gateways(rtnl, ifindex, AF_UNSPEC, &local);
if (n < 0)
return n;
@@ -453,6 +534,9 @@ static int dump_addresses(
_cleanup_free_ struct local_address *local = NULL;
int r, n, i;
+ assert(rtnl);
+ assert(prefix);
+
n = local_addresses(rtnl, ifindex, AF_UNSPEC, &local);
if (n < 0)
return n;
@@ -485,6 +569,116 @@ static int dump_addresses(
return 0;
}
+static int open_lldp_neighbors(int ifindex, FILE **ret) {
+ _cleanup_free_ char *p = NULL;
+ FILE *f;
+
+ if (asprintf(&p, "/run/systemd/netif/lldp/%i", ifindex) < 0)
+ return -ENOMEM;
+
+ f = fopen(p, "re");
+ if (!f)
+ return -errno;
+
+ *ret = f;
+ return 0;
+}
+
+static int next_lldp_neighbor(FILE *f, sd_lldp_neighbor **ret) {
+ _cleanup_free_ void *raw = NULL;
+ size_t l;
+ le64_t u;
+ int r;
+
+ assert(f);
+ assert(ret);
+
+ l = fread(&u, 1, sizeof(u), f);
+ if (l == 0 && feof(f))
+ return 0;
+ if (l != sizeof(u))
+ return -EBADMSG;
+
+ raw = new(uint8_t, le64toh(u));
+ if (!raw)
+ return -ENOMEM;
+
+ if (fread(raw, 1, le64toh(u), f) != le64toh(u))
+ return -EBADMSG;
+
+ r = sd_lldp_neighbor_from_raw(ret, raw, le64toh(u));
+ if (r < 0)
+ return r;
+
+ return 1;
+}
+
+static int dump_lldp_neighbors(const char *prefix, int ifindex) {
+ _cleanup_fclose_ FILE *f = NULL;
+ int r, c = 0;
+
+ assert(prefix);
+ assert(ifindex > 0);
+
+ r = open_lldp_neighbors(ifindex, &f);
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ const char *system_name = NULL, *port_id = NULL, *port_description = NULL;
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
+
+ r = next_lldp_neighbor(f, &n);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ printf("%*s",
+ (int) strlen(prefix),
+ c == 0 ? prefix : "");
+
+ (void) sd_lldp_neighbor_get_system_name(n, &system_name);
+ (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
+ (void) sd_lldp_neighbor_get_port_description(n, &port_description);
+
+ printf("%s on port %s", strna(system_name), strna(port_id));
+
+ if (!isempty(port_description))
+ printf(" (%s)", port_description);
+
+ putchar('\n');
+
+ c++;
+ }
+
+ return c;
+}
+
+static void dump_ifindexes(const char *prefix, const int *ifindexes) {
+ unsigned c;
+
+ assert(prefix);
+
+ if (!ifindexes || ifindexes[0] <= 0)
+ return;
+
+ for (c = 0; ifindexes[c] > 0; c++) {
+ char name[IF_NAMESIZE+1];
+
+ printf("%*s",
+ (int) strlen(prefix),
+ c == 0 ? prefix : "");
+
+ if (if_indextoname(ifindexes[c], name))
+ fputs(name, stdout);
+ else
+ printf("%i", ifindexes[c]);
+
+ fputc('\n', stdout);
+ }
+}
+
static void dump_list(const char *prefix, char **l) {
char **i;
@@ -502,85 +696,36 @@ static void dump_list(const char *prefix, char **l) {
static int link_status_one(
sd_netlink *rtnl,
sd_hwdb *hwdb,
- const char *name) {
+ const LinkInfo *info) {
+
_cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
_cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL;
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_(sd_device_unrefp) sd_device *d = NULL;
char devid[2 + DECIMAL_STR_MAX(int)];
_cleanup_free_ char *t = NULL, *network = NULL;
const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL;
const char *on_color_operational, *off_color_operational,
*on_color_setup, *off_color_setup;
- _cleanup_strv_free_ char **carrier_bound_to = NULL;
- _cleanup_strv_free_ char **carrier_bound_by = NULL;
- struct ether_addr e;
- unsigned iftype;
- int r, ifindex;
- bool have_mac;
- uint32_t mtu;
+ _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL;
+ int r;
assert(rtnl);
- assert(name);
-
- 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);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_message_append_string(req, IFLA_IFNAME, name);
- }
+ assert(info);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_call(rtnl, req, 0, &reply);
- if (r < 0)
- return log_error_errno(r, "Failed to query link: %m");
-
- r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
- if (r < 0)
- return rtnl_log_parse_error(r);
-
- r = sd_netlink_message_read_string(reply, IFLA_IFNAME, &name);
- if (r < 0)
- return rtnl_log_parse_error(r);
-
- r = sd_rtnl_message_link_get_type(reply, &iftype);
- if (r < 0)
- return rtnl_log_parse_error(r);
-
- have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0;
- if (have_mac) {
- const uint8_t *p;
- bool all_zeroes = true;
-
- for (p = (uint8_t*) &e; p < (uint8_t*) &e + sizeof(e); p++)
- if (*p != 0) {
- all_zeroes = false;
- break;
- }
-
- if (all_zeroes)
- have_mac = false;
- }
-
- (void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu);
-
- (void) sd_network_link_get_operational_state(ifindex, &operational_state);
+ (void) sd_network_link_get_operational_state(info->ifindex, &operational_state);
operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- (void) sd_network_link_get_setup_state(ifindex, &setup_state);
+ r = sd_network_link_get_setup_state(info->ifindex, &setup_state);
+ if (r == -ENODATA) /* If there's no info available about this iface, it's unmanaged by networkd */
+ setup_state = strdup("unmanaged");
setup_state_to_color(setup_state, &on_color_setup, &off_color_setup);
- (void) sd_network_link_get_dns(ifindex, &dns);
- (void) sd_network_link_get_search_domains(ifindex, &search_domains);
- (void) sd_network_link_get_route_domains(ifindex, &route_domains);
- (void) sd_network_link_get_ntp(ifindex, &ntp);
+ (void) sd_network_link_get_dns(info->ifindex, &dns);
+ (void) sd_network_link_get_search_domains(info->ifindex, &search_domains);
+ (void) sd_network_link_get_route_domains(info->ifindex, &route_domains);
+ (void) sd_network_link_get_ntp(info->ifindex, &ntp);
- sprintf(devid, "n%i", ifindex);
+ xsprintf(devid, "n%i", info->ifindex);
(void) sd_device_new_from_device_id(&d, devid);
@@ -598,14 +743,14 @@ static int link_status_one(
(void) sd_device_get_property_value(d, "ID_MODEL", &model);
}
- link_get_type_string(iftype, d, &t);
+ (void) link_get_type_string(info->iftype, d, &t);
- sd_network_link_get_network_file(ifindex, &network);
+ (void) sd_network_link_get_network_file(info->ifindex, &network);
- sd_network_link_get_carrier_bound_to(ifindex, &carrier_bound_to);
- sd_network_link_get_carrier_bound_by(ifindex, &carrier_bound_by);
+ (void) sd_network_link_get_carrier_bound_to(info->ifindex, &carrier_bound_to);
+ (void) sd_network_link_get_carrier_bound_by(info->ifindex, &carrier_bound_by);
- printf("%s%s%s %i: %s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, ifindex, name);
+ printf("%s%s%s %i: %s\n", on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational, info->ifindex, info->name);
printf(" Link File: %s\n"
" Network File: %s\n"
@@ -626,23 +771,23 @@ static int link_status_one(
if (model)
printf(" Model: %s\n", model);
- if (have_mac) {
+ if (info->has_mac_address) {
_cleanup_free_ char *description = NULL;
char ea[ETHER_ADDR_TO_STRING_MAX];
- ieee_oui(hwdb, &e, &description);
+ (void) ieee_oui(hwdb, &info->mac_address, &description);
if (description)
- printf(" HW Address: %s (%s)\n", ether_addr_to_string(&e, ea), description);
+ printf(" HW Address: %s (%s)\n", ether_addr_to_string(&info->mac_address, ea), description);
else
- printf(" HW Address: %s\n", ether_addr_to_string(&e, ea));
+ printf(" HW Address: %s\n", ether_addr_to_string(&info->mac_address, ea));
}
- if (mtu > 0)
- printf(" MTU: %u\n", mtu);
+ if (info->has_mtu)
+ printf(" MTU: %u\n", info->mtu);
- dump_addresses(rtnl, " Address: ", ifindex);
- dump_gateways(rtnl, hwdb, " Gateway: ", ifindex);
+ (void) dump_addresses(rtnl, " Address: ", info->ifindex);
+ (void) dump_gateways(rtnl, hwdb, " Gateway: ", info->ifindex);
dump_list(" DNS: ", dns);
dump_list(" Search Domains: ", search_domains);
@@ -650,362 +795,237 @@ static int link_status_one(
dump_list(" NTP: ", ntp);
- dump_list("Carrier Bound To: ", carrier_bound_to);
- dump_list("Carrier Bound By: ", carrier_bound_by);
+ dump_ifindexes("Carrier Bound To: ", carrier_bound_to);
+ dump_ifindexes("Carrier Bound By: ", carrier_bound_by);
- (void) sd_network_link_get_timezone(ifindex, &tz);
+ (void) sd_network_link_get_timezone(info->ifindex, &tz);
if (tz)
- printf(" Time Zone: %s", tz);
+ printf(" Time Zone: %s\n", tz);
+
+ (void) dump_lldp_neighbors(" Connected To: ", info->ifindex);
return 0;
}
-static int link_status(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- char **name;
- int r;
-
- r = sd_netlink_open(&rtnl);
- if (r < 0)
- return log_error_errno(r, "Failed to connect to netlink: %m");
-
- r = sd_hwdb_new(&hwdb);
- if (r < 0)
- log_debug_errno(r, "Failed to open hardware database: %m");
-
- if (argc <= 1 && !arg_all) {
- _cleanup_free_ char *operational_state = NULL;
- _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains;
- const char *on_color_operational, *off_color_operational;
-
- sd_network_get_operational_state(&operational_state);
- operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
-
- printf("%s%s%s State: %s%s%s\n",
- on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational,
- on_color_operational, strna(operational_state), off_color_operational);
-
- dump_addresses(rtnl, " Address: ", 0);
- dump_gateways(rtnl, hwdb, " Gateway: ", 0);
-
- sd_network_get_dns(&dns);
- dump_list(" DNS: ", dns);
-
- sd_network_get_search_domains(&search_domains);
- dump_list("Search Domains: ", search_domains);
-
- sd_network_get_route_domains(&route_domains);
- dump_list(" Route Domains: ", route_domains);
-
- sd_network_get_ntp(&ntp);
- dump_list(" NTP: ", ntp);
-
- return 0;
- }
+static int system_status(sd_netlink *rtnl, sd_hwdb *hwdb) {
+ _cleanup_free_ char *operational_state = NULL;
+ _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL;
+ const char *on_color_operational, *off_color_operational;
- pager_open_if_enabled();
+ assert(rtnl);
- if (arg_all) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
- _cleanup_free_ LinkInfo *links = NULL;
- int c, i;
+ (void) sd_network_get_operational_state(&operational_state);
+ operational_state_to_color(operational_state, &on_color_operational, &off_color_operational);
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
- if (r < 0)
- return rtnl_log_create_error(r);
+ printf("%s%s%s State: %s%s%s\n",
+ on_color_operational, special_glyph(BLACK_CIRCLE), off_color_operational,
+ on_color_operational, strna(operational_state), off_color_operational);
- r = sd_netlink_message_request_dump(req, true);
- if (r < 0)
- return rtnl_log_create_error(r);
+ (void) dump_addresses(rtnl, " Address: ", 0);
+ (void) dump_gateways(rtnl, hwdb, " Gateway: ", 0);
- r = sd_netlink_call(rtnl, req, 0, &reply);
- if (r < 0)
- return log_error_errno(r, "Failed to enumerate links: %m");
+ (void) sd_network_get_dns(&dns);
+ dump_list(" DNS: ", dns);
- c = decode_and_sort_links(reply, &links);
- if (c < 0)
- return rtnl_log_parse_error(c);
+ (void) sd_network_get_search_domains(&search_domains);
+ dump_list("Search Domains: ", search_domains);
- for (i = 0; i < c; i++) {
- if (i > 0)
- fputc('\n', stdout);
+ (void) sd_network_get_route_domains(&route_domains);
+ dump_list(" Route Domains: ", route_domains);
- link_status_one(rtnl, hwdb, links[i].name);
- }
- } else {
- STRV_FOREACH(name, argv + 1) {
- if (name != argv + 1)
- fputc('\n', stdout);
-
- link_status_one(rtnl, hwdb, *name);
- }
- }
+ (void) sd_network_get_ntp(&ntp);
+ dump_list(" NTP: ", ntp);
return 0;
}
-const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_;
-LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_;
-
-static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = {
- [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O",
- [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P",
- [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B",
- [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W",
- [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R",
- [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T",
- [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D",
- [LLDP_SYSTEM_CAPABILITIES_STATION] = "A",
- [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C",
- [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S",
- [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M",
- [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities);
-
-static char *lldp_system_caps(uint16_t cap) {
- _cleanup_free_ char *s = NULL, *t = NULL;
- char *capability;
-
- t = strdup("[ ");
- if (!t)
- return NULL;
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
-
- if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
+static int link_status(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL;
+ _cleanup_free_ LinkInfo *links = NULL;
+ int r, c, i;
- if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL);
- if (!s)
- return NULL;
+ pager_open(arg_no_pager, false);
- free(t);
- t = s;
- }
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
- if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL);
- if (!s)
- return NULL;
+ r = sd_hwdb_new(&hwdb);
+ if (r < 0)
+ log_debug_errno(r, "Failed to open hardware database: %m");
- free(t);
- t = s;
- }
+ if (arg_all)
+ c = acquire_link_info_all(rtnl, &links);
+ else if (argc <= 1)
+ return system_status(rtnl, hwdb);
+ else
+ c = acquire_link_info_strv(rtnl, argv + 1, &links);
+ if (c < 0)
+ return c;
- if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL);
- if (!s)
- return NULL;
+ for (i = 0; i < c; i++) {
+ if (i > 0)
+ fputc('\n', stdout);
- free(t);
- t = s;
+ link_status_one(rtnl, hwdb, links + i);
}
- if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) {
- s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL);
- if (!s)
- return NULL;
-
- free(t);
- t = s;
- }
+ return 0;
+}
- if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) {
- s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR));
- if (!s)
- return NULL;
+static char *lldp_capabilities_to_string(uint16_t x) {
+ static const char characters[] = {
+ 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm',
+ };
+ char *ret;
+ unsigned i;
- free(t);
- }
+ ret = new(char, ELEMENTSOF(characters) + 1);
+ if (!ret)
+ return NULL;
- if (!s) {
- s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX));
- if (!s)
- return NULL;
+ for (i = 0; i < ELEMENTSOF(characters); i++)
+ ret[i] = (x & (1U << i)) ? characters[i] : '.';
- free(t);
- }
+ ret[i] = 0;
+ return ret;
+}
- t = strappend(s, "]");
- if (!t)
- return NULL;
+static void lldp_capabilities_legend(uint16_t x) {
+ unsigned w, i, cols = columns();
+ static const char* const table[] = {
+ "o - Other",
+ "p - Repeater",
+ "b - Bridge",
+ "w - WLAN Access Point",
+ "r - Router",
+ "t - Telephone",
+ "d - DOCSIS cable device",
+ "a - Station",
+ "c - Customer VLAN",
+ "s - Service VLAN",
+ "m - Two-port MAC Relay (TPMR)",
+ };
- free(s);
- capability = t;
+ if (x == 0)
+ return;
- s = NULL;
- t = NULL;
+ printf("\nCapability Flags:\n");
+ for (w = 0, i = 0; i < ELEMENTSOF(table); i++)
+ if (x & (1U << i) || arg_all) {
+ bool newline;
- return capability;
+ newline = w + strlen(table[i]) + (w == 0 ? 0 : 2) > cols;
+ if (newline)
+ w = 0;
+ w += printf("%s%s%s", newline ? "\n" : "", w == 0 ? "" : "; ", table[i]);
+ }
+ puts("");
}
static int link_lldp_status(int argc, char *argv[], void *userdata) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
_cleanup_free_ LinkInfo *links = NULL;
- double ttl = -1;
- uint32_t capability;
- int i, r, c, j;
- const char *p;
- char **s;
-
- pager_open_if_enabled();
+ int i, r, c, m = 0;
+ uint16_t all = 0;
r = sd_netlink_open(&rtnl);
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_message_request_dump(req, true);
- if (r < 0)
- return rtnl_log_create_error(r);
-
- r = sd_netlink_call(rtnl, req, 0, &reply);
- if (r < 0)
- return log_error_errno(r, "Failed to enumerate links: %m");
-
- c = decode_and_sort_links(reply, &links);
+ if (argc > 1)
+ c = acquire_link_info_strv(rtnl, argv + 1, &links);
+ else
+ c = acquire_link_info_all(rtnl, &links);
if (c < 0)
- return rtnl_log_parse_error(c);
+ return c;
+
+ pager_open(arg_no_pager, false);
if (arg_legend)
- printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability");
+ printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
+ "LINK",
+ "CHASSIS ID",
+ "SYSTEM NAME",
+ "CAPS",
+ "PORT ID",
+ "PORT DESCRIPTION");
- for (i = j = 0; i < c; i++) {
- _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL;
- _cleanup_strv_free_ char **l = NULL;
+ for (i = 0; i < c; i++) {
+ _cleanup_fclose_ FILE *f = NULL;
- r = sd_network_link_get_lldp(links[i].ifindex, &lldp);
- if (r < 0)
+ r = open_lldp_neighbors(links[i].ifindex, &f);
+ if (r == -ENOENT)
continue;
+ if (r < 0) {
+ log_warning_errno(r, "Failed to open LLDP data for %i, ignoring: %m", links[i].ifindex);
+ continue;
+ }
- l = strv_split_newlines(lldp);
- if (!l)
- return -ENOMEM;
-
- STRV_FOREACH(s, l) {
-
- p = *s;
- for (;;) {
- _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r < 0)
- return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s);
-
- if (r == 0)
- break;
-
- r = split_pair(word, "=", &a, &b);
- if (r < 0)
- continue;
-
- if (streq(a, "_Chassis")) {
- r = free_and_strdup(&chassis, b);
- if (r < 0)
- return r;
-
- } else if (streq(a, "_Port")) {
- r = free_and_strdup(&port, b);
- if (r < 0)
- return r;
-
- } else if (streq(a, "_TTL")) {
- long long unsigned x = 0;
- usec_t time;
+ for (;;) {
+ _cleanup_free_ char *cid = NULL, *pid = NULL, *sname = NULL, *pdesc = NULL;
+ const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL;
+ _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL;
+ uint16_t cc;
- r = safe_atollu(b, &x);
- if (r < 0 || (usec_t) x != x)
- return log_warning_errno(r < 0 ? r : ERANGE,
- "Failed to parse TTL \"%s\": %m", b);
+ r = next_lldp_neighbor(f, &n);
+ if (r < 0) {
+ log_warning_errno(r, "Failed to read neighbor data: %m");
+ break;
+ }
+ if (r == 0)
+ break;
- time = now(clock_boottime_or_monotonic());
- if (x < time)
- continue;
+ (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id);
+ (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id);
+ (void) sd_lldp_neighbor_get_system_name(n, &system_name);
+ (void) sd_lldp_neighbor_get_port_description(n, &port_description);
- ttl = (double) (x - time) / USEC_PER_SEC;
+ if (chassis_id) {
+ cid = ellipsize(chassis_id, 17, 100);
+ if (cid)
+ chassis_id = cid;
+ }
- } else if (streq(a, "_CAP")) {
- sscanf(b, "%x", &capability);
+ if (port_id) {
+ pid = ellipsize(port_id, 17, 100);
+ if (pid)
+ port_id = pid;
+ }
- cap = lldp_system_caps(capability);
- }
+ if (system_name) {
+ sname = ellipsize(system_name, 16, 100);
+ if (sname)
+ system_name = sname;
+ }
+ if (port_description) {
+ pdesc = ellipsize(port_description, 16, 100);
+ if (pdesc)
+ port_description = pdesc;
}
- if (ttl >= 0) {
- printf("%10s %24s %16s %16f %16s\n",
- links[i].name,
- strna(chassis), strna(port),
- ttl, cap);
- j++;
+ if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) {
+ capabilities = lldp_capabilities_to_string(cc);
+ all |= cc;
}
+
+ printf("%-16s %-17s %-16s %-11s %-17s %-16s\n",
+ links[i].name,
+ strna(chassis_id),
+ strna(system_name),
+ strna(capabilities),
+ strna(port_id),
+ strna(port_description));
+
+ m++;
}
}
if (arg_legend) {
- printf("\nCapability Codes:\n"
- "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n"
- "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n"
- "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n");
-
- printf("Total entries displayed: %d\n", j);
+ lldp_capabilities_legend(all);
+ printf("\n%i neighbors listed.\n", m);
}
return 0;
@@ -1020,9 +1040,9 @@ static void help(void) {
" --no-legend Do not show the headers and footers\n"
" -a --all Show status for all links\n\n"
"Commands:\n"
- " list List links\n"
+ " list [LINK...] List links\n"
" status [LINK...] Show link status\n"
- " lldp Show lldp information\n"
+ " lldp [LINK...] Show LLDP neighbors\n"
, program_invocation_short_name);
}
@@ -1084,15 +1104,23 @@ static int parse_argv(int argc, char *argv[]) {
static int networkctl_main(int argc, char *argv[]) {
const Verb verbs[] = {
- { "list", VERB_ANY, 1, VERB_DEFAULT, list_links },
- { "status", 1, VERB_ANY, 0, link_status },
- { "lldp", VERB_ANY, 1, VERB_DEFAULT, link_lldp_status },
+ { "list", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_links },
+ { "status", VERB_ANY, VERB_ANY, 0, link_status },
+ { "lldp", VERB_ANY, VERB_ANY, 0, link_lldp_status },
{}
};
return dispatch_verb(argc, argv, verbs, NULL);
}
+static void warn_networkd_missing(void) {
+
+ if (access("/run/systemd/netif/state", F_OK) >= 0)
+ return;
+
+ fprintf(stderr, "WARNING: systemd-networkd is not running, output will be incomplete.\n\n");
+}
+
int main(int argc, char* argv[]) {
int r;
@@ -1103,6 +1131,8 @@ int main(int argc, char* argv[]) {
if (r <= 0)
goto finish;
+ warn_networkd_missing();
+
r = networkctl_main(argc, argv);
finish:
diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c
index d9d487d805..ebc6c9eb9e 100644
--- a/src/network/networkd-address-pool.c
+++ b/src/network/networkd-address-pool.c
@@ -148,8 +148,12 @@ int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union
for (;;) {
if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
_cleanup_free_ char *s = NULL;
+ int r;
+
+ r = in_addr_to_string(p->family, &u, &s);
+ if (r < 0)
+ return r;
- in_addr_to_string(p->family, &u, &s);
log_debug("Found range %s/%u", strna(s), prefixlen);
*found = u;
diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h
index 8e1378ff40..af30decfe0 100644
--- a/src/network/networkd-address-pool.h
+++ b/src/network/networkd-address-pool.h
@@ -22,7 +22,9 @@
typedef struct AddressPool AddressPool;
#include "in-addr-util.h"
-#include "networkd.h"
+#include "list.h"
+
+typedef struct Manager Manager;
struct AddressPool {
Manager *manager;
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c
index 7f9a7268cc..367c340e08 100644
--- a/src/network/networkd-address.c
+++ b/src/network/networkd-address.c
@@ -27,6 +27,7 @@
#include "networkd.h"
#include "parse-util.h"
#include "set.h"
+#include "socket-util.h"
#include "string-util.h"
#include "utf8.h"
#include "util.h"
@@ -67,16 +68,15 @@ int address_new_static(Network *network, unsigned section, Address **ret) {
if (r < 0)
return r;
- address->network = network;
-
- LIST_APPEND(addresses, network->static_addresses, address);
-
if (section) {
address->section = section;
hashmap_put(network->addresses_by_section,
UINT_TO_PTR(address->section), address);
}
+ address->network = network;
+ LIST_APPEND(addresses, network->static_addresses, address);
+
*ret = address;
address = NULL;
@@ -98,6 +98,9 @@ void address_free(Address *address) {
if (address->link) {
set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address);
+
+ if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
+ memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
}
free(address);
@@ -331,6 +334,10 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
assert(address);
assert(cinfo);
+ assert_return(address->link, 1);
+
+ if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
ready = address_is_ready(address);
@@ -338,19 +345,18 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s
address->scope = scope;
address->cinfo = *cinfo;
- if (address->link) {
- link_update_operstate(address->link);
-
- if (!ready && address_is_ready(address)) {
- link_check_ready(address->link);
-
- if (address->family == AF_INET6 &&
- in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
- in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
- r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
- if (r < 0)
- return r;
- }
+ link_update_operstate(address->link);
+
+ if (!ready && address_is_ready(address)) {
+ link_check_ready(address->link);
+
+ if (address->family == AF_INET6 &&
+ in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 &&
+ in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) {
+
+ r = link_ipv6ll_gained(address->link, &address->in_addr.in6);
+ if (r < 0)
+ return r;
}
}
@@ -404,8 +410,11 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi
return 0;
}
-int address_remove(Address *address, Link *link,
- sd_netlink_message_handler_t callback) {
+int address_remove(
+ Address *address,
+ Link *link,
+ sd_netlink_message_handler_t callback) {
+
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
@@ -727,7 +736,8 @@ int config_parse_address(const char *unit,
return 0;
}
-int config_parse_label(const char *unit,
+int config_parse_label(
+ const char *unit,
const char *filename,
unsigned line,
const char *section,
@@ -737,9 +747,9 @@ int config_parse_label(const char *unit,
const char *rvalue,
void *data,
void *userdata) {
- Network *network = userdata;
+
_cleanup_address_free_ Address *n = NULL;
- char *label;
+ Network *network = userdata;
int r;
assert(filename);
@@ -752,25 +762,64 @@ int config_parse_label(const char *unit,
if (r < 0)
return r;
- label = strdup(rvalue);
- if (!label)
+ if (!ifname_valid(rvalue)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not valid or too long, ignoring assignment: %s", rvalue);
+ return 0;
+ }
+
+ r = free_and_strdup(&n->label, rvalue);
+ if (r < 0)
return log_oom();
- if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue);
- free(label);
+ n = NULL;
+
+ return 0;
+}
+
+int config_parse_lifetime(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_address_free_ Address *n = NULL;
+ unsigned k;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = address_new_static(network, section_line, &n);
+ if (r < 0)
+ return r;
+
+ if (STR_IN_SET(rvalue, "forever", "infinity")) {
+ n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
+ n = NULL;
+
return 0;
}
- free(n->label);
- if (*label)
- n->label = label;
- else {
- free(label);
- n->label = NULL;
+ r = safe_atou(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
+ return 0;
}
- n = NULL;
+ if (k != 0)
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
+ else {
+ n->cinfo.ifa_prefered = k;
+ n = NULL;
+ }
return 0;
}
diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h
index 338f6eb9a2..784ab18b27 100644
--- a/src/network/networkd-address.h
+++ b/src/network/networkd-address.h
@@ -28,10 +28,12 @@ typedef struct Address Address;
#include "networkd-link.h"
#include "networkd-network.h"
-#include "networkd.h"
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
+typedef struct Network Network;
+typedef struct Link Link;
+
struct Address {
Network *network;
unsigned section;
@@ -74,3 +76,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
int config_parse_address(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_broadcast(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_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_lifetime(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-conf.c b/src/network/networkd-conf.c
new file mode 100644
index 0000000000..b67a1f6d09
--- /dev/null
+++ b/src/network/networkd-conf.c
@@ -0,0 +1,111 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Vinay Kulkarni <kulkarniv@vmware.com>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+ ***/
+
+#include <ctype.h>
+
+#include "conf-parser.h"
+#include "def.h"
+#include "dhcp-identifier.h"
+#include "hexdecoct.h"
+#include "networkd-conf.h"
+#include "string-table.h"
+
+int manager_parse_config_file(Manager *m) {
+ assert(m);
+
+ return config_parse_many(PKGSYSCONFDIR "/networkd.conf",
+ CONF_PATHS_NULSTR("systemd/networkd.conf.d"),
+ "DHCP\0",
+ config_item_perf_lookup, networkd_gperf_lookup,
+ false, m);
+}
+
+static const char* const duid_type_table[_DUID_TYPE_MAX] = {
+ [DUID_TYPE_LLT] = "link-layer-time",
+ [DUID_TYPE_EN] = "vendor",
+ [DUID_TYPE_LL] = "link-layer",
+ [DUID_TYPE_UUID] = "uuid",
+};
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_duid_type, duid_type, DUIDType, "Failed to parse DUID type");
+
+int config_parse_duid_rawdata(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ DUID *ret = data;
+ uint8_t raw_data[MAX_DUID_LEN];
+ unsigned count = 0;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(ret);
+
+ /* RawData contains DUID in format "NN:NN:NN..." */
+ for (;;) {
+ int n1, n2, len, r;
+ uint32_t byte;
+ _cleanup_free_ char *cbyte = NULL;
+
+ r = extract_first_word(&rvalue, &cbyte, ":", 0);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue);
+ return 0;
+ }
+ if (r == 0)
+ break;
+ if (count >= MAX_DUID_LEN) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue);
+ return 0;
+ }
+
+ len = strlen(cbyte);
+ if (len != 1 && len != 2) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue);
+ return 0;
+ }
+ n1 = unhexchar(cbyte[0]);
+ if (len == 2)
+ n2 = unhexchar(cbyte[1]);
+ else
+ n2 = 0;
+
+ if (n1 < 0 || n2 < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue);
+ return 0;
+ }
+
+ byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2;
+ raw_data[count++] = byte;
+ }
+
+ assert_cc(sizeof(raw_data) == sizeof(ret->raw_data));
+ memcpy(ret->raw_data, raw_data, count);
+ ret->raw_data_len = count;
+ return 0;
+}
diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h
new file mode 100644
index 0000000000..c7bfb42a72
--- /dev/null
+++ b/src/network/networkd-conf.h
@@ -0,0 +1,49 @@
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2014 Vinay Kulkarni <kulkarniv@vmware.com>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "networkd.h"
+
+int manager_parse_config_file(Manager *m);
+
+const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, unsigned length);
+
+int config_parse_duid_type(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata);
+int config_parse_duid_rawdata(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata);
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 03c28bbcb6..2ddcee9db8 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -24,7 +24,7 @@
#include "dhcp-lease-internal.h"
#include "hostname-util.h"
#include "network-internal.h"
-#include "networkd-link.h"
+#include "networkd.h"
static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
void *userdata) {
@@ -34,7 +34,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
assert(link);
assert(link->dhcp4_messages > 0);
- link->dhcp4_messages --;
+ link->dhcp4_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
@@ -57,6 +57,10 @@ static int link_set_dhcp_routes(Link *link) {
assert(link);
assert(link->dhcp_lease);
+ assert(link->network);
+
+ if (!link->network->dhcp_use_routes)
+ return 0;
r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
if (r < 0 && r != -ENODATA)
@@ -92,25 +96,25 @@ static int link_set_dhcp_routes(Link *link) {
route_gw->protocol = RTPROT_DHCP;
route_gw->priority = link->network->dhcp_route_metric;
- r = route_configure(route_gw, link, &dhcp4_route_handler);
+ r = route_configure(route_gw, link, dhcp4_route_handler);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set host route: %m");
- link->dhcp4_messages ++;
+ link->dhcp4_messages++;
route->family = AF_INET;
route->gw.in = gateway;
route->prefsrc.in = address;
route->priority = link->network->dhcp_route_metric;
- r = route_configure(route, link, &dhcp4_route_handler);
+ r = route_configure(route, link, dhcp4_route_handler);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set routes: %m");
link_enter_failed(link);
return r;
}
- link->dhcp4_messages ++;
+ link->dhcp4_messages++;
}
n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
@@ -133,11 +137,11 @@ static int link_set_dhcp_routes(Link *link) {
assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
route->priority = link->network->dhcp_route_metric;
- r = route_configure(route, link, &dhcp4_route_handler);
+ r = route_configure(route, link, dhcp4_route_handler);
if (r < 0)
return log_link_warning_errno(link, r, "Could not set host route: %m");
- link->dhcp4_messages ++;
+ link->dhcp4_messages++;
}
return 0;
@@ -173,7 +177,7 @@ static int dhcp_lease_lost(Link *link) {
assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
route_remove(route, link,
- &link_route_remove_handler);
+ link_route_remove_handler);
}
}
}
@@ -194,7 +198,7 @@ static int dhcp_lease_lost(Link *link) {
route_gw->scope = RT_SCOPE_LINK;
route_remove(route_gw, link,
- &link_route_remove_handler);
+ link_route_remove_handler);
}
r = route_new(&route);
@@ -203,7 +207,7 @@ static int dhcp_lease_lost(Link *link) {
route->gw.in = gateway;
route_remove(route, link,
- &link_route_remove_handler);
+ link_route_remove_handler);
}
}
@@ -217,7 +221,7 @@ static int dhcp_lease_lost(Link *link) {
address->in_addr.in = addr;
address->prefixlen = prefixlen;
- address_remove(address, link, &link_address_remove_handler);
+ address_remove(address, link, link_address_remove_handler);
}
}
@@ -305,7 +309,7 @@ static int dhcp4_update_address(Link *link,
/* allow reusing an existing address and simply update its lifetime
* in case it already exists */
- r = address_configure(addr, link, &dhcp4_address_handler, true);
+ r = address_configure(addr, link, dhcp4_address_handler, true);
if (r < 0)
return r;
@@ -624,14 +628,24 @@ int dhcp4_configure(Link *link) {
}
switch (link->network->dhcp_client_identifier) {
- case DHCP_CLIENT_ID_DUID:
- /* Library defaults to this. */
+ case DHCP_CLIENT_ID_DUID: {
+ /* If configured, apply user specified DUID and/or IAID */
+ const DUID *duid = link_duid(link);
+
+ r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+ link->network->iaid,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
+ if (r < 0)
+ return r;
break;
+ }
case DHCP_CLIENT_ID_MAC:
r = sd_dhcp_client_set_client_id(link->dhcp_client,
ARPHRD_ETHER,
(const uint8_t *) &link->mac,
- sizeof (link->mac));
+ sizeof(link->mac));
if (r < 0)
return r;
break;
diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c
index bf8e826368..c5a3c52e94 100644
--- a/src/network/networkd-dhcp6.c
+++ b/src/network/networkd-dhcp6.c
@@ -23,7 +23,7 @@
#include <systemd/sd-dhcp6-client.h>
#include "network-internal.h"
-#include "networkd-link.h"
+#include "networkd.h"
static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link);
@@ -103,8 +103,8 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) {
sd_dhcp6_lease_reset_address_iter(lease);
while (sd_dhcp6_lease_get_address(lease, &ip6_addr,
- &lifetime_preferred,
- &lifetime_valid) >= 0) {
+ &lifetime_preferred,
+ &lifetime_valid) >= 0) {
r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid);
if (r < 0)
@@ -194,18 +194,13 @@ int dhcp6_request_address(Link *link) {
if (r < 0)
return r;
- if (running) {
- r = sd_dhcp6_client_start(link->dhcp6_client);
- if (r < 0)
- return r;
- }
-
return 0;
}
int dhcp6_configure(Link *link) {
sd_dhcp6_client *client = NULL;
int r;
+ const DUID *duid;
assert(link);
@@ -230,6 +225,18 @@ int dhcp6_configure(Link *link) {
if (r < 0)
goto error;
+ r = sd_dhcp6_client_set_iaid(client, link->network->iaid);
+ if (r < 0)
+ goto error;
+
+ duid = link_duid(link);
+ r = sd_dhcp6_client_set_duid(client,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
+ if (r < 0)
+ goto error;
+
r = sd_dhcp6_client_set_index(client, link->ifindex);
if (r < 0)
goto error;
diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c
index 1538caa204..241f486211 100644
--- a/src/network/networkd-fdb.c
+++ b/src/network/networkd-fdb.c
@@ -37,7 +37,7 @@ int fdb_entry_new_static(Network *const network,
assert(network);
/* search entry in hashmap first. */
- if(section) {
+ if (section) {
fdb_entry = hashmap_get(network->fdb_entries_by_section, UINT_TO_PTR(section));
if (fdb_entry) {
*ret = fdb_entry;
@@ -141,10 +141,10 @@ int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) {
/* remove and FDB entry. */
void fdb_entry_free(FdbEntry *fdb_entry) {
- if(!fdb_entry)
+ if (!fdb_entry)
return;
- if(fdb_entry->network) {
+ if (fdb_entry->network) {
LIST_REMOVE(static_fdb_entries, fdb_entry->network->static_fdb_entries,
fdb_entry);
diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h
index 89b3e29405..84410714f5 100644
--- a/src/network/networkd-fdb.h
+++ b/src/network/networkd-fdb.h
@@ -19,10 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-typedef struct FdbEntry FdbEntry;
+#include "list.h"
+#include "macro.h"
-#include "networkd-network.h"
-#include "networkd.h"
+typedef struct Network Network;
+typedef struct FdbEntry FdbEntry;
+typedef struct Link Link;
struct FdbEntry {
Network *network;
diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf
new file mode 100644
index 0000000000..3fdfe74955
--- /dev/null
+++ b/src/network/networkd-gperf.gperf
@@ -0,0 +1,18 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "networkd-conf.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name networkd_gperf_hash
+%define lookup-function-name networkd_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid.type)
+DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid)
diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c
index 949c75337c..ae323d595b 100644
--- a/src/network/networkd-ipv4ll.c
+++ b/src/network/networkd-ipv4ll.c
@@ -21,7 +21,7 @@
#include <linux/if.h>
#include "network-internal.h"
-#include "networkd-link.h"
+#include "networkd.h"
static int ipv4ll_address_lost(Link *link) {
_cleanup_address_free_ Address *address = NULL;
@@ -51,7 +51,7 @@ static int ipv4ll_address_lost(Link *link) {
address->prefixlen = 16;
address->scope = RT_SCOPE_LINK;
- address_remove(address, link, &link_address_remove_handler);
+ address_remove(address, link, link_address_remove_handler);
r = route_new(&route);
if (r < 0) {
@@ -63,7 +63,7 @@ static int ipv4ll_address_lost(Link *link) {
route->scope = RT_SCOPE_LINK;
route->priority = IPV4LL_ROUTE_METRIC;
- route_remove(route, link, &link_route_remove_handler);
+ route_remove(route, link, link_route_remove_handler);
link_check_ready(link);
@@ -165,7 +165,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
return 0;
}
-static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){
+static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
Link *link = userdata;
int r;
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 692c0bf63d..a021fc886f 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -28,8 +28,8 @@
#include "fileio.h"
#include "netlink-util.h"
#include "network-internal.h"
-#include "networkd-link.h"
-#include "networkd-netdev.h"
+#include "networkd.h"
+#include "networkd-lldp-tx.h"
#include "set.h"
#include "socket-util.h"
#include "stdio-util.h"
@@ -38,7 +38,12 @@
#include "util.h"
#include "virt.h"
-bool link_dhcp6_enabled(Link *link) {
+static bool link_dhcp6_enabled(Link *link) {
+ assert(link);
+
+ if (!socket_ipv6_is_supported())
+ return false;
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -48,7 +53,9 @@ bool link_dhcp6_enabled(Link *link) {
return link->network->dhcp & ADDRESS_FAMILY_IPV6;
}
-bool link_dhcp4_enabled(Link *link) {
+static bool link_dhcp4_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -58,7 +65,9 @@ bool link_dhcp4_enabled(Link *link) {
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
}
-bool link_dhcp4_server_enabled(Link *link) {
+static bool link_dhcp4_server_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -68,7 +77,9 @@ bool link_dhcp4_server_enabled(Link *link) {
return link->network->dhcp_server;
}
-bool link_ipv4ll_enabled(Link *link) {
+static bool link_ipv4ll_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -78,7 +89,12 @@ bool link_ipv4ll_enabled(Link *link) {
return link->network->link_local & ADDRESS_FAMILY_IPV4;
}
-bool link_ipv6ll_enabled(Link *link) {
+static bool link_ipv6ll_enabled(Link *link) {
+ assert(link);
+
+ if (!socket_ipv6_is_supported())
+ return false;
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -88,20 +104,51 @@ bool link_ipv6ll_enabled(Link *link) {
return link->network->link_local & ADDRESS_FAMILY_IPV6;
}
-bool link_lldp_enabled(Link *link) {
+static bool link_ipv6_enabled(Link *link) {
+ assert(link);
+
+ if (!socket_ipv6_is_supported())
+ return false;
+
+ return link_dhcp6_enabled(link) || link_ipv6ll_enabled(link) || network_has_static_ipv6_addresses(link->network);
+}
+
+static bool link_lldp_rx_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
+ if (link->iftype != ARPHRD_ETHER)
+ return false;
+
if (!link->network)
return false;
if (link->network->bridge)
return false;
- return link->network->lldp;
+ return link->network->lldp_mode != LLDP_MODE_NO;
+}
+
+static bool link_lldp_emit_enabled(Link *link) {
+ assert(link);
+
+ if (link->flags & IFF_LOOPBACK)
+ return false;
+
+ if (link->iftype != ARPHRD_ETHER)
+ return false;
+
+ if (!link->network)
+ return false;
+
+ return link->network->lldp_emit != LLDP_EMIT_NO;
}
static bool link_ipv4_forward_enabled(Link *link) {
+ assert(link);
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -115,6 +162,7 @@ static bool link_ipv4_forward_enabled(Link *link) {
}
static bool link_ipv6_forward_enabled(Link *link) {
+ assert(link);
if (!socket_ipv6_is_supported())
return false;
@@ -131,7 +179,27 @@ static bool link_ipv6_forward_enabled(Link *link) {
return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
}
-bool link_ipv6_accept_ra_enabled(Link *link) {
+static bool link_proxy_arp_enabled(Link *link) {
+ assert(link);
+
+ if (link->flags & IFF_LOOPBACK)
+ return false;
+
+ if (!link->network)
+ return false;
+
+ if (link->network->proxy_arp < 0)
+ return false;
+
+ return true;
+}
+
+static bool link_ipv6_accept_ra_enabled(Link *link) {
+ assert(link);
+
+ if (!socket_ipv6_is_supported())
+ return false;
+
if (link->flags & IFF_LOOPBACK)
return false;
@@ -154,6 +222,7 @@ bool link_ipv6_accept_ra_enabled(Link *link) {
}
static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
+ assert(link);
if (!socket_ipv6_is_supported())
return _IPV6_PRIVACY_EXTENSIONS_INVALID;
@@ -167,6 +236,31 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
return link->network->ipv6_privacy_extensions;
}
+static int link_enable_ipv6(Link *link) {
+ const char *p = NULL;
+ bool disabled;
+ int r;
+
+ if (link->flags & IFF_LOOPBACK)
+ return 0;
+
+ disabled = !link_ipv6_enabled(link);
+
+ p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6");
+
+ r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m", disabled ? "disable" : "enable", link->ifname);
+ else {
+ if (disabled)
+ log_link_info(link, "IPv6 disabled for interface: %m");
+ else
+ log_link_info(link, "IPv6 enabled for interface: %m");
+ }
+
+ return 0;
+}
+
void link_update_operstate(Link *link) {
LinkOperationalState operstate;
assert(link);
@@ -214,7 +308,6 @@ void link_update_operstate(Link *link) {
link->operstate = operstate;
link_send_changed(link, "OperationalState", NULL);
link_dirty(link);
- manager_dirty(link->manager);
}
}
@@ -300,6 +393,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
uint16_t type;
const char *ifname;
int r, ifindex;
+ unsigned short iftype;
assert(manager);
assert(message);
@@ -317,6 +411,10 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
else if (ifindex <= 0)
return -EINVAL;
+ r = sd_rtnl_message_link_get_type(message, &iftype);
+ if (r < 0)
+ return r;
+
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
if (r < 0)
return r;
@@ -330,30 +428,24 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
link->state = LINK_STATE_PENDING;
link->rtnl_extended_attrs = true;
link->ifindex = ifindex;
+ link->iftype = iftype;
link->ifname = strdup(ifname);
if (!link->ifname)
return -ENOMEM;
r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
if (r < 0)
- log_link_debug(link, "MAC address not found for new device, continuing without");
+ log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
- r = asprintf(&link->state_file, "/run/systemd/netif/links/%d",
- link->ifindex);
- if (r < 0)
+ if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0)
return -ENOMEM;
- r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d",
- link->ifindex);
- if (r < 0)
+ if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0)
return -ENOMEM;
- r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d",
- link->ifindex);
- if (r < 0)
+ if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0)
return -ENOMEM;
-
r = hashmap_ensure_allocated(&manager->links, NULL);
if (r < 0)
return r;
@@ -399,10 +491,11 @@ static void link_free(Link *link) {
sd_dhcp_client_unref(link->dhcp_client);
sd_dhcp_lease_unref(link->dhcp_lease);
+ link_lldp_emit_stop(link);
+
free(link->lease_file);
sd_lldp_unref(link->lldp);
-
free(link->lldp_file);
sd_ipv4ll_unref(link->ipv4ll);
@@ -436,7 +529,7 @@ Link *link_unref(Link *link) {
assert(link->n_ref > 0);
- link->n_ref --;
+ link->n_ref--;
if (link->n_ref > 0)
return NULL;
@@ -452,7 +545,7 @@ Link *link_ref(Link *link) {
assert(link->n_ref > 0);
- link->n_ref ++;
+ link->n_ref++;
return link;
}
@@ -482,8 +575,6 @@ static void link_set_state(Link *link, LinkState state) {
link->state = state;
link_send_changed(link, "AdministrativeState", NULL);
-
- return;
}
static void link_enter_unmanaged(Link *link) {
@@ -506,33 +597,28 @@ static int link_stop_clients(Link *link) {
if (link->dhcp_client) {
k = sd_dhcp_client_stop(link->dhcp_client);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop DHCPv4 client: %m");
+ r = log_link_warning_errno(link, k, "Could not stop DHCPv4 client: %m");
}
if (link->ipv4ll) {
k = sd_ipv4ll_stop(link->ipv4ll);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m");
+ r = log_link_warning_errno(link, k, "Could not stop IPv4 link-local: %m");
}
if (link->dhcp6_client) {
k = sd_dhcp6_client_stop(link->dhcp6_client);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m");
+ r = log_link_warning_errno(link, k, "Could not stop DHCPv6 client: %m");
}
if (link->ndisc_router_discovery) {
k = sd_ndisc_stop(link->ndisc_router_discovery);
if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m");
- }
-
- if (link->lldp) {
- k = sd_lldp_stop(link->lldp);
- if (k < 0)
- r = log_link_warning_errno(link, r, "Could not stop LLDP: %m");
+ r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
}
+ link_lldp_emit_stop(link);
return r;
}
@@ -600,6 +686,9 @@ void link_check_ready(Link *link) {
assert(link);
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return;
+
if (!link->network)
return;
@@ -645,7 +734,7 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata
LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
LINK_STATE_LINGER));
- link->link_messages --;
+ link->link_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
@@ -674,14 +763,14 @@ static int link_enter_set_routes(Link *link) {
link_set_state(link, LINK_STATE_SETTING_ROUTES);
LIST_FOREACH(routes, rt, link->network->static_routes) {
- r = route_configure(rt, link, &route_handler);
+ r = route_configure(rt, link, route_handler);
if (r < 0) {
log_link_warning_errno(link, r, "Could not set routes: %m");
link_enter_failed(link);
return r;
}
- link->link_messages ++;
+ link->link_messages++;
}
if (link->link_messages == 0) {
@@ -723,7 +812,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda
assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
LINK_STATE_FAILED, LINK_STATE_LINGER));
- link->link_messages --;
+ link->link_messages--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
@@ -843,14 +932,14 @@ 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, false);
+ 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);
return r;
}
- link->link_messages ++;
+ link->link_messages++;
}
/* now that we can figure out a default address for the dhcp server,
@@ -934,6 +1023,12 @@ static int link_enter_set_addresses(Link *link) {
log_link_warning_errno(link, r, "Failed to set NTP server for DHCP server, ignoring: %m");
}
+ r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router);
+ if (r < 0) {
+ log_link_warning_errno(link, r, "Failed to set router emission for DHCP server: %m");
+ return r;
+ }
+
if (link->network->dhcp_server_emit_timezone) {
_cleanup_free_ char *buffer = NULL;
const char *tz = NULL;
@@ -999,7 +1094,7 @@ static int link_set_bridge_fdb(Link *const link) {
LIST_FOREACH(static_fdb_entries, fdb_entry, link->network->static_fdb_entries) {
r = fdb_entry_configure(link, fdb_entry);
- if(r < 0) {
+ if (r < 0) {
log_link_error_errno(link, r, "Failed to add MAC entry to static MAC table: %m");
break;
}
@@ -1008,6 +1103,22 @@ static int link_set_bridge_fdb(Link *const link) {
return r;
}
+static int link_set_proxy_arp(Link *const link) {
+ const char *p = NULL;
+ int r;
+
+ if (!link_proxy_arp_enabled(link))
+ return 0;
+
+ p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp");
+
+ r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m");
+
+ return 0;
+}
+
static int link_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
int r;
@@ -1211,7 +1322,7 @@ static int link_set_bridge(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
- if(link->network->cost != 0) {
+ if (link->network->cost != 0) {
r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
if (r < 0)
return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m");
@@ -1230,23 +1341,93 @@ static int link_set_bridge(Link *link) {
return r;
}
-static void lldp_handler(sd_lldp *lldp, int event, void *userdata) {
+static int link_lldp_save(Link *link) {
+ _cleanup_free_ char *temp_path = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ sd_lldp_neighbor **l = NULL;
+ int n = 0, r, i;
+
+ assert(link);
+ assert(link->lldp_file);
+
+ if (!link->lldp) {
+ (void) unlink(link->lldp_file);
+ return 0;
+ }
+
+ r = sd_lldp_get_neighbors(link->lldp, &l);
+ if (r < 0)
+ goto finish;
+ if (r == 0) {
+ (void) unlink(link->lldp_file);
+ goto finish;
+ }
+
+ n = r;
+
+ r = fopen_temporary(link->lldp_file, &f, &temp_path);
+ if (r < 0)
+ goto finish;
+
+ fchmod(fileno(f), 0644);
+
+ for (i = 0; i < n; i++) {
+ const void *p;
+ le64_t u;
+ size_t sz;
+
+ r = sd_lldp_neighbor_get_raw(l[i], &p, &sz);
+ if (r < 0)
+ goto finish;
+
+ u = htole64(sz);
+ (void) fwrite(&u, 1, sizeof(u), f);
+ (void) fwrite(p, 1, sz, f);
+ }
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ goto finish;
+
+ if (rename(temp_path, link->lldp_file) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+finish:
+ if (r < 0) {
+ (void) unlink(link->lldp_file);
+ if (temp_path)
+ (void) unlink(temp_path);
+
+ log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
+ }
+
+ if (l) {
+ for (i = 0; i < n; i++)
+ sd_lldp_neighbor_unref(l[i]);
+ free(l);
+ }
+
+ return r;
+}
+
+static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) {
Link *link = userdata;
int r;
assert(link);
- assert(link->network);
- assert(link->manager);
- switch (event) {
- case SD_LLDP_EVENT_UPDATE_INFO:
- r = sd_lldp_save(link->lldp, link->lldp_file);
- if (r < 0)
- log_link_warning_errno(link, r, "Could not save LLDP: %m");
+ (void) link_lldp_save(link);
+
+ if (link_lldp_emit_enabled(link) && event == SD_LLDP_EVENT_ADDED) {
+ /* If we received information about a new neighbor, restart the LLDP "fast" logic */
- break;
- default:
- break;
+ log_link_debug(link, "Received LLDP datagram from previously unknown neighbor, restarting 'fast' LLDP transmission.");
+
+ r = link_lldp_emit_start(link);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Failed to restart LLDP transmission: %m");
}
}
@@ -1283,7 +1464,7 @@ static int link_acquire_ipv6_conf(Link *link) {
return 0;
}
-static int link_acquire_conf(Link *link) {
+static int link_acquire_ipv4_conf(Link *link) {
int r;
assert(link);
@@ -1311,14 +1492,28 @@ static int link_acquire_conf(Link *link) {
return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m");
}
- if (link_lldp_enabled(link)) {
- assert(link->lldp);
+ return 0;
+}
+
+static int link_acquire_conf(Link *link) {
+ int r;
- log_link_debug(link, "Starting LLDP");
+ assert(link);
- r = sd_lldp_start(link->lldp);
+ r = link_acquire_ipv4_conf(link);
+ if (r < 0)
+ return r;
+
+ if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) {
+ r = link_acquire_ipv6_conf(link);
+ if (r < 0)
+ return r;
+ }
+
+ if (link_lldp_emit_enabled(link)) {
+ r = link_lldp_emit_start(link);
if (r < 0)
- return log_link_warning_errno(link, r, "Could not start LLDP: %m");
+ return log_link_warning_errno(link, r, "Failed to start LLDP transmission: %m");
}
return 0;
@@ -1382,7 +1577,21 @@ static int link_up(Link *link) {
return log_link_error_errno(link, r, "Could not set MAC address: %m");
}
+ /* If IPv6 not configured (no static IPv6 address and neither DHCPv6 nor IPv6LL is enabled)
+ for this interface then disable IPv6 else enable it. */
+ (void) link_enable_ipv6(link);
+
if (link->network->mtu) {
+ /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
+ on the interface. Bump up MTU bytes to IPV6_MTU_MIN. */
+ if (link_ipv6_enabled(link) && link->network->mtu < IPV6_MIN_MTU) {
+
+ log_link_warning(link, "Bumping MTU to " STRINGIFY(IPV6_MIN_MTU) ", as "
+ "IPv6 is requested and requires a minimum MTU of " STRINGIFY(IPV6_MIN_MTU) " bytes: %m");
+
+ link->network->mtu = IPV6_MIN_MTU;
+ }
+
r = sd_netlink_message_append_u32(req, IFLA_MTU, link->network->mtu);
if (r < 0)
return log_link_error_errno(link, r, "Could not set MTU: %m");
@@ -1392,7 +1601,7 @@ static int link_up(Link *link) {
if (r < 0)
return log_link_error_errno(link, r, "Could not open IFLA_AF_SPEC container: %m");
- if (socket_ipv6_is_supported()) {
+ if (link_ipv6_enabled(link)) {
/* if the kernel lacks ipv6 support setting IFF_UP fails if any ipv6 options are passed */
r = sd_netlink_message_open_container(req, AF_INET6);
if (r < 0)
@@ -1559,7 +1768,7 @@ static int link_new_bound_by_list(Link *link) {
m = link->manager;
- HASHMAP_FOREACH (carrier, m->links, i) {
+ HASHMAP_FOREACH(carrier, m->links, i) {
if (!carrier->network)
continue;
@@ -1578,7 +1787,7 @@ static int link_new_bound_by_list(Link *link) {
if (list_updated)
link_dirty(link);
- HASHMAP_FOREACH (carrier, link->bound_by_links, i) {
+ HASHMAP_FOREACH(carrier, link->bound_by_links, i) {
r = link_put_carrier(carrier, link, &carrier->bound_to_links);
if (r < 0)
return r;
@@ -1738,7 +1947,7 @@ static int link_joined(Link *link) {
}
}
- if(link->network->bridge) {
+ if (link->network->bridge) {
r = link_set_bridge(link);
if (r < 0)
log_link_error_errno(link, r, "Could not set bridge message: %m");
@@ -1754,7 +1963,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us
assert(link);
assert(link->network);
- link->enslaving --;
+ link->enslaving--;
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
@@ -1810,7 +2019,7 @@ static int link_enter_join_netdev(Link *link) {
return r;
}
- link->enslaving ++;
+ link->enslaving++;
}
if (link->network->bridge) {
@@ -1831,7 +2040,7 @@ static int link_enter_join_netdev(Link *link) {
return r;
}
- link->enslaving ++;
+ link->enslaving++;
}
HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
@@ -1853,7 +2062,7 @@ static int link_enter_join_netdev(Link *link) {
return r;
}
- link->enslaving ++;
+ link->enslaving++;
}
return 0;
@@ -2030,6 +2239,27 @@ static int link_drop_foreign_config(Link *link) {
return 0;
}
+static int link_update_lldp(Link *link) {
+ int r;
+
+ assert(link);
+
+ if (!link->lldp)
+ return 0;
+
+ if (link->flags & IFF_UP) {
+ r = sd_lldp_start(link->lldp);
+ if (r > 0)
+ log_link_debug(link, "Started LLDP.");
+ } else {
+ r = sd_lldp_stop(link->lldp);
+ if (r > 0)
+ log_link_debug(link, "Stopped LLDP.");
+ }
+
+ return r;
+}
+
static int link_configure(Link *link) {
int r;
@@ -2049,6 +2279,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
+ r = link_set_proxy_arp(link);
+ if (r < 0)
+ return r;
+
r = link_set_ipv4_forward(link);
if (r < 0)
return r;
@@ -2108,8 +2342,19 @@ static int link_configure(Link *link) {
return r;
}
- if (link_lldp_enabled(link)) {
- r = sd_lldp_new(link->ifindex, link->ifname, &link->mac, &link->lldp);
+ if (link_lldp_rx_enabled(link)) {
+ r = sd_lldp_new(&link->lldp, link->ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_lldp_match_capabilities(link->lldp,
+ link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ?
+ SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS :
+ SD_LLDP_SYSTEM_CAPABILITIES_ALL);
+ if (r < 0)
+ return r;
+
+ r = sd_lldp_set_filter_address(link->lldp, &link->mac);
if (r < 0)
return r;
@@ -2117,8 +2362,11 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
- r = sd_lldp_set_callback(link->lldp,
- lldp_handler, link);
+ r = sd_lldp_set_callback(link->lldp, lldp_handler, link);
+ if (r < 0)
+ return r;
+
+ r = link_update_lldp(link);
if (r < 0)
return r;
}
@@ -2127,12 +2375,6 @@ static int link_configure(Link *link) {
r = link_acquire_conf(link);
if (r < 0)
return r;
-
- if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) {
- r = link_acquire_ipv6_conf(link);
- if (r < 0)
- return r;
- }
}
return link_enter_join_netdev(link);
@@ -2307,7 +2549,7 @@ network_file_fail:
continue;
}
- *prefixlen_str ++ = '\0';
+ *prefixlen_str++ = '\0';
r = sscanf(prefixlen_str, "%hhu", &prefixlen);
if (r != 1) {
@@ -2354,7 +2596,7 @@ network_file_fail:
continue;
}
- *prefixlen_str ++ = '\0';
+ *prefixlen_str++ = '\0';
r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime);
if (r != 5) {
@@ -2515,6 +2757,10 @@ static int link_carrier_gained(Link *link) {
link_enter_failed(link);
return r;
}
+
+ r = link_enter_set_addresses(link);
+ if (r < 0)
+ return r;
}
r = link_handle_bound_by_list(link);
@@ -2562,7 +2808,6 @@ int link_carrier_reset(Link *link) {
return 0;
}
-
int link_update(Link *link, sd_netlink_message *m) {
struct ether_addr mac;
const char *ifname;
@@ -2643,21 +2888,45 @@ int link_update(Link *link, sd_netlink_message *m) {
}
if (link->dhcp_client) {
+ const DUID *duid = link_duid(link);
+
r = sd_dhcp_client_set_mac(link->dhcp_client,
(const uint8_t *) &link->mac,
sizeof (link->mac),
ARPHRD_ETHER);
if (r < 0)
return log_link_warning_errno(link, r, "Could not update MAC address in DHCP client: %m");
+
+ r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
+ link->network->iaid,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update DUID/IAID in DHCP client: %m");
}
if (link->dhcp6_client) {
+ const DUID* duid = link_duid(link);
+
r = sd_dhcp6_client_set_mac(link->dhcp6_client,
(const uint8_t *) &link->mac,
sizeof (link->mac),
ARPHRD_ETHER);
if (r < 0)
return log_link_warning_errno(link, r, "Could not update MAC address in DHCPv6 client: %m");
+
+ r = sd_dhcp6_client_set_iaid(link->dhcp6_client,
+ link->network->iaid);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update DHCPv6 IAID: %m");
+
+ r = sd_dhcp6_client_set_duid(link->dhcp6_client,
+ duid->type,
+ duid->raw_data_len > 0 ? duid->raw_data : NULL,
+ duid->raw_data_len);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Could not update DHCPv6 DUID: %m");
}
}
}
@@ -2668,6 +2937,10 @@ int link_update(Link *link, sd_netlink_message *m) {
if (r < 0)
return r;
+ r = link_update_lldp(link);
+ if (r < 0)
+ return r;
+
carrier_gained = !had_carrier && link_has_carrier(link);
carrier_lost = had_carrier && !link_has_carrier(link);
@@ -2683,12 +2956,34 @@ int link_update(Link *link, sd_netlink_message *m) {
r = link_carrier_lost(link);
if (r < 0)
return r;
-
}
return 0;
}
+static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
+ bool space = false;
+ Iterator i;
+ Link *link;
+
+ assert(f);
+ assert(prefix);
+
+ if (hashmap_isempty(h))
+ return;
+
+ fputs(prefix, f);
+ HASHMAP_FOREACH(link, h, i) {
+ if (space)
+ fputc(' ', f);
+
+ fprintf(f, "%i", link->ifindex);
+ space = true;
+ }
+
+ fputc('\n', f);
+}
+
int link_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -2708,6 +3003,8 @@ int link_save(Link *link) {
return 0;
}
+ link_lldp_save(link);
+
admin_state = link_state_to_string(link->state);
assert(admin_state);
@@ -2887,27 +3184,8 @@ int link_save(Link *link) {
fputc('\n', f);
}
- if (!hashmap_isempty(link->bound_to_links)) {
- Link *carrier;
- bool space = false;
-
- fputs("CARRIER_BOUND_TO=", f);
- HASHMAP_FOREACH(carrier, link->bound_to_links, i)
- fputs_with_space(f, carrier->ifname, NULL, &space);
-
- fputc('\n', f);
- }
-
- if (!hashmap_isempty(link->bound_by_links)) {
- Link *carrier;
- bool space = false;
-
- fputs("CARRIER_BOUND_BY=", f);
- HASHMAP_FOREACH(carrier, link->bound_by_links, i)
- fputs_with_space(f, carrier->ifname, NULL, &space);
-
- fputc('\n', f);
- }
+ print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
+ print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
if (link->dhcp_lease) {
struct in_addr address;
@@ -2947,19 +3225,6 @@ int link_save(Link *link) {
}
}
- if (link->lldp) {
- assert(link->network);
-
- r = sd_lldp_save(link->lldp, link->lldp_file);
- if (r < 0)
- goto fail;
-
- fprintf(f,
- "LLDP_FILE=%s\n",
- link->lldp_file);
- } else
- unlink(link->lldp_file);
-
r = fflush_and_check(f);
if (r < 0)
goto fail;
@@ -2985,14 +3250,17 @@ void link_dirty(Link *link) {
assert(link);
+ /* mark manager dirty as link is dirty */
+ manager_dirty(link->manager);
+
r = set_ensure_allocated(&link->manager->dirty_links, NULL);
if (r < 0)
/* allocation errors are ignored */
return;
r = set_put(link->manager->dirty_links, link);
- if (r < 0)
- /* allocation errors are ignored */
+ if (r <= 0)
+ /* don't take another ref if the link was already dirty */
return;
link_ref(link);
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index 30f01faf2a..90cb9b93f6 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -21,14 +21,17 @@
#include <endian.h>
+#include <systemd/sd-bus.h>
#include <systemd/sd-dhcp-client.h>
#include <systemd/sd-dhcp-server.h>
#include <systemd/sd-dhcp6-client.h>
#include <systemd/sd-ipv4ll.h>
#include <systemd/sd-lldp.h>
#include <systemd/sd-ndisc.h>
+#include <systemd/sd-netlink.h>
-typedef struct Link Link;
+#include "list.h"
+#include "set.h"
typedef enum LinkState {
LINK_STATE_PENDING,
@@ -54,17 +57,18 @@ typedef enum LinkOperationalState {
_LINK_OPERSTATE_INVALID = -1
} LinkOperationalState;
-#include "networkd-address.h"
-#include "networkd-network.h"
-#include "networkd.h"
+typedef struct Manager Manager;
+typedef struct Network Network;
+typedef struct Address Address;
-struct Link {
+typedef struct Link {
Manager *manager;
int n_ref;
int ifindex;
char *ifname;
+ unsigned short iftype;
char *state_file;
struct ether_addr mac;
struct in6_addr ipv6ll_address;
@@ -111,12 +115,17 @@ struct Link {
sd_dhcp6_client *dhcp6_client;
bool rtnl_extended_attrs;
+ /* This is about LLDP reception */
sd_lldp *lldp;
char *lldp_file;
+ /* This is about LLDP transmission */
+ unsigned lldp_tx_fast; /* The LLDP txFast counter (See 802.1ab-2009, section 9.2.5.18) */
+ sd_event_source *lldp_emit_event_source;
+
Hashmap *bound_by_links;
Hashmap *bound_to_links;
-};
+} Link;
Link *link_unref(Link *link);
Link *link_ref(Link *link);
@@ -154,14 +163,6 @@ int dhcp6_configure(Link *link);
int dhcp6_request_address(Link *link);
int ndisc_configure(Link *link);
-bool link_lldp_enabled(Link *link);
-bool link_ipv4ll_enabled(Link *link);
-bool link_ipv6ll_enabled(Link *link);
-bool link_dhcp4_server_enabled(Link *link);
-bool link_dhcp4_enabled(Link *link);
-bool link_dhcp6_enabled(Link *link);
-bool link_ipv6_accept_ra_enabled(Link *link);
-
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c
new file mode 100644
index 0000000000..3aa768388b
--- /dev/null
+++ b/src/network/networkd-lldp-tx.c
@@ -0,0 +1,416 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <endian.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "hostname-util.h"
+#include "networkd-lldp-tx.h"
+#include "networkd.h"
+#include "parse-util.h"
+#include "random-util.h"
+#include "socket-util.h"
+#include "string-util.h"
+#include "unaligned.h"
+
+/* The LLDP spec calls this "txFastInit", see 9.2.5.19 */
+#define LLDP_TX_FAST_INIT 4U
+
+/* The LLDP spec calls this "msgTxHold", see 9.2.5.6 */
+#define LLDP_TX_HOLD 4U
+
+/* The jitter range to add, see 9.2.2. */
+#define LLDP_JITTER_USEC (400U * USEC_PER_MSEC)
+
+/* The LLDP spec calls this msgTxInterval, but we subtract half the jitter off it. */
+#define LLDP_TX_INTERVAL_USEC (30U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
+
+/* The LLDP spec calls this msgFastTx, but we subtract half the jitter off it. */
+#define LLDP_FAST_TX_USEC (1U * USEC_PER_SEC - LLDP_JITTER_USEC / 2)
+
+static const struct ether_addr lldp_multicast_addr[_LLDP_EMIT_MAX] = {
+ [LLDP_EMIT_NEAREST_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e }},
+ [LLDP_EMIT_NON_TPMR_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }},
+ [LLDP_EMIT_CUSTOMER_BRIDGE] = {{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }},
+};
+
+static int lldp_write_tlv_header(uint8_t **p, uint8_t id, size_t sz) {
+ assert(p);
+
+ if (id > 127)
+ return -EBADMSG;
+ if (sz > 511)
+ return -ENOBUFS;
+
+ (*p)[0] = (id << 1) | !!(sz & 256);
+ (*p)[1] = sz & 255;
+
+ *p = *p + 2;
+ return 0;
+}
+
+static int lldp_make_packet(
+ LLDPEmit mode,
+ const struct ether_addr *hwaddr,
+ const char *machine_id,
+ const char *ifname,
+ uint16_t ttl,
+ const char *port_description,
+ const char *hostname,
+ const char *pretty_hostname,
+ uint16_t system_capabilities,
+ uint16_t enabled_capabilities,
+ void **ret, size_t *sz) {
+
+ size_t machine_id_length, ifname_length, port_description_length = 0, hostname_length = 0, pretty_hostname_length = 0;
+ _cleanup_free_ void *packet = NULL;
+ struct ether_header *h;
+ uint8_t *p;
+ size_t l;
+ int r;
+
+ assert(mode > LLDP_EMIT_NO);
+ assert(mode < _LLDP_EMIT_MAX);
+ assert(hwaddr);
+ assert(machine_id);
+ assert(ifname);
+ assert(ret);
+ assert(sz);
+
+ machine_id_length = strlen(machine_id);
+ ifname_length = strlen(ifname);
+
+ if (port_description)
+ port_description_length = strlen(port_description);
+
+ if (hostname)
+ hostname_length = strlen(hostname);
+
+ if (pretty_hostname)
+ pretty_hostname_length = strlen(pretty_hostname);
+
+ l = sizeof(struct ether_header) +
+ /* Chassis ID */
+ 2 + 1 + machine_id_length +
+ /* Port ID */
+ 2 + 1 + ifname_length +
+ /* TTL */
+ 2 + 2 +
+ /* System Capabilities */
+ 2 + 4 +
+ /* End */
+ 2;
+
+ /* Port Description */
+ if (port_description)
+ l += 2 + port_description_length;
+
+ /* System Name */
+ if (hostname)
+ l += 2 + hostname_length;
+
+ /* System Description */
+ if (pretty_hostname)
+ l += 2 + pretty_hostname_length;
+
+ packet = malloc(l);
+ if (!packet)
+ return -ENOMEM;
+
+ h = (struct ether_header*) packet;
+ h->ether_type = htobe16(ETHERTYPE_LLDP);
+ memcpy(h->ether_dhost, lldp_multicast_addr + mode, ETH_ALEN);
+ memcpy(h->ether_shost, hwaddr, ETH_ALEN);
+
+ p = (uint8_t*) packet + sizeof(struct ether_header);
+
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_CHASSIS_ID, 1 + machine_id_length);
+ if (r < 0)
+ return r;
+ *(p++) = SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED;
+ p = mempcpy(p, machine_id, machine_id_length);
+
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_ID, 1 + ifname_length);
+ if (r < 0)
+ return r;
+ *(p++) = SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME;
+ p = mempcpy(p, ifname, ifname_length);
+
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_TTL, 2);
+ if (r < 0)
+ return r;
+ unaligned_write_be16(p, ttl);
+ p += 2;
+
+ if (port_description) {
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_PORT_DESCRIPTION, port_description_length);
+ if (r < 0)
+ return r;
+ p = mempcpy(p, port_description, port_description_length);
+ }
+
+ if (hostname) {
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_NAME, hostname_length);
+ if (r < 0)
+ return r;
+ p = mempcpy(p, hostname, hostname_length);
+ }
+
+ if (pretty_hostname) {
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_DESCRIPTION, pretty_hostname_length);
+ if (r < 0)
+ return r;
+ p = mempcpy(p, pretty_hostname, pretty_hostname_length);
+ }
+
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_SYSTEM_CAPABILITIES, 4);
+ if (r < 0)
+ return r;
+ unaligned_write_be16(p, system_capabilities);
+ p += 2;
+ unaligned_write_be16(p, enabled_capabilities);
+ p += 2;
+
+ r = lldp_write_tlv_header(&p, SD_LLDP_TYPE_END, 0);
+ if (r < 0)
+ return r;
+
+ assert(p == (uint8_t*) packet + l);
+
+ *ret = packet;
+ *sz = l;
+
+ packet = NULL;
+ return 0;
+}
+
+static int lldp_send_packet(
+ int ifindex,
+ const struct ether_addr *address,
+ const void *packet,
+ size_t packet_size) {
+
+ union sockaddr_union sa = {
+ .ll.sll_family = AF_PACKET,
+ .ll.sll_protocol = htobe16(ETHERTYPE_LLDP),
+ .ll.sll_ifindex = ifindex,
+ .ll.sll_halen = ETH_ALEN,
+ };
+
+ _cleanup_close_ int fd = -1;
+ ssize_t l;
+
+ assert(ifindex > 0);
+ assert(address);
+ assert(packet || packet_size <= 0);
+
+ memcpy(sa.ll.sll_addr, address, ETH_ALEN);
+
+ fd = socket(PF_PACKET, SOCK_RAW|SOCK_CLOEXEC, IPPROTO_RAW);
+ if (fd < 0)
+ return -errno;
+
+ l = sendto(fd, packet, packet_size, MSG_NOSIGNAL, &sa.sa, sizeof(sa.ll));
+ if (l < 0)
+ return -errno;
+
+ if ((size_t) l != packet_size)
+ return -EIO;
+
+ return 0;
+}
+
+static int link_send_lldp(Link *link) {
+ char machine_id_string[SD_ID128_STRING_MAX];
+ _cleanup_free_ char *hostname = NULL, *pretty_hostname = NULL;
+ _cleanup_free_ void *packet = NULL;
+ size_t packet_size = 0;
+ sd_id128_t machine_id;
+ uint16_t caps;
+ usec_t ttl;
+ int r;
+
+ assert(link);
+
+ if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO)
+ return 0;
+
+ assert(link->network->lldp_emit < _LLDP_EMIT_MAX);
+
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return r;
+
+ (void) gethostname_strict(&hostname);
+ (void) parse_env_file("/etc/machine-info", NEWLINE, "PRETTY_HOSTNAME", &pretty_hostname, NULL);
+
+ assert_cc(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1 <= (UINT16_MAX - 1) * USEC_PER_SEC);
+ ttl = DIV_ROUND_UP(LLDP_TX_INTERVAL_USEC * LLDP_TX_HOLD + 1, USEC_PER_SEC);
+
+ caps = (link->network && link->network->ip_forward != ADDRESS_FAMILY_NO) ?
+ SD_LLDP_SYSTEM_CAPABILITIES_ROUTER :
+ SD_LLDP_SYSTEM_CAPABILITIES_STATION;
+
+ r = lldp_make_packet(link->network->lldp_emit,
+ &link->mac,
+ sd_id128_to_string(machine_id, machine_id_string),
+ link->ifname,
+ (uint16_t) ttl,
+ link->network ? link->network->description : NULL,
+ hostname,
+ pretty_hostname,
+ SD_LLDP_SYSTEM_CAPABILITIES_STATION|SD_LLDP_SYSTEM_CAPABILITIES_BRIDGE|SD_LLDP_SYSTEM_CAPABILITIES_ROUTER,
+ caps,
+ &packet, &packet_size);
+ if (r < 0)
+ return r;
+
+ return lldp_send_packet(link->ifindex, lldp_multicast_addr + link->network->lldp_emit, packet, packet_size);
+}
+
+static int on_lldp_timer(sd_event_source *s, usec_t t, void *userdata) {
+ Link *link = userdata;
+ usec_t current, delay, next;
+ int r;
+
+ assert(s);
+ assert(userdata);
+
+ log_link_debug(link, "Sending LLDP packet...");
+
+ r = link_send_lldp(link);
+ if (r < 0)
+ log_link_debug_errno(link, r, "Failed to send LLDP packet, ignoring: %m");
+
+ if (link->lldp_tx_fast > 0)
+ link->lldp_tx_fast--;
+
+ assert_se(sd_event_now(sd_event_source_get_event(s), clock_boottime_or_monotonic(), &current) >= 0);
+
+ delay = link->lldp_tx_fast > 0 ? LLDP_FAST_TX_USEC : LLDP_TX_INTERVAL_USEC;
+ next = usec_add(usec_add(current, delay), (usec_t) random_u64() % LLDP_JITTER_USEC);
+
+ r = sd_event_source_set_time(s, next);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to restart LLDP timer: %m");
+
+ r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
+ if (r < 0)
+ return log_link_error_errno(link, r, "Failed to enable LLDP timer: %m");
+
+ return 0;
+}
+
+int link_lldp_emit_start(Link *link) {
+ usec_t next;
+ int r;
+
+ assert(link);
+
+ if (!link->network || link->network->lldp_emit == LLDP_EMIT_NO) {
+ link_lldp_emit_stop(link);
+ return 0;
+ }
+
+ /* Starts the LLDP transmission in "fast" mode. If it is already started, turns "fast" mode back on again. */
+
+ link->lldp_tx_fast = LLDP_TX_FAST_INIT;
+
+ next = usec_add(usec_add(now(clock_boottime_or_monotonic()), LLDP_FAST_TX_USEC),
+ (usec_t) random_u64() % LLDP_JITTER_USEC);
+
+ if (link->lldp_emit_event_source) {
+ usec_t old;
+
+ /* Lower the timeout, maybe */
+ r = sd_event_source_get_time(link->lldp_emit_event_source, &old);
+ if (r < 0)
+ return r;
+
+ if (old <= next)
+ return 0;
+
+ return sd_event_source_set_time(link->lldp_emit_event_source, next);
+ } else {
+ r = sd_event_add_time(
+ link->manager->event,
+ &link->lldp_emit_event_source,
+ clock_boottime_or_monotonic(),
+ next,
+ 0,
+ on_lldp_timer,
+ link);
+ if (r < 0)
+ return r;
+
+ (void) sd_event_source_set_description(link->lldp_emit_event_source, "lldp-tx");
+ }
+
+ return 0;
+}
+
+void link_lldp_emit_stop(Link *link) {
+ assert(link);
+
+ link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source);
+}
+
+int config_parse_lldp_emit(
+ 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) {
+
+ LLDPEmit *emit = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ if (isempty(rvalue))
+ *emit = LLDP_EMIT_NO;
+ else if (streq(rvalue, "nearest-bridge"))
+ *emit = LLDP_EMIT_NEAREST_BRIDGE;
+ else if (streq(rvalue, "non-tpmr-bridge"))
+ *emit = LLDP_EMIT_NON_TPMR_BRIDGE;
+ else if (streq(rvalue, "customer-bridge"))
+ *emit = LLDP_EMIT_CUSTOMER_BRIDGE;
+ else {
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO;
+ }
+
+ return 0;
+}
diff --git a/src/systemd-bootchart/svg.h b/src/network/networkd-lldp-tx.h
index 6e06b5ad97..4680c9d950 100644
--- a/src/systemd-bootchart/svg.h
+++ b/src/network/networkd-lldp-tx.h
@@ -3,10 +3,7 @@
/***
This file is part of systemd.
- Copyright (C) 2009-2013 Intel Corporation
-
- Authors:
- Auke Kok <auke-jan.h.kok@intel.com>
+ Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -22,14 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-int svg_do(FILE *of,
- const char *build,
- struct list_sample_data *head,
- struct ps_struct *ps_first,
- int n_samples,
- int pscount,
- int n_cpus,
- double graph_start,
- double log_start,
- double interval,
- int overrun);
+#include "networkd-link.h"
+
+typedef enum LLDPEmit {
+ LLDP_EMIT_NO,
+ LLDP_EMIT_NEAREST_BRIDGE,
+ LLDP_EMIT_NON_TPMR_BRIDGE,
+ LLDP_EMIT_CUSTOMER_BRIDGE,
+ _LLDP_EMIT_MAX,
+} LLDPEmit;
+
+int link_lldp_emit_start(Link *link);
+void link_lldp_emit_stop(Link *link);
+
+int config_parse_lldp_emit(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-manager.c b/src/network/networkd-manager.c
index c73d313c85..7af7abaa81 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -457,11 +457,9 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
break;
case RTM_DELROUTE:
-
- if (route)
- route_drop(route);
-
+ route_free(route);
break;
+
default:
assert_not_reached("Received invalid RTNL message type");
}
@@ -1037,6 +1035,8 @@ int manager_new(Manager **ret) {
if (r < 0)
return r;
+ m->duid.type = DUID_TYPE_EN;
+
*ret = m;
m = NULL;
@@ -1091,22 +1091,19 @@ static bool manager_check_idle(void *userdata) {
assert(m);
+ /* Check whether we are idle now. The only case when we decide to be idle is when there's only a loopback
+ * device around, for which we have no configuration, and which already left the PENDING state. In all other
+ * cases we are not idle. */
+
HASHMAP_FOREACH(link, m->links, i) {
- /* we are not woken on udev activity, so let's just wait for the
- * pending udev event */
+ /* We are not woken on udev activity, so let's just wait for the pending udev event */
if (link->state == LINK_STATE_PENDING)
return false;
- if (!link->network)
- continue;
+ if ((link->flags & IFF_LOOPBACK) == 0)
+ return false;
- /* we are not woken on netork activity, so let's stay around */
- if (link_lldp_enabled(link) ||
- link_ipv4ll_enabled(link) ||
- link_dhcp4_server_enabled(link) ||
- link_dhcp4_enabled(link) ||
- link_dhcp6_enabled(link) ||
- link_ipv6_accept_ra_enabled(link))
+ if (link->network)
return false;
}
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index ae647b0293..f3a4fc0fa5 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -19,11 +19,12 @@
#include <netinet/ether.h>
#include <netinet/icmp6.h>
+#include <netinet/in.h>
#include <linux/if.h>
#include <systemd/sd-ndisc.h>
-#include "networkd-link.h"
+#include "networkd.h"
static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
_cleanup_link_unref_ Link *link = userdata;
@@ -32,7 +33,7 @@ static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *
assert(link);
assert(link->ndisc_messages > 0);
- link->ndisc_messages --;
+ link->ndisc_messages--;
r = sd_netlink_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
@@ -76,15 +77,15 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr
memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8);
else {
/* see RFC4291 section 2.5.1 */
- address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0];
- address->in_addr.in6.__in6_u.__u6_addr8[8] ^= 1 << 1;
- address->in_addr.in6.__in6_u.__u6_addr8[9] = link->mac.ether_addr_octet[1];
- address->in_addr.in6.__in6_u.__u6_addr8[10] = link->mac.ether_addr_octet[2];
- address->in_addr.in6.__in6_u.__u6_addr8[11] = 0xff;
- address->in_addr.in6.__in6_u.__u6_addr8[12] = 0xfe;
- address->in_addr.in6.__in6_u.__u6_addr8[13] = link->mac.ether_addr_octet[3];
- address->in_addr.in6.__in6_u.__u6_addr8[14] = link->mac.ether_addr_octet[4];
- address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5];
+ address->in_addr.in6.s6_addr[8] = link->mac.ether_addr_octet[0];
+ address->in_addr.in6.s6_addr[8] ^= 1 << 1;
+ address->in_addr.in6.s6_addr[9] = link->mac.ether_addr_octet[1];
+ address->in_addr.in6.s6_addr[10] = link->mac.ether_addr_octet[2];
+ address->in_addr.in6.s6_addr[11] = 0xff;
+ address->in_addr.in6.s6_addr[12] = 0xfe;
+ address->in_addr.in6.s6_addr[13] = link->mac.ether_addr_octet[3];
+ address->in_addr.in6.s6_addr[14] = link->mac.ether_addr_octet[4];
+ address->in_addr.in6.s6_addr[15] = link->mac.ether_addr_octet[5];
}
address->prefixlen = prefixlen;
address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR;
@@ -98,7 +99,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr
return;
}
- link->ndisc_messages ++;
+ link->ndisc_messages++;
}
static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) {
@@ -136,7 +137,7 @@ static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *pre
return;
}
- link->ndisc_messages ++;
+ link->ndisc_messages++;
}
static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) {
@@ -156,6 +157,10 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a
if (flags & ND_RA_FLAG_MANAGED)
dhcp6_request_address(link);
+ r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
+ if (r < 0 && r != -EBUSY)
+ log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m");
+
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0 && r != -EBUSY)
log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m");
@@ -186,7 +191,7 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a
return;
}
- link->ndisc_messages ++;
+ link->ndisc_messages++;
}
static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
@@ -202,6 +207,10 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) {
case SD_NDISC_EVENT_TIMEOUT:
dhcp6_request_address(link);
+ r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address);
+ if (r < 0 && r != -EBUSY)
+ log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m");
+
r = sd_dhcp6_client_start(link->dhcp6_client);
if (r < 0 && r != -EBUSY)
log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m");
diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c
index e04e78f870..7005b165d9 100644
--- a/src/network/networkd-netdev-bond.c
+++ b/src/network/networkd-netdev-bond.c
@@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "conf-parser.h"
+#include "extract-word.h"
#include "missing.h"
#include "networkd-netdev-bond.h"
#include "string-table.h"
@@ -375,7 +376,7 @@ int config_parse_arp_ip_target_address(const char *unit,
}
LIST_PREPEND(arp_ip_target, b->arp_ip_targets, buffer);
- b->n_arp_ip_targets ++;
+ b->n_arp_ip_targets++;
buffer = NULL;
}
diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h
index cb6baea24f..b941edb344 100644
--- a/src/network/networkd-netdev-bond.h
+++ b/src/network/networkd-netdev-bond.h
@@ -20,8 +20,7 @@
***/
#include "in-addr-util.h"
-
-typedef struct Bond Bond;
+#include "list.h"
#include "networkd-netdev.h"
@@ -106,7 +105,7 @@ typedef struct ArpIpTarget {
LIST_FIELDS(struct ArpIpTarget, arp_ip_target);
} ArpIpTarget;
-struct Bond {
+typedef struct Bond {
NetDev meta;
BondMode mode;
@@ -133,8 +132,9 @@ struct Bond {
int n_arp_ip_targets;
ArpIpTarget *arp_ip_targets;
-};
+} Bond;
+DEFINE_NETDEV_CAST(BOND, Bond);
extern const NetDevVTable bond_vtable;
const char *bond_mode_to_string(BondMode d) _const_;
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index cdcd08f057..4cfd00413f 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -22,6 +22,7 @@
#include "missing.h"
#include "netlink-util.h"
+#include "networkd.h"
#include "networkd-netdev-bridge.h"
/* callback for brige netdev's parameter set */
@@ -89,6 +90,18 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m");
}
+ if (b->mcast_querier >= 0) {
+ r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_QUERIER, b->mcast_querier);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_QUERIER attribute: %m");
+ }
+
+ if (b->mcast_snooping >= 0) {
+ r = sd_netlink_message_append_u8(req, IFLA_BR_MCAST_SNOOPING, b->mcast_snooping);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MCAST_SNOOPING attribute: %m");
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
@@ -106,8 +119,20 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return r;
}
+static void bridge_init(NetDev *n) {
+ Bridge *b;
+
+ b = BRIDGE(n);
+
+ assert(b);
+
+ b->mcast_querier = -1;
+ b->mcast_snooping = -1;
+}
+
const NetDevVTable bridge_vtable = {
.object_size = sizeof(Bridge),
+ .init = bridge_init,
.sections = "Match\0NetDev\0Bridge\0",
.post_create = netdev_bridge_post_create,
.create_type = NETDEV_CREATE_MASTER,
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index b2bf7e15f1..f2ae21fc50 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,18 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-typedef struct Bridge Bridge;
-
#include "networkd-netdev.h"
-struct Bridge {
+typedef struct Bridge {
NetDev meta;
+ int mcast_querier;
+ int mcast_snooping;
+
usec_t forward_delay;
usec_t hello_time;
usec_t max_age;
-};
+} Bridge;
+DEFINE_NETDEV_CAST(BRIDGE, Bridge);
extern const NetDevVTable bridge_vtable;
diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h
index 29f75a149b..efe302267e 100644
--- a/src/network/networkd-netdev-dummy.h
+++ b/src/network/networkd-netdev-dummy.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,14 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-typedef struct Dummy Dummy;
-
#include "networkd-netdev.h"
-struct Dummy {
+typedef struct Dummy {
NetDev meta;
-};
+} Dummy;
+DEFINE_NETDEV_CAST(DUMMY, Dummy);
extern const NetDevVTable dummy_vtable;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 8f506af092..ba04bb0165 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -1,11 +1,17 @@
%{
#include <stddef.h>
#include "conf-parser.h"
-#include "networkd-netdev.h"
-#include "networkd-netdev-tunnel.h"
+#include "network-internal.h"
#include "networkd-netdev-bond.h"
+#include "networkd-netdev-ipvlan.h"
#include "networkd-netdev-macvlan.h"
-#include "network-internal.h"
+#include "networkd-netdev-tunnel.h"
+#include "networkd-netdev-tuntap.h"
+#include "networkd-netdev-veth.h"
+#include "networkd-netdev-vlan.h"
+#include "networkd-netdev-vxlan.h"
+#include "networkd-netdev-bridge.h"
+#include "networkd-netdev.h"
%}
struct ConfigPerfItem;
%null_strings
@@ -92,3 +98,5 @@ Bond.LearnPacketIntervalSec, config_parse_sec, 0,
Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time)
Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age)
Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay)
+Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
+Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping)
diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h
index 5b85ef2150..10d4079844 100644
--- a/src/network/networkd-netdev-ipvlan.h
+++ b/src/network/networkd-netdev-ipvlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,10 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-typedef struct IPVlan IPVlan;
-
#include "missing.h"
#include "networkd-netdev.h"
@@ -31,12 +29,13 @@ typedef enum IPVlanMode {
_NETDEV_IPVLAN_MODE_INVALID = -1
} IPVlanMode;
-struct IPVlan {
+typedef struct IPVlan {
NetDev meta;
IPVlanMode mode;
-};
+} IPVlan;
+DEFINE_NETDEV_CAST(IPVLAN, IPVlan);
extern const NetDevVTable ipvlan_vtable;
const char *ipvlan_mode_to_string(IPVlanMode d) _const_;
diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h
index 8b42684de6..3663f4f051 100644
--- a/src/network/networkd-netdev-macvlan.h
+++ b/src/network/networkd-netdev-macvlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct MacVlan MacVlan;
#include "networkd-netdev.h"
@@ -38,6 +38,8 @@ struct MacVlan {
MacVlanMode mode;
};
+DEFINE_NETDEV_CAST(MACVLAN, MacVlan);
+DEFINE_NETDEV_CAST(MACVTAP, MacVlan);
extern const NetDevVTable macvlan_vtable;
extern const NetDevVTable macvtap_vtable;
diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c
index 408ceaf55e..26a9a972f1 100644
--- a/src/network/networkd-netdev-tunnel.c
+++ b/src/network/networkd-netdev-tunnel.c
@@ -54,7 +54,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin
assert(link);
assert(m);
assert(t);
- assert(t->family == AF_INET || t->family != -1);
+ assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
if (r < 0)
@@ -87,7 +87,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink
assert(link);
assert(m);
assert(t);
- assert(t->family == AF_INET || t->family != -1);
+ assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
if (r < 0)
@@ -124,7 +124,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink
t = GRETAP(netdev);
assert(t);
- assert(t->family == AF_INET || t->family != -1);
+ assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
assert(link);
assert(m);
@@ -497,7 +497,7 @@ static void ipip_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
- t->family = -1;
+ t->family = AF_UNSPEC;
}
static void sit_init(NetDev *n) {
@@ -507,7 +507,7 @@ static void sit_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
- t->family = -1;
+ t->family = AF_UNSPEC;
}
static void vti_init(NetDev *n) {
@@ -538,7 +538,7 @@ static void gre_init(NetDev *n) {
assert(t);
t->pmtudisc = true;
- t->family = -1;
+ t->family = AF_UNSPEC;
}
static void ip6gre_init(NetDev *n) {
diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h
index ea1d9a79e7..7d31e7b687 100644
--- a/src/network/networkd-netdev-tunnel.h
+++ b/src/network/networkd-netdev-tunnel.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,9 +19,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
-typedef struct Tunnel Tunnel;
+#include "in-addr-util.h"
#include "networkd-netdev.h"
@@ -37,7 +37,7 @@ typedef enum IPv6FlowLabel {
_NETDEV_IPV6_FLOWLABEL_INVALID = -1,
} IPv6FlowLabel;
-struct Tunnel {
+typedef struct Tunnel {
NetDev meta;
uint8_t encap_limit;
@@ -56,8 +56,17 @@ struct Tunnel {
bool pmtudisc;
bool copy_dscp;
-};
-
+} Tunnel;
+
+DEFINE_NETDEV_CAST(IPIP, Tunnel);
+DEFINE_NETDEV_CAST(GRE, Tunnel);
+DEFINE_NETDEV_CAST(GRETAP, Tunnel);
+DEFINE_NETDEV_CAST(IP6GRE, Tunnel);
+DEFINE_NETDEV_CAST(IP6GRETAP, Tunnel);
+DEFINE_NETDEV_CAST(SIT, Tunnel);
+DEFINE_NETDEV_CAST(VTI, Tunnel);
+DEFINE_NETDEV_CAST(VTI6, Tunnel);
+DEFINE_NETDEV_CAST(IP6TNL, Tunnel);
extern const NetDevVTable ipip_vtable;
extern const NetDevVTable sit_vtable;
extern const NetDevVTable vti_vtable;
diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c
index ab9a1b0426..088a4d8d32 100644
--- a/src/network/networkd-netdev-tuntap.c
+++ b/src/network/networkd-netdev-tuntap.c
@@ -17,9 +17,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <fcntl.h>
+#include <linux/if_tun.h>
#include <net/if.h>
+#include <netinet/if_ether.h>
#include <sys/ioctl.h>
-#include <linux/if_tun.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "alloc-util.h"
#include "fd-util.h"
@@ -87,7 +91,7 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
assert(t);
- if(t->user_name) {
+ if (t->user_name) {
user = t->user_name;
@@ -126,7 +130,7 @@ static int netdev_create_tuntap(NetDev *netdev) {
int r;
r = netdev_fill_tuntap_message(netdev, &ifr);
- if(r < 0)
+ if (r < 0)
return r;
return netdev_tuntap_add(netdev, &ifr);
diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h
index b970b0ce3b..120f00a353 100644
--- a/src/network/networkd-netdev-tuntap.h
+++ b/src/network/networkd-netdev-tuntap.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct TunTap TunTap;
#include "networkd-netdev.h"
@@ -34,5 +34,7 @@ struct TunTap {
bool vnet_hdr;
};
+DEFINE_NETDEV_CAST(TUN, TunTap);
+DEFINE_NETDEV_CAST(TAP, TunTap);
extern const NetDevVTable tun_vtable;
extern const NetDevVTable tap_vtable;
diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h
index f7fdf906ab..e69bfbc8f0 100644
--- a/src/network/networkd-netdev-veth.h
+++ b/src/network/networkd-netdev-veth.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct Veth Veth;
#include "networkd-netdev.h"
@@ -30,4 +30,5 @@ struct Veth {
struct ether_addr *mac_peer;
};
+DEFINE_NETDEV_CAST(VETH, Veth);
extern const NetDevVTable veth_vtable;
diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h
index 8701c4b785..73aacf4a0f 100644
--- a/src/network/networkd-netdev-vlan.h
+++ b/src/network/networkd-netdev-vlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct VLan VLan;
#include "networkd-netdev.h"
@@ -31,4 +31,5 @@ struct VLan {
uint64_t id;
};
+DEFINE_NETDEV_CAST(VLAN, VLan);
extern const NetDevVTable vlan_vtable;
diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c
index 223d60f4db..363a6bdde6 100644
--- a/src/network/networkd-netdev-vxlan.c
+++ b/src/network/networkd-netdev-vxlan.c
@@ -23,8 +23,10 @@
#include "conf-parser.h"
#include "alloc-util.h"
+#include "extract-word.h"
#include "parse-util.h"
#include "missing.h"
+
#include "networkd-link.h"
#include "networkd-netdev-vxlan.h"
@@ -54,13 +56,13 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LINK attribute: %m");
- if(v->ttl) {
+ if (v->ttl) {
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TTL, v->ttl);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TTL attribute: %m");
}
- if(v->tos) {
+ if (v->tos) {
r = sd_netlink_message_append_u8(m, IFLA_VXLAN_TOS, v->tos);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_TOS attribute: %m");
@@ -86,7 +88,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_L3MISS attribute: %m");
- if(v->fdb_ageing) {
+ if (v->fdb_ageing) {
r = sd_netlink_message_append_u32(m, IFLA_VXLAN_AGEING, v->fdb_ageing / USEC_PER_SEC);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m");
diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h
index 459ce53f5e..4614c66fd1 100644
--- a/src/network/networkd-netdev-vxlan.h
+++ b/src/network/networkd-netdev-vxlan.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
typedef struct VxLan VxLan;
#include "in-addr-util.h"
@@ -55,6 +55,7 @@ struct VxLan {
struct ifla_vxlan_port_range port_range;
};
+DEFINE_NETDEV_CAST(VXLAN, VxLan);
extern const NetDevVTable vxlan_vtable;
int config_parse_vxlan_group_address(const char *unit,
diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c
index d7d014f05d..851a36290c 100644
--- a/src/network/networkd-netdev.c
+++ b/src/network/networkd-netdev.c
@@ -656,7 +656,7 @@ static int netdev_load_one(Manager *manager, const char *filename) {
if (!netdev->filename)
return log_oom();
- if (!netdev->mac) {
+ if (!netdev->mac && netdev->kind != NETDEV_KIND_VLAN) {
r = netdev_get_mac(netdev->ifname, &netdev->mac);
if (r < 0)
return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h
index 3eacee824b..ab3f068167 100644
--- a/src/network/networkd-netdev.h
+++ b/src/network/networkd-netdev.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,17 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
+#include <systemd/sd-netlink.h>
#include "list.h"
-
-typedef struct NetDev NetDev;
-typedef struct NetDevVTable NetDevVTable;
-
-#include "networkd-link.h"
-#include "networkd.h"
+#include "time-util.h"
typedef struct netdev_join_callback netdev_join_callback;
+typedef struct Link Link;
struct netdev_join_callback {
sd_netlink_message_handler_t callback;
@@ -78,7 +76,10 @@ typedef enum NetDevCreateType {
_NETDEV_CREATE_INVALID = -1,
} NetDevCreateType;
-struct NetDev {
+typedef struct Manager Manager;
+typedef struct Condition Condition;
+
+typedef struct NetDev {
Manager *manager;
int n_ref;
@@ -99,20 +100,9 @@ struct NetDev {
int ifindex;
LIST_HEAD(netdev_join_callback, callbacks);
-};
+} NetDev;
-#include "networkd-netdev-bond.h"
-#include "networkd-netdev-bridge.h"
-#include "networkd-netdev-dummy.h"
-#include "networkd-netdev-ipvlan.h"
-#include "networkd-netdev-macvlan.h"
-#include "networkd-netdev-tunnel.h"
-#include "networkd-netdev-tuntap.h"
-#include "networkd-netdev-veth.h"
-#include "networkd-netdev-vlan.h"
-#include "networkd-netdev-vxlan.h"
-
-struct NetDevVTable {
+typedef struct NetDevVTable {
/* How much memory does an object of this unit type need */
size_t object_size;
@@ -144,14 +134,14 @@ struct NetDevVTable {
/* verify that compulsory configuration options were specified */
int (*config_verify)(NetDev *netdev, const char *filename);
-};
+} NetDevVTable;
extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
#define NETDEV_VTABLE(n) netdev_vtable[(n)->kind]
/* For casting a netdev into the various netdev kinds */
-#define DEFINE_CAST(UPPERCASE, MixedCase) \
+#define DEFINE_NETDEV_CAST(UPPERCASE, MixedCase) \
static inline MixedCase* UPPERCASE(NetDev *n) { \
if (_unlikely_(!n || n->kind != NETDEV_KIND_##UPPERCASE)) \
return NULL; \
@@ -162,27 +152,6 @@ extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
/* For casting the various netdev kinds into a netdev */
#define NETDEV(n) (&(n)->meta)
-DEFINE_CAST(BRIDGE, Bridge);
-DEFINE_CAST(BOND, Bond);
-DEFINE_CAST(VLAN, VLan);
-DEFINE_CAST(MACVLAN, MacVlan);
-DEFINE_CAST(MACVTAP, MacVlan);
-DEFINE_CAST(IPVLAN, IPVlan);
-DEFINE_CAST(VXLAN, VxLan);
-DEFINE_CAST(IPIP, Tunnel);
-DEFINE_CAST(GRE, Tunnel);
-DEFINE_CAST(GRETAP, Tunnel);
-DEFINE_CAST(IP6GRE, Tunnel);
-DEFINE_CAST(IP6GRETAP, Tunnel);
-DEFINE_CAST(SIT, Tunnel);
-DEFINE_CAST(VTI, Tunnel);
-DEFINE_CAST(VTI6, Tunnel);
-DEFINE_CAST(IP6TNL, Tunnel);
-DEFINE_CAST(VETH, Veth);
-DEFINE_CAST(DUMMY, Dummy);
-DEFINE_CAST(TUN, TunTap);
-DEFINE_CAST(TAP, TunTap);
-
int netdev_load(Manager *manager);
void netdev_drop(NetDev *netdev);
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index 409df1709f..03e4e3b39f 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -2,6 +2,7 @@
#include <stddef.h>
#include "conf-parser.h"
#include "networkd.h"
+#include "networkd-conf.h"
#include "network-internal.h"
%}
struct ConfigPerfItem;
@@ -40,7 +41,8 @@ Network.DHCPServer, config_parse_bool,
Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local)
Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route)
Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token)
-Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp)
+Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode)
+Network.EmitLLDP, config_parse_lldp_emit, 0, offsetof(Network, lldp_emit)
Network.Address, config_parse_address, 0, 0
Network.Gateway, config_parse_gateway, 0, 0
Network.Domains, config_parse_domains, 0, 0
@@ -56,17 +58,20 @@ Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions,
Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits)
Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit)
+Network.ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp)
Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier)
Address.Address, config_parse_address, 0, 0
Address.Peer, config_parse_address, 0, 0
Address.Broadcast, config_parse_broadcast, 0, 0
Address.Label, config_parse_label, 0, 0
+Address.PreferredLifetime, config_parse_lifetime, 0, 0
Route.Gateway, config_parse_gateway, 0, 0
Route.Destination, config_parse_destination, 0, 0
Route.Source, config_parse_destination, 0, 0
Route.Metric, config_parse_route_priority, 0, 0
Route.Scope, config_parse_route_scope, 0, 0
Route.PreferredSource, config_parse_preferred_src, 0, 0
+Route.Table, config_parse_route_table, 0, 0
DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns)
DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp)
@@ -79,14 +84,18 @@ DHCP.Hostname, config_parse_hostname,
DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast)
DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical)
DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier)
+DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid.type)
+DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid)
DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric)
DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone)
+DHCP.IAID, config_parse_iaid, 0, offsetof(Network, iaid)
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns)
DHCPServer.DNS, config_parse_dhcp_server_dns, 0, 0
DHCPServer.EmitNTP, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_ntp)
DHCPServer.NTP, config_parse_dhcp_server_ntp, 0, 0
+DHCPServer.EmitRouter, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_router)
DHCPServer.EmitTimezone, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_timezone)
DHCPServer.Timezone, config_parse_timezone, 0, offsetof(Network, dhcp_server_timezone)
DHCPServer.PoolOffset, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_offset)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 4315790093..dd89b3770c 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -113,12 +113,15 @@ static int network_load_one(Manager *manager, const char *filename) {
network->dhcp_server_emit_dns = true;
network->dhcp_server_emit_ntp = true;
+ network->dhcp_server_emit_router = true;
network->dhcp_server_emit_timezone = true;
network->use_bpdu = true;
network->allow_port_to_be_root = true;
network->unicast_flood = true;
+ network->lldp_mode = LLDP_MODE_ROUTERS_ONLY;
+
network->llmnr = RESOLVE_SUPPORT_YES;
network->mdns = RESOLVE_SUPPORT_NO;
network->dnssec_mode = _DNSSEC_MODE_INVALID;
@@ -129,6 +132,8 @@ static int network_load_one(Manager *manager, const char *filename) {
network->ipv6_accept_ra = -1;
network->ipv6_dad_transmits = -1;
network->ipv6_hop_limit = -1;
+ network->duid.type = _DUID_TYPE_INVALID;
+ network->proxy_arp = -1;
r = config_parse(NULL, filename, file,
"Match\0"
@@ -394,6 +399,19 @@ int network_apply(Manager *manager, Network *network, Link *link) {
return 0;
}
+bool network_has_static_ipv6_addresses(Network *network) {
+ Address *address;
+
+ assert(network);
+
+ LIST_FOREACH(addresses, address, network->static_addresses) {
+ if (address->family == AF_INET6)
+ return true;
+ }
+
+ return false;
+}
+
int config_parse_netdev(const char *unit,
const char *filename,
unsigned line,
@@ -627,10 +645,7 @@ int config_parse_ipv4ll(
* config_parse_address_family_boolean(), except that it
* applies only to IPv4 */
- if (parse_boolean(rvalue))
- *link_local |= ADDRESS_FAMILY_IPV4;
- else
- *link_local &= ~ADDRESS_FAMILY_IPV4;
+ SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, parse_boolean(rvalue));
return 0;
}
@@ -994,6 +1009,10 @@ int config_parse_dnssec_negative_trust_anchors(
continue;
}
+ r = set_ensure_allocated(&n->dnssec_negative_trust_anchors, &dns_name_hash_ops);
+ if (r < 0)
+ return log_oom();
+
r = set_put(n->dnssec_negative_trust_anchors, w);
if (r < 0)
return log_oom();
@@ -1013,3 +1032,13 @@ static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES);
+
+DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting.");
+
+static const char* const lldp_mode_table[_LLDP_MODE_MAX] = {
+ [LLDP_MODE_NO] = "no",
+ [LLDP_MODE_YES] = "yes",
+ [LLDP_MODE_ROUTERS_ONLY] = "routers-only",
+};
+
+DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES);
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 03c3f206c3..177bc11ec4 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -19,17 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <systemd/sd-bus.h>
+#include "udev.h"
+
#include "condition.h"
+#include "dhcp-identifier.h"
+#include "hashmap.h"
#include "resolve-util.h"
-typedef struct Network Network;
-
#include "networkd-address.h"
#include "networkd-fdb.h"
+#include "networkd-lldp-tx.h"
#include "networkd-netdev.h"
#include "networkd-route.h"
#include "networkd-util.h"
-#include "networkd.h"
#define DHCP_ROUTE_METRIC 1024
#define IPV4LL_ROUTE_METRIC 2048
@@ -58,6 +61,24 @@ typedef enum DHCPUseDomains {
_DHCP_USE_DOMAINS_INVALID = -1,
} DHCPUseDomains;
+typedef enum LLDPMode {
+ LLDP_MODE_NO = 0,
+ LLDP_MODE_YES = 1,
+ LLDP_MODE_ROUTERS_ONLY = 2,
+ _LLDP_MODE_MAX,
+ _LLDP_MODE_INVALID = -1,
+} LLDPMode;
+
+typedef struct DUID {
+ /* Value of Type in [DHCP] section */
+ DUIDType type;
+
+ uint8_t raw_data_len;
+ uint8_t raw_data[MAX_DUID_LEN];
+} DUID;
+
+typedef struct Manager Manager;
+
struct Network {
Manager *manager;
@@ -106,6 +127,7 @@ struct Network {
bool dhcp_server_emit_ntp;
struct in_addr *dhcp_server_ntp;
unsigned n_dhcp_server_ntp;
+ bool dhcp_server_emit_router;
bool dhcp_server_emit_timezone;
char *dhcp_server_timezone;
usec_t dhcp_server_default_lease_time_usec, dhcp_server_max_lease_time_usec;
@@ -130,14 +152,18 @@ struct Network {
int ipv6_accept_ra;
int ipv6_dad_transmits;
int ipv6_hop_limit;
+ int proxy_arp;
union in_addr_union ipv6_token;
IPv6PrivacyExtensions ipv6_privacy_extensions;
struct ether_addr *mac;
unsigned mtu;
+ uint32_t iaid;
+ DUID duid;
- bool lldp;
+ LLDPMode lldp_mode; /* LLDP reception */
+ LLDPEmit lldp_emit; /* LLDP transmission */
LIST_HEAD(Address, static_addresses);
LIST_HEAD(Route, static_routes);
@@ -168,6 +194,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret);
int network_get(Manager *manager, struct udev_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
int network_apply(Manager *manager, Network *network, Link *link);
+bool network_has_static_ipv6_addresses(Network *network);
+
int config_parse_netdev(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_tunnel(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -181,6 +209,7 @@ int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigne
int config_parse_dhcp_server_ntp(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_dnssec_negative_trust_anchors(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_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_lldp_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);
/* Legacy IPv4LL support */
int config_parse_ipv4ll(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);
@@ -197,3 +226,6 @@ IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_;
const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_;
DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_;
+
+const char* lldp_mode_to_string(LLDPMode m) _const_;
+LLDPMode lldp_mode_from_string(const char *s) _pure_;
diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c
index e065a5a5a9..f001de772a 100644
--- a/src/network/networkd-route.c
+++ b/src/network/networkd-route.c
@@ -52,8 +52,7 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
int r;
if (section) {
- route = hashmap_get(network->routes_by_section,
- UINT_TO_PTR(section));
+ route = hashmap_get(network->routes_by_section, UINT_TO_PTR(section));
if (route) {
*ret = route;
route = NULL;
@@ -67,16 +66,18 @@ int route_new_static(Network *network, unsigned section, Route **ret) {
return r;
route->protocol = RTPROT_STATIC;
- route->network = network;
-
- LIST_PREPEND(routes, network->static_routes, route);
if (section) {
route->section = section;
- hashmap_put(network->routes_by_section,
- UINT_TO_PTR(route->section), route);
+
+ r = hashmap_put(network->routes_by_section, UINT_TO_PTR(route->section), route);
+ if (r < 0)
+ return r;
}
+ route->network = network;
+ LIST_PREPEND(routes, network->static_routes, route);
+
*ret = route;
route = NULL;
@@ -323,12 +324,6 @@ int route_update(Route *route,
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_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
@@ -374,7 +369,7 @@ int route_remove(Route *route, Link *link,
else if (route->family == AF_INET6)
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");
+ return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
if (r < 0)
@@ -411,15 +406,45 @@ int route_remove(Route *route, Link *link,
return 0;
}
+static int route_expire_callback(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
+ Link *link = userdata;
+ int r;
+
+ assert(rtnl);
+ assert(m);
+ assert(link);
+ assert(link->ifname);
+ assert(link->link_messages > 0);
+
+ if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+ return 1;
+
+ link->link_messages--;
+
+ r = sd_netlink_message_get_errno(m);
+ if (r < 0 && r != -EEXIST)
+ log_link_warning_errno(link, r, "could not remove route: %m");
+
+ if (link->link_messages == 0)
+ log_link_debug(link, "route removed");
+
+ return 1;
+}
+
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);
+ r = route_remove(route, route->link, route_expire_callback);
if (r < 0)
log_warning_errno(r, "Could not remove route: %m");
+ else {
+ /* route may not be exist in kernel. If we fail still remove it */
+ route->link->link_messages++;
+ route_free(route);
+ }
return 1;
}
@@ -450,6 +475,10 @@ int route_configure(Route *route, Link *link,
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");
+
+ r = sd_rtnl_message_route_set_family(req, route->family);
+ if (r < 0)
+ return log_error_errno(r, "Could not set route family: %m");
}
if (route->dst_prefixlen) {
@@ -493,7 +522,26 @@ int route_configure(Route *route, Link *link,
r = sd_rtnl_message_route_set_flags(req, route->flags);
if (r < 0)
- return log_error_errno(r, "Colud not set flags: %m");
+ return log_error_errno(r, "Could not set flags: %m");
+
+ if (route->table != RT_TABLE_DEFAULT) {
+
+ if (route->table < 256) {
+ r = sd_rtnl_message_route_set_table(req, route->table);
+ if (r < 0)
+ return log_error_errno(r, "Could not set route table: %m");
+ } else {
+
+ r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
+ if (r < 0)
+ return log_error_errno(r, "Could not set route table: %m");
+
+ /* Table attribute to allow more than 256. */
+ r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
+ if (r < 0)
+ return log_error_errno(r, "Could not append RTA_TABLE attribute: %m");
+ }
+ }
r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
if (r < 0)
@@ -776,3 +824,42 @@ int config_parse_route_scope(const char *unit,
return 0;
}
+
+int config_parse_route_table(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_route_free_ Route *n = NULL;
+ Network *network = userdata;
+ uint32_t k;
+ int r;
+
+ assert(filename);
+ assert(section);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ r = route_new_static(network, section_line, &n);
+ if (r < 0)
+ return r;
+
+ r = safe_atou32(rvalue, &k);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue);
+ return 0;
+ }
+
+ n->table = k;
+
+ n = NULL;
+
+ return 0;
+}
diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h
index a4a4bf2653..39de8363ed 100644
--- a/src/network/networkd-route.h
+++ b/src/network/networkd-route.h
@@ -22,7 +22,6 @@
typedef struct Route Route;
#include "networkd-network.h"
-#include "networkd.h"
struct Route {
Network *network;
@@ -37,7 +36,7 @@ struct Route {
unsigned char protocol; /* RTPROT_* */
unsigned char tos;
uint32_t priority; /* note that ip(8) calls this 'metric' */
- unsigned char table;
+ uint32_t table;
unsigned char pref;
unsigned flags;
@@ -62,7 +61,6 @@ int route_get(Link *link, int family, union in_addr_union *dst, unsigned char ds
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);
@@ -74,3 +72,4 @@ int config_parse_preferred_src(const char *unit, const char *filename, unsigned
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);
+int config_parse_route_table(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-wait-online.h b/src/network/networkd-wait-online.h
index f1ea4a6494..7ac7f4018a 100644
--- a/src/network/networkd-wait-online.h
+++ b/src/network/networkd-wait-online.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <systemd/sd-event.h>
#include <systemd/sd-netlink.h>
#include <systemd/sd-network.h>
diff --git a/src/network/networkd.c b/src/network/networkd.c
index 6cf396e478..9f5c75ac3d 100644
--- a/src/network/networkd.c
+++ b/src/network/networkd.c
@@ -21,6 +21,7 @@
#include "capability-util.h"
#include "networkd.h"
+#include "networkd-conf.h"
#include "signal-util.h"
#include "user-util.h"
@@ -89,6 +90,10 @@ int main(int argc, char *argv[]) {
goto out;
}
+ r = manager_parse_config_file(m);
+ if (r < 0)
+ log_warning_errno(r, "Failed to parse configuration file: %m");
+
r = manager_load_config(m);
if (r < 0) {
log_error_errno(r, "Could not load configuration files: %m");
diff --git a/src/network/networkd.h b/src/network/networkd.h
index efe70970c3..b61e03920e 100644
--- a/src/network/networkd.h
+++ b/src/network/networkd.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,25 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <arpa/inet.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-event.h>
#include <systemd/sd-netlink.h>
+#include "udev.h"
+#include "dhcp-identifier.h"
#include "hashmap.h"
#include "list.h"
-#include "udev.h"
-
-typedef struct Manager Manager;
#include "networkd-address-pool.h"
#include "networkd-link.h"
+#include "networkd-netdev-bond.h"
+#include "networkd-netdev-bridge.h"
+#include "networkd-netdev-dummy.h"
+#include "networkd-netdev-ipvlan.h"
+#include "networkd-netdev-macvlan.h"
+#include "networkd-netdev-tunnel.h"
+#include "networkd-netdev-tuntap.h"
+#include "networkd-netdev-veth.h"
+#include "networkd-netdev-vlan.h"
+#include "networkd-netdev-vxlan.h"
#include "networkd-network.h"
#include "networkd-util.h"
+extern const char* const network_dirs[];
+
struct Manager {
sd_netlink *rtnl;
sd_event *event;
@@ -61,11 +72,16 @@ struct Manager {
LIST_HEAD(AddressPool, address_pools);
usec_t network_dirs_ts_usec;
-};
-extern const char* const network_dirs[];
+ DUID duid;
+};
-/* Manager */
+static inline const DUID* link_duid(const Link *link) {
+ if (link->network->duid.type != _DUID_TYPE_INVALID)
+ return &link->network->duid;
+ else
+ return &link->manager->duid;
+}
extern const sd_bus_vtable manager_vtable[];
diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c
index ecbbe6c3c9..adbe09a5e1 100644
--- a/src/network/test-network-tables.c
+++ b/src/network/test-network-tables.c
@@ -9,7 +9,7 @@
int main(int argc, char **argv) {
test_table(bond_mode, NETDEV_BOND_MODE);
- /* test_table(link_state, LINK_STATE); -- not a reversible mapping */
+ /* test_table(link_state, LINK_STATE); — not a reversible mapping */
test_table(link_operstate, LINK_OPERSTATE);
test_table(address_family_boolean, ADDRESS_FAMILY_BOOLEAN);
test_table(netdev_kind, NETDEV_KIND);
diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c
new file mode 100644
index 0000000000..0e1a18457d
--- /dev/null
+++ b/src/network/test-networkd-conf.c
@@ -0,0 +1,142 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "hexdecoct.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "ether-addr-util.h"
+
+#include "networkd-conf.h"
+#include "networkd-network.h"
+#include "network-internal.h"
+
+static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected) {
+ DUIDType actual = 0;
+ int r;
+
+ r = config_parse_duid_type("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL);
+ log_info_errno(r, "\"%s\" → %d (%m)", rvalue, actual);
+ assert_se(r == ret);
+ assert_se(expected == actual);
+}
+
+static void test_config_parse_duid_type(void) {
+ test_config_parse_duid_type_one("", 0, 0);
+ test_config_parse_duid_type_one("link-layer-time", 0, DUID_TYPE_LLT);
+ test_config_parse_duid_type_one("vendor", 0, DUID_TYPE_EN);
+ test_config_parse_duid_type_one("link-layer", 0, DUID_TYPE_LL);
+ test_config_parse_duid_type_one("uuid", 0, DUID_TYPE_UUID);
+ test_config_parse_duid_type_one("foo", 0, 0);
+}
+
+static void test_config_parse_duid_rawdata_one(const char *rvalue, int ret, const DUID* expected) {
+ DUID actual = {};
+ int r;
+ _cleanup_free_ char *d = NULL;
+
+ r = config_parse_duid_rawdata("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL);
+ d = hexmem(actual.raw_data, actual.raw_data_len);
+ log_info_errno(r, "\"%s\" → \"%s\" (%m)",
+ rvalue, strnull(d));
+ assert_se(r == ret);
+ if (expected) {
+ assert_se(actual.raw_data_len == expected->raw_data_len);
+ assert_se(memcmp(actual.raw_data, expected->raw_data, expected->raw_data_len) == 0);
+ }
+}
+
+static void test_config_parse_hwaddr_one(const char *rvalue, int ret, const struct ether_addr* expected) {
+ struct ether_addr *actual = NULL;
+ int r;
+
+ r = config_parse_hwaddr("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &actual, NULL);
+ assert_se(ret == r);
+ if (expected) {
+ assert_se(actual);
+ assert(ether_addr_equal(expected, actual));
+ } else {
+ assert_se(actual == NULL);
+ }
+ free(actual);
+}
+
+#define BYTES_0_128 "0:1:2:3:4:5:6:7:8:9:a:b:c:d:e:f:10:11:12:13:14:15:16:17:18:19:1a:1b:1c:1d:1e:1f:20:21:22:23:24:25:26:27:28:29:2a:2b:2c:2d:2e:2f:30:31:32:33:34:35:36:37:38:39:3a:3b:3c:3d:3e:3f:40:41:42:43:44:45:46:47:48:49:4a:4b:4c:4d:4e:4f:50:51:52:53:54:55:56:57:58:59:5a:5b:5c:5d:5e:5f:60:61:62:63:64:65:66:67:68:69:6a:6b:6c:6d:6e:6f:70:71:72:73:74:75:76:77:78:79:7a:7b:7c:7d:7e:7f:80"
+
+#define BYTES_1_128 {0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80}
+
+static void test_config_parse_duid_rawdata(void) {
+ test_config_parse_duid_rawdata_one("", 0, &(DUID){});
+ test_config_parse_duid_rawdata_one("00:11:22:33:44:55:66:77", 0,
+ &(DUID){0, 8, {0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77}});
+ test_config_parse_duid_rawdata_one("00:11:22:", 0,
+ &(DUID){0, 3, {0x00,0x11,0x22}});
+ test_config_parse_duid_rawdata_one("000:11:22", 0, &(DUID){}); /* error, output is all zeros */
+ test_config_parse_duid_rawdata_one("00:111:22", 0, &(DUID){});
+ test_config_parse_duid_rawdata_one("0:1:2:3:4:5:6:7", 0,
+ &(DUID){0, 8, {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7}});
+ test_config_parse_duid_rawdata_one("11::", 0, &(DUID){0, 1, {0x11}}); /* FIXME: should this be an error? */
+ test_config_parse_duid_rawdata_one("abcdef", 0, &(DUID){});
+ test_config_parse_duid_rawdata_one(BYTES_0_128, 0, &(DUID){});
+ test_config_parse_duid_rawdata_one(BYTES_0_128 + 2, 0, &(DUID){0, 128, BYTES_1_128});
+}
+
+static void test_config_parse_hwaddr(void) {
+ const struct ether_addr t[] = {
+ { .ether_addr_octet = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff } },
+ { .ether_addr_octet = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab } },
+ };
+ test_config_parse_hwaddr_one("", 0, NULL);
+ test_config_parse_hwaddr_one("no:ta:ma:ca:dd:re", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:fx", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff", 0, &t[0]);
+ test_config_parse_hwaddr_one(" aa:bb:cc:dd:ee:ff", 0, &t[0]);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\n", 0, &t[0]);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff \t\nxxx", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc: dd:ee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:d d:ee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee", 0, NULL);
+ test_config_parse_hwaddr_one("9:aa:bb:cc:dd:ee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("aa:bb:cc:dd:ee:ff:gg", 0, NULL);
+ test_config_parse_hwaddr_one("aa:Bb:CC:dd:ee:ff", 0, &t[0]);
+ test_config_parse_hwaddr_one("01:23:45:67:89:aB", 0, &t[1]);
+ test_config_parse_hwaddr_one("1:23:45:67:89:aB", 0, &t[1]);
+ test_config_parse_hwaddr_one("aa-bb-cc-dd-ee-ff", 0, &t[0]);
+ test_config_parse_hwaddr_one("AA-BB-CC-DD-EE-FF", 0, &t[0]);
+ test_config_parse_hwaddr_one("01-23-45-67-89-ab", 0, &t[1]);
+ test_config_parse_hwaddr_one("aabb.ccdd.eeff", 0, &t[0]);
+ test_config_parse_hwaddr_one("0123.4567.89ab", 0, &t[1]);
+ test_config_parse_hwaddr_one("123.4567.89ab.", 0, NULL);
+ test_config_parse_hwaddr_one("aabbcc.ddeeff", 0, NULL);
+ test_config_parse_hwaddr_one("aabbccddeeff", 0, NULL);
+ test_config_parse_hwaddr_one("aabbccddee:ff", 0, NULL);
+ test_config_parse_hwaddr_one("012345.6789ab", 0, NULL);
+ test_config_parse_hwaddr_one("123.4567.89ab", 0, &t[1]);
+}
+
+int main(int argc, char **argv) {
+ log_parse_environment();
+ log_open();
+
+ test_config_parse_duid_type();
+ test_config_parse_duid_rawdata();
+ test_config_parse_hwaddr();
+
+ return 0;
+}
diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c
index 2536ad2898..2b83d127b7 100644
--- a/src/nss-myhostname/nss-myhostname.c
+++ b/src/nss-myhostname/nss-myhostname.c
@@ -127,7 +127,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
memcpy(r_name, canonical, l+1);
idx = ALIGN(l+1);
- if (n_addresses <= 0) {
+ assert(n_addresses >= 0);
+ if (n_addresses == 0) {
/* Second, fill in IPv6 tuple */
r_tuple = (struct gaih_addrtuple*) (buffer + idx);
r_tuple->next = r_tuple_prev;
@@ -453,38 +454,33 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r(
}
n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
- if (n_addresses > 0) {
- for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
- if (af != a->family)
- continue;
+ for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
+ if (af != a->family)
+ continue;
- if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
- goto found;
- }
+ if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0)
+ goto found;
}
addresses = mfree(addresses);
n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
- if (n_addresses > 0) {
- for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
- if (af != a->family)
- continue;
+ for (a = addresses, n = 0; (int) n < n_addresses; n++, a++) {
+ if (af != a->family)
+ continue;
- if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
- canonical = "gateway";
- goto found;
- }
+ if (memcmp(addr, &a->address, FAMILY_ADDRESS_SIZE(af)) == 0) {
+ canonical = "gateway";
+ goto found;
}
}
*errnop = ENOENT;
*h_errnop = HOST_NOT_FOUND;
-
return NSS_STATUS_NOTFOUND;
found:
- if (!canonical || (!additional && additional_from_hostname)) {
+ if (!canonical || additional_from_hostname) {
hn = gethostname_malloc();
if (!hn) {
*errnop = ENOMEM;
@@ -494,8 +490,7 @@ found:
if (!canonical)
canonical = hn;
-
- if (!additional && additional_from_hostname)
+ else
additional = hn;
}
diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c
index 4be8d0507f..ce226c4d66 100644
--- a/src/socket-proxy/socket-proxyd.c
+++ b/src/socket-proxy/socket-proxyd.c
@@ -400,34 +400,25 @@ static int resolve_remote(Connection *c) {
union sockaddr_union sa = {};
const char *node, *service;
- socklen_t salen;
int r;
if (path_is_absolute(arg_remote_host)) {
sa.un.sun_family = AF_UNIX;
- strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path)-1);
- sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
-
- salen = offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path);
-
- return connection_start(c, &sa.sa, salen);
+ strncpy(sa.un.sun_path, arg_remote_host, sizeof(sa.un.sun_path));
+ return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}
if (arg_remote_host[0] == '@') {
sa.un.sun_family = AF_UNIX;
sa.un.sun_path[0] = 0;
- strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-2);
- sa.un.sun_path[sizeof(sa.un.sun_path)-1] = 0;
-
- salen = offsetof(union sockaddr_union, un.sun_path) + 1 + strlen(sa.un.sun_path + 1);
-
- return connection_start(c, &sa.sa, salen);
+ strncpy(sa.un.sun_path+1, arg_remote_host+1, sizeof(sa.un.sun_path)-1);
+ return connection_start(c, &sa.sa, SOCKADDR_UN_LEN(sa.un));
}
service = strrchr(arg_remote_host, ':');
if (service) {
node = strndupa(arg_remote_host, service - arg_remote_host);
- service ++;
+ service++;
} else {
node = arg_remote_host;
service = "80";
diff --git a/src/systemd-activate/Makefile b/src/systemd-activate/Makefile
index 058e10809e..5e2299f00e 100644
--- a/src/systemd-activate/Makefile
+++ b/src/systemd-activate/Makefile
@@ -24,13 +24,13 @@ include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
-libexec_PROGRAMS += \
- systemd-activate
+bin_PROGRAMS += \
+ systemd-socket-activate
-systemd_activate_SOURCES = \
+systemd_socket_activate_SOURCES = \
src/activate/activate.c
-systemd_activate_LDADD = \
+systemd_socket_activate_LDADD = \
libshared.la
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/systemd-activate/activate.c b/src/systemd-activate/activate.c
index 94f99028e5..89cc1ee813 100644
--- a/src/systemd-activate/activate.c
+++ b/src/systemd-activate/activate.c
@@ -27,6 +27,7 @@
#include <systemd/sd-daemon.h>
#include "alloc-util.h"
+#include "escape.h"
#include "fd-util.h"
#include "log.h"
#include "macro.h"
@@ -40,7 +41,7 @@ static bool arg_accept = false;
static int arg_socket_type = SOCK_STREAM;
static char** arg_args = NULL;
static char** arg_setenv = NULL;
-static const char *arg_fdname = NULL;
+static char **arg_fdnames = NULL;
static bool arg_inetd = false;
static int add_epoll(int epoll_fd, int fd) {
@@ -76,7 +77,7 @@ static int open_sockets(int *epoll_fd, bool accept) {
if (r < 0)
return r;
- count ++;
+ count++;
}
}
@@ -104,7 +105,7 @@ static int open_sockets(int *epoll_fd, bool accept) {
}
assert(fd == SD_LISTEN_FDS_START + count);
- count ++;
+ count++;
}
if (arg_listen)
@@ -134,7 +135,6 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
_cleanup_free_ char *joined = NULL;
unsigned n_env = 0, length;
const char *tocopy;
- unsigned i;
char **s;
int r;
@@ -176,7 +176,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
if (!envp[n_env])
return log_oom();
- n_env ++;
+ n_env++;
}
}
@@ -191,7 +191,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
if (!envp[n_env])
return log_oom();
- n_env ++;
+ n_env++;
}
if (arg_inetd) {
@@ -224,25 +224,30 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0)
return log_oom();
- if (arg_fdname) {
+ if (arg_fdnames) {
+ _cleanup_free_ char *names = NULL;
+ size_t len;
char *e;
+ int i;
+
+ len = strv_length(arg_fdnames);
+ if (len == 1)
+ for (i = 1; i < n_fds; i++) {
+ r = strv_extend(&arg_fdnames, arg_fdnames[0]);
+ if (r < 0)
+ return log_error_errno(r, "Failed to extend strv: %m");
+ }
+ else if (len != (unsigned) n_fds)
+ log_warning("The number of fd names is different than number of fds: %zu vs %d",
+ len, n_fds);
- e = strappend("LISTEN_FDNAMES=", arg_fdname);
- if (!e)
+ names = strv_join(arg_fdnames, ":");
+ if (!names)
return log_oom();
- for (i = 1; i < (unsigned) n_fds; i++) {
- char *c;
-
- c = strjoin(e, ":", arg_fdname, NULL);
- if (!c) {
- free(e);
- return log_oom();
- }
-
- free(e);
- e = c;
- }
+ e = strappend("LISTEN_FDNAMES=", names);
+ if (!e)
+ return log_oom();
envp[n_env++] = e;
}
@@ -311,19 +316,31 @@ static int do_accept(const char* name, char **argv, char **envp, int fd) {
}
/* SIGCHLD handler. */
-static void sigchld_hdl(int sig, siginfo_t *t, void *data) {
+static void sigchld_hdl(int sig) {
PROTECT_ERRNO;
- log_info("Child %d died with code %d", t->si_pid, t->si_status);
+ for (;;) {
+ siginfo_t si;
+ int r;
+
+ si.si_pid = 0;
+ r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG);
+ if (r < 0) {
+ if (errno != ECHILD)
+ log_error_errno(errno, "Failed to reap children: %m");
+ return;
+ }
+ if (si.si_pid == 0)
+ return;
- /* Wait for a dead child. */
- (void) waitpid(t->si_pid, NULL, 0);
+ log_info("Child %d died with code %d", si.si_pid, si.si_status);
+ }
}
static int install_chld_handler(void) {
static const struct sigaction act = {
- .sa_flags = SA_SIGINFO,
- .sa_sigaction = sigchld_hdl,
+ .sa_flags = SA_NOCLDSTOP,
+ .sa_handler = sigchld_hdl,
};
int r;
@@ -339,14 +356,15 @@ static void help(void) {
printf("%s [OPTIONS...]\n\n"
"Listen on sockets and launch child on connection.\n\n"
"Options:\n"
- " -h --help Show this help and exit\n"
- " --version Print version string and exit\n"
- " -l --listen=ADDR Listen for raw connections at ADDR\n"
- " -d --datagram Listen on datagram instead of stream socket\n"
- " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n"
- " -a --accept Spawn separate child for each connection\n"
- " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
- " --inetd Enable inetd file descriptor passing protocol\n"
+ " -h --help Show this help and exit\n"
+ " --version Print version string and exit\n"
+ " -l --listen=ADDR Listen for raw connections at ADDR\n"
+ " -d --datagram Listen on datagram instead of stream socket\n"
+ " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n"
+ " -a --accept Spawn separate child for each connection\n"
+ " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n"
+ " --fdname=NAME[:NAME...] Specify names for file descriptors\n"
+ " --inetd Enable inetd file descriptor passing protocol\n"
"\n"
"Note: file descriptors from sd_listen_fds() will be passed through.\n"
, program_invocation_short_name);
@@ -379,7 +397,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hl:aEd", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0)
switch(c) {
case 'h':
help();
@@ -424,14 +442,30 @@ static int parse_argv(int argc, char *argv[]) {
break;
- case ARG_FDNAME:
- if (!fdname_is_valid(optarg)) {
- log_error("File descriptor name %s is not valid, refusing.", optarg);
- return -EINVAL;
- }
+ case ARG_FDNAME: {
+ _cleanup_strv_free_ char **names;
+ char **s;
+
+ names = strv_split(optarg, ":");
+ if (!names)
+ return log_oom();
- arg_fdname = optarg;
+ STRV_FOREACH(s, names)
+ if (!fdname_is_valid(*s)) {
+ _cleanup_free_ char *esc;
+
+ esc = cescape(*s);
+ log_warning("File descriptor name \"%s\" is not valid.", esc);
+ }
+
+ /* Empty optargs means one empty name */
+ r = strv_extend_strv(&arg_fdnames,
+ strv_isempty(names) ? STRV_MAKE("") : names,
+ false);
+ if (r < 0)
+ return log_error_errno(r, "strv_extend_strv: %m");
break;
+ }
case ARG_INETD:
arg_inetd = true;
diff --git a/src/systemd-activate/systemd-activate.xml b/src/systemd-activate/systemd-activate.xml
deleted file mode 100644
index 995e6eecce..0000000000
--- a/src/systemd-activate/systemd-activate.xml
+++ /dev/null
@@ -1,204 +0,0 @@
-<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
- This file is part of systemd.
-
- Copyright 2013 Zbigniew Jędrzejewski-Szmek
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
--->
-
-<refentry id="systemd-activate"
- xmlns:xi="http://www.w3.org/2001/XInclude">
-
- <refentryinfo>
- <title>systemd-activate</title>
- <productname>systemd</productname>
-
- <authorgroup>
- <author>
- <contrib>Developer</contrib>
- <firstname>Zbigniew</firstname>
- <surname>Jędrzejewski-Szmek</surname>
- <email>zbyszek@in.waw.pl</email>
- </author>
- </authorgroup>
- </refentryinfo>
-
- <refmeta>
- <refentrytitle>systemd-activate</refentrytitle>
- <manvolnum>8</manvolnum>
- </refmeta>
-
- <refnamediv>
- <refname>systemd-activate</refname>
- <refpurpose>Test socket activation of daemons</refpurpose>
- </refnamediv>
-
- <refsynopsisdiv>
- <cmdsynopsis>
- <command>/usr/lib/systemd/systemd-activate</command>
- <arg choice="opt" rep="repeat">OPTIONS</arg>
- <arg choice="plain"><replaceable>daemon</replaceable></arg>
- <arg choice="opt" rep="repeat">OPTIONS</arg>
- </cmdsynopsis>
- </refsynopsisdiv>
-
- <refsect1>
- <title>Description</title>
-
- <para><command>systemd-activate</command> may be used to launch a socket-activated service binary from the command
- line for testing purposes. It may also be used to launch individual instances of the service binary per connection.
- </para>
-
- <para>The daemon to launch and its options should be specified
- after options intended for <command>systemd-activate</command>.
- </para>
-
- <para>If the <option>--inetd</option> option is given, the socket file descriptor will be used as the standard
- input and output of the launched process. Otherwise, standard input and output will be inherited, and sockets will
- be passed through file descriptors 3 and higher. Sockets passed through <varname>$LISTEN_FDS</varname> to
- <command>systemd-activate</command> will be passed through to the daemon, in the original positions. Other sockets
- specified with <option>--listen=</option> will use consecutive descriptors. By default,
- <command>systemd-activate</command> listens on a stream socket, use <option>--datagram</option> and
- <option>--seqpacket</option> to listen on datagram or sequential packet sockets instead (see below).
- </para>
- </refsect1>
-
- <refsect1>
- <title>Options</title>
- <variablelist>
- <varlistentry>
- <term><option>-l <replaceable>address</replaceable></option></term>
- <term><option>--listen=<replaceable>address</replaceable></option></term>
-
- <listitem><para>Listen on this <replaceable>address</replaceable>.
- Takes a string like <literal>2000</literal> or
- <literal>127.0.0.1:2001</literal>.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>-a</option></term>
- <term><option>--accept</option></term>
-
- <listitem><para>Launch an instance of the service binary for each connection and pass the connection
- socket.</para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>-d</option></term>
- <term><option>--datagram</option></term>
-
- <listitem><para>Listen on a datagram socket (<constant>SOCK_DGRAM</constant>), instead of a stream socket
- (<constant>SOCK_STREAM</constant>). May not be combined with <option>--seqpacket</option>.</para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>--seqpacket</option></term>
-
- <listitem><para>Listen on a sequential packet socket (<constant>SOCK_SEQPACKET</constant>), instead of a stream
- socket (<constant>SOCK_STREAM</constant>). May not be combined with
- <option>--datagram</option>.</para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>--inetd</option></term>
-
- <listitem><para>Use the inetd protocol for passing file descriptors, i.e. as standard input and standard
- output, instead of the new-style protocol for passing file descriptors using <varname>$LISTEN_FDS</varname>
- (see above).</para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>-E <replaceable>VAR</replaceable><optional>=<replaceable>VALUE</replaceable></optional></option></term>
- <term><option>--setenv=<replaceable>VAR</replaceable><optional>=<replaceable>VALUE</replaceable></optional></option></term>
-
- <listitem><para>Add this variable to the environment of the
- launched process. If <replaceable>VAR</replaceable> is
- followed by <literal>=</literal>, assume that it is a
- variable–value pair. Otherwise, obtain the value from the
- environment of <command>systemd-activate</command> itself.
- </para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><option>--fdname=</option><replaceable>NAME</replaceable></term>
-
- <listitem><para>Specify a name for the activation file
- descriptors. This is equivalent to setting
- <varname>FileDescriptorName=</varname> in socket unit files, and
- enables use of
- <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
- </varlistentry>
-
- <xi:include href="standard-options.xml" xpointer="help" />
- <xi:include href="standard-options.xml" xpointer="version" />
- </variablelist>
- </refsect1>
-
- <refsect1>
- <title>Environment variables</title>
- <variablelist class='environment-variables'>
- <varlistentry>
- <term><varname>$LISTEN_FDS</varname></term>
- <term><varname>$LISTEN_PID</varname></term>
- <term><varname>$LISTEN_FDNAMES</varname></term>
-
- <listitem><para>See
- <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
- </varlistentry>
-
- <varlistentry>
- <term><varname>$SYSTEMD_LOG_TARGET</varname></term>
- <term><varname>$SYSTEMD_LOG_LEVEL</varname></term>
- <term><varname>$SYSTEMD_LOG_COLOR</varname></term>
- <term><varname>$SYSTEMD_LOG_LOCATION</varname></term>
-
- <listitem><para>Same as in
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem>
- </varlistentry>
- </variablelist>
- </refsect1>
-
- <refsect1>
- <title>Examples</title>
-
- <example>
- <title>Run an echo server on port 2000</title>
-
- <programlisting>$ /usr/lib/systemd/systemd-activate -l 2000 --inetd -a cat</programlisting>
- </example>
-
- <example>
- <title>Run a socket-activated instance of <citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry></title>
-
- <programlisting>$ /usr/lib/systemd/systemd-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd</programlisting>
- </example>
- </refsect1>
-
- <refsect1>
- <title>See Also</title>
- <para>
- <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry project='man-pages'><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry>
- </para>
- </refsect1>
-</refentry>
diff --git a/src/systemd-analyze/analyze-verify.c b/src/systemd-analyze/analyze-verify.c
index d36c8db3d4..5fd3ee49eb 100644
--- a/src/systemd-analyze/analyze-verify.c
+++ b/src/systemd-analyze/analyze-verify.c
@@ -231,14 +231,12 @@ static int verify_unit(Unit *u, bool check_man) {
return r;
}
-int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) {
+int verify_units(char **filenames, UnitFileScope scope, bool check_man) {
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *var = NULL;
Manager *m = NULL;
FILE *serial = NULL;
FDSet *fdset = NULL;
-
- _cleanup_free_ char *var = NULL;
-
char **filename;
int r = 0, k;
@@ -255,7 +253,7 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man)
assert_se(set_unit_path(var) >= 0);
- r = manager_new(running_as, true, &m);
+ r = manager_new(scope, true, &m);
if (r < 0)
return log_error_errno(r, "Failed to initialize manager: %m");
@@ -290,7 +288,7 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man)
if (r == 0)
r = k;
} else
- count ++;
+ count++;
}
for (i = 0; i < count; i++) {
diff --git a/src/systemd-analyze/analyze-verify.h b/src/systemd-analyze/analyze-verify.h
index 54adad93e1..d8204dc69c 100644
--- a/src/systemd-analyze/analyze-verify.h
+++ b/src/systemd-analyze/analyze-verify.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,10 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <stdbool.h>
#include "path-lookup.h"
-int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man);
+int verify_units(char **filenames, UnitFileScope scope, bool check_man);
diff --git a/src/systemd-analyze/analyze.c b/src/systemd-analyze/analyze.c
index 13bcc8ebdd..0e1eee16ec 100644
--- a/src/systemd-analyze/analyze.c
+++ b/src/systemd-analyze/analyze.c
@@ -28,6 +28,7 @@
#include "alloc-util.h"
#include "analyze-verify.h"
#include "bus-error.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "glob-util.h"
#include "hashmap.h"
@@ -60,7 +61,7 @@
svg(" <text class=\"%s\" x=\"%.03f\" y=\"%.03f\">", (b) ? "left" : "right", SCALE_X * (x) + (b ? 5.0 : -5.0), SCALE_Y * (y) + 14.0); \
svg(format, ## __VA_ARGS__); \
svg("</text>\n"); \
- } while(false)
+ } while (false)
static enum dot {
DEP_ALL,
@@ -123,14 +124,6 @@ struct host_info {
char *architecture;
};
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
int r;
@@ -759,9 +752,9 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne
char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX];
for (i = level; i != 0; i--)
- printf("%s", draw_special_char(branches & (1 << (i-1)) ? DRAW_TREE_VERTICAL : DRAW_TREE_SPACE));
+ printf("%s", special_glyph(branches & (1 << (i-1)) ? TREE_VERTICAL : TREE_SPACE));
- printf("%s", draw_special_char(last ? DRAW_TREE_RIGHT : DRAW_TREE_BRANCH));
+ printf("%s", special_glyph(last ? TREE_RIGHT : TREE_BRANCH));
if (times) {
if (times->time)
@@ -965,7 +958,7 @@ static int analyze_critical_chain(sd_bus *bus, char *names[]) {
}
unit_times_hashmap = h;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
puts("The time after the unit is active or started is printed after the \"@\" character.\n"
"The time the unit takes to start is printed after the \"+\" character.\n");
@@ -993,7 +986,7 @@ static int analyze_blame(sd_bus *bus) {
qsort(times, n, sizeof(struct unit_times), compare_unit_time);
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
for (i = 0; i < (unsigned) n; i++) {
char ts[FORMAT_TIMESPAN_MAX];
@@ -1206,7 +1199,7 @@ static int dump(sd_bus *bus, char **args) {
return -E2BIG;
}
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
r = sd_bus_call_method(
bus,
@@ -1284,7 +1277,7 @@ static int set_log_target(sd_bus *bus, char **args) {
static void help(void) {
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Profile systemd, show unit dependencies, check unit files.\n\n"
@@ -1451,7 +1444,7 @@ int main(int argc, char *argv[]) {
if (streq_ptr(argv[optind], "verify"))
r = verify_units(argv+optind+1,
- arg_user ? MANAGER_USER : MANAGER_SYSTEM,
+ arg_user ? UNIT_FILE_USER : UNIT_FILE_SYSTEM,
arg_man);
else {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
diff --git a/src/systemd-ask-password/ask-password.c b/src/systemd-ask-password/ask-password.c
index adc9286612..6d53dd982c 100644
--- a/src/systemd-ask-password/ask-password.c
+++ b/src/systemd-ask-password/ask-password.c
@@ -34,6 +34,7 @@ static const char *arg_keyname = NULL;
static char *arg_message = NULL;
static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC;
static bool arg_multiple = false;
+static bool arg_no_output = false;
static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE;
static void help(void) {
@@ -48,6 +49,7 @@ static void help(void) {
" --no-tty Ask question via agent even on TTY\n"
" --accept-cached Accept cached passwords\n"
" --multiple List multiple passwords if available\n"
+ " --no-output Do not print password to standard output\n"
, program_invocation_short_name);
}
@@ -62,6 +64,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_MULTIPLE,
ARG_ID,
ARG_KEYNAME,
+ ARG_NO_OUTPUT,
};
static const struct option options[] = {
@@ -74,6 +77,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "multiple", no_argument, NULL, ARG_MULTIPLE },
{ "id", required_argument, NULL, ARG_ID },
{ "keyname", required_argument, NULL, ARG_KEYNAME },
+ { "no-output", no_argument, NULL, ARG_NO_OUTPUT },
{}
};
@@ -125,6 +129,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_keyname = optarg;
break;
+ case ARG_NO_OUTPUT:
+ arg_no_output = true;
+ break;
+
case '?':
return -EINVAL;
@@ -166,7 +174,8 @@ int main(int argc, char *argv[]) {
}
STRV_FOREACH(p, l) {
- puts(*p);
+ if (!arg_no_output)
+ puts(*p);
if (!arg_multiple)
break;
diff --git a/src/systemd-bootchart/bootchart.c b/src/systemd-bootchart/bootchart.c
deleted file mode 100644
index 8755b2d884..0000000000
--- a/src/systemd-bootchart/bootchart.c
+++ /dev/null
@@ -1,531 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2009-2013 Intel Corporation
-
- Authors:
- Auke Kok <auke-jan.h.kok@intel.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
- ***/
-
-/***
-
- Many thanks to those who contributed ideas and code:
- - Ziga Mahkovec - Original bootchart author
- - Anders Norgaard - PyBootchartgui
- - Michael Meeks - bootchart2
- - Scott James Remnant - Ubuntu C-based logger
- - Arjan van der Ven - for the idea to merge bootgraph.pl functionality
-
- ***/
-
-#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 <sys/resource.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <systemd/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 "parse-util.h"
-#include "path-util.h"
-#include "store.h"
-#include "string-util.h"
-#include "strxcpyx.h"
-#include "svg.h"
-#include "util.h"
-
-static int exiting = 0;
-
-#define DEFAULT_SAMPLES_LEN 500
-#define DEFAULT_HZ 25.0
-#define DEFAULT_SCALE_X 100.0 /* 100px = 1sec */
-#define DEFAULT_SCALE_Y 20.0 /* 16px = 1 process bar */
-#define DEFAULT_INIT ROOTLIBEXECDIR "/systemd"
-#define DEFAULT_OUTPUT "/run/log"
-
-/* graph defaults */
-bool arg_entropy = false;
-bool arg_initcall = true;
-bool arg_relative = false;
-bool arg_filter = true;
-bool arg_show_cmdline = false;
-bool arg_show_cgroup = false;
-bool arg_pss = false;
-bool arg_percpu = false;
-int arg_samples_len = DEFAULT_SAMPLES_LEN; /* we record len+1 (1 start sample) */
-double arg_hz = DEFAULT_HZ;
-double arg_scale_x = DEFAULT_SCALE_X;
-double arg_scale_y = DEFAULT_SCALE_Y;
-
-char arg_init_path[PATH_MAX] = DEFAULT_INIT;
-char arg_output_path[PATH_MAX] = DEFAULT_OUTPUT;
-
-static void signal_handler(int sig) {
- exiting = 1;
-}
-
-#define BOOTCHART_MAX (16*1024*1024)
-
-static void parse_conf(void) {
- char *init = NULL, *output = NULL;
- const ConfigTableItem items[] = {
- { "Bootchart", "Samples", config_parse_int, 0, &arg_samples_len },
- { "Bootchart", "Frequency", config_parse_double, 0, &arg_hz },
- { "Bootchart", "Relative", config_parse_bool, 0, &arg_relative },
- { "Bootchart", "Filter", config_parse_bool, 0, &arg_filter },
- { "Bootchart", "Output", config_parse_path, 0, &output },
- { "Bootchart", "Init", config_parse_path, 0, &init },
- { "Bootchart", "PlotMemoryUsage", config_parse_bool, 0, &arg_pss },
- { "Bootchart", "PlotEntropyGraph", config_parse_bool, 0, &arg_entropy },
- { "Bootchart", "ScaleX", config_parse_double, 0, &arg_scale_x },
- { "Bootchart", "ScaleY", config_parse_double, 0, &arg_scale_y },
- { "Bootchart", "ControlGroup", config_parse_bool, 0, &arg_show_cgroup },
- { "Bootchart", "PerCPU", config_parse_bool, 0, &arg_percpu },
- { NULL, NULL, NULL, 0, NULL }
- };
-
- config_parse_many(PKGSYSCONFDIR "/bootchart.conf",
- CONF_PATHS_NULSTR("systemd/bootchart.conf.d"),
- NULL, config_item_table_lookup, items, true, NULL);
-
- if (init != NULL)
- strscpy(arg_init_path, sizeof(arg_init_path), init);
- if (output != NULL)
- strscpy(arg_output_path, sizeof(arg_output_path), output);
-}
-
-static void help(void) {
- printf("Usage: %s [OPTIONS]\n\n"
- "Options:\n"
- " -r --rel Record time relative to recording\n"
- " -f --freq=FREQ Sample frequency [%g]\n"
- " -n --samples=N Stop sampling at [%d] samples\n"
- " -x --scale-x=N Scale the graph horizontally [%g] \n"
- " -y --scale-y=N Scale the graph vertically [%g] \n"
- " -p --pss Enable PSS graph (CPU intensive)\n"
- " -e --entropy Enable the entropy_avail graph\n"
- " -o --output=PATH Path to output files [%s]\n"
- " -i --init=PATH Path to init executable [%s]\n"
- " -F --no-filter Disable filtering of unimportant or ephemeral processes\n"
- " -C --cmdline Display full command lines with arguments\n"
- " -c --control-group Display process control group\n"
- " --per-cpu Draw each CPU utilization and wait bar also\n"
- " -h --help Display this message\n\n"
- "See bootchart.conf for more information.\n",
- program_invocation_short_name,
- DEFAULT_HZ,
- DEFAULT_SAMPLES_LEN,
- DEFAULT_SCALE_X,
- DEFAULT_SCALE_Y,
- DEFAULT_OUTPUT,
- DEFAULT_INIT);
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
- enum {
- ARG_PERCPU = 0x100,
- };
-
- static const struct option options[] = {
- {"rel", no_argument, NULL, 'r' },
- {"freq", required_argument, NULL, 'f' },
- {"samples", required_argument, NULL, 'n' },
- {"pss", no_argument, NULL, 'p' },
- {"output", required_argument, NULL, 'o' },
- {"init", required_argument, NULL, 'i' },
- {"no-filter", no_argument, NULL, 'F' },
- {"cmdline", no_argument, NULL, 'C' },
- {"control-group", no_argument, NULL, 'c' },
- {"help", no_argument, NULL, 'h' },
- {"scale-x", required_argument, NULL, 'x' },
- {"scale-y", required_argument, NULL, 'y' },
- {"entropy", no_argument, NULL, 'e' },
- {"per-cpu", no_argument, NULL, ARG_PERCPU},
- {}
- };
- int c, r;
-
- if (getpid() == 1)
- opterr = 0;
-
- while ((c = getopt_long(argc, argv, "erpf:n:o:i:FCchx:y:", options, NULL)) >= 0)
- switch (c) {
-
- case 'r':
- arg_relative = true;
- break;
- case 'f':
- r = safe_atod(optarg, &arg_hz);
- if (r < 0)
- log_warning_errno(r, "failed to parse --freq/-f argument '%s': %m",
- optarg);
- break;
- case 'F':
- arg_filter = false;
- break;
- case 'C':
- arg_show_cmdline = true;
- break;
- case 'c':
- arg_show_cgroup = true;
- break;
- case 'n':
- r = safe_atoi(optarg, &arg_samples_len);
- if (r < 0)
- log_warning_errno(r, "failed to parse --samples/-n argument '%s': %m",
- optarg);
- break;
- case 'o':
- path_kill_slashes(optarg);
- strscpy(arg_output_path, sizeof(arg_output_path), optarg);
- break;
- case 'i':
- path_kill_slashes(optarg);
- strscpy(arg_init_path, sizeof(arg_init_path), optarg);
- break;
- case 'p':
- arg_pss = true;
- break;
- case 'x':
- r = safe_atod(optarg, &arg_scale_x);
- if (r < 0)
- log_warning_errno(r, "failed to parse --scale-x/-x argument '%s': %m",
- optarg);
- break;
- case 'y':
- r = safe_atod(optarg, &arg_scale_y);
- if (r < 0)
- log_warning_errno(r, "failed to parse --scale-y/-y argument '%s': %m",
- optarg);
- break;
- case 'e':
- arg_entropy = true;
- break;
- case ARG_PERCPU:
- arg_percpu = true;
- break;
- case 'h':
- help();
- return 0;
- case '?':
- if (getpid() != 1)
- return -EINVAL;
- else
- return 0;
- default:
- assert_not_reached("Unhandled option code.");
- }
-
- if (arg_hz <= 0) {
- log_error("Frequency needs to be > 0");
- return -EINVAL;
- }
-
- return 1;
-}
-
-static int do_journal_append(char *file) {
- _cleanup_free_ char *bootchart_message = NULL;
- _cleanup_free_ char *bootchart_file = NULL;
- _cleanup_free_ char *p = NULL;
- _cleanup_close_ int fd = -1;
- struct iovec iovec[5];
- int r, j = 0;
- ssize_t n;
-
- bootchart_file = strappend("BOOTCHART_FILE=", file);
- if (!bootchart_file)
- return log_oom();
-
- IOVEC_SET_STRING(iovec[j++], bootchart_file);
- IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518");
- IOVEC_SET_STRING(iovec[j++], "PRIORITY=7");
- bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL);
- if (!bootchart_message)
- return log_oom();
-
- IOVEC_SET_STRING(iovec[j++], bootchart_message);
-
- p = malloc(10 + BOOTCHART_MAX);
- if (!p)
- return log_oom();
-
- memcpy(p, "BOOTCHART=", 10);
-
- fd = open(file, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file);
-
- n = loop_read(fd, p + 10, BOOTCHART_MAX, false);
- if (n < 0)
- return log_error_errno(n, "Failed to read bootchart data: %m");
-
- iovec[j].iov_base = p;
- iovec[j].iov_len = 10 + n;
- j++;
-
- r = sd_journal_sendv(iovec, j);
- if (r < 0)
- log_error_errno(r, "Failed to send bootchart: %m");
-
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- static struct list_sample_data *sampledata;
- _cleanup_closedir_ DIR *proc = NULL;
- _cleanup_free_ char *build = NULL;
- _cleanup_fclose_ FILE *of = NULL;
- _cleanup_close_ int sysfd = -1;
- struct ps_struct *ps_first;
- double graph_start;
- double log_start;
- double interval;
- char output_file[PATH_MAX];
- char datestr[200];
- int pscount = 0;
- int n_cpus = 0;
- int overrun = 0;
- time_t t = 0;
- int r, samples;
- struct ps_struct *ps;
- struct rlimit rlim;
- struct list_sample_data *head;
- struct sigaction sig = {
- .sa_handler = signal_handler,
- };
-
- parse_conf();
-
- r = parse_argv(argc, argv);
- if (r < 0)
- return EXIT_FAILURE;
-
- if (r == 0)
- return EXIT_SUCCESS;
-
- /*
- * If the kernel executed us through init=/usr/lib/systemd/systemd-bootchart, then
- * fork:
- * - parent execs executable specified via init_path[] (/usr/lib/systemd/systemd by default) as pid=1
- * - child logs data
- */
- if (getpid() == 1) {
- if (fork())
- /* parent */
- execl(arg_init_path, arg_init_path, NULL);
- }
- argv[0][0] = '@';
-
- rlim.rlim_cur = 4096;
- rlim.rlim_max = 4096;
- (void) setrlimit(RLIMIT_NOFILE, &rlim);
-
- /* start with empty ps LL */
- ps_first = new0(struct ps_struct, 1);
- if (!ps_first) {
- log_oom();
- return EXIT_FAILURE;
- }
-
- /* handle TERM/INT nicely */
- sigaction(SIGHUP, &sig, NULL);
-
- interval = (1.0 / arg_hz) * 1000000000.0;
-
- if (arg_relative)
- graph_start = log_start = gettime_ns();
- else {
- struct timespec n;
- double uptime;
-
- clock_gettime(clock_boottime_or_monotonic(), &n);
- uptime = (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC));
-
- log_start = gettime_ns();
- graph_start = log_start - uptime;
- }
-
- if (graph_start < 0.0) {
- log_error("Failed to setup graph start time.\n\n"
- "The system uptime probably includes time that the system was suspended. "
- "Use --rel to bypass this issue.");
- return EXIT_FAILURE;
- }
-
- LIST_HEAD_INIT(head);
-
- /* main program loop */
- for (samples = 0; !exiting && samples < arg_samples_len; samples++) {
- int res;
- double sample_stop;
- double elapsed;
- double timeleft;
-
- sampledata = new0(struct list_sample_data, 1);
- if (sampledata == NULL) {
- log_oom();
- return EXIT_FAILURE;
- }
-
- sampledata->sampletime = gettime_ns();
- sampledata->counter = samples;
-
- if (sysfd < 0)
- sysfd = open("/sys", O_RDONLY|O_CLOEXEC);
-
- if (!build) {
- if (parse_env_file("/etc/os-release", NEWLINE, "PRETTY_NAME", &build, NULL) == -ENOENT)
- parse_env_file("/usr/lib/os-release", NEWLINE, "PRETTY_NAME", &build, NULL);
- }
-
- if (proc)
- rewinddir(proc);
- else
- proc = opendir("/proc");
-
- /* wait for /proc to become available, discarding samples */
- if (proc) {
- r = log_sample(proc, samples, ps_first, &sampledata, &pscount, &n_cpus);
- if (r < 0)
- return EXIT_FAILURE;
- }
-
- sample_stop = gettime_ns();
-
- elapsed = (sample_stop - sampledata->sampletime) * 1000000000.0;
- timeleft = interval - elapsed;
-
- /*
- * check if we have not consumed our entire timeslice. If we
- * do, don't sleep and take a new sample right away.
- * we'll lose all the missed samples and overrun our total
- * time
- */
- if (timeleft > 0) {
- struct timespec req;
-
- req.tv_sec = (time_t)(timeleft / 1000000000.0);
- req.tv_nsec = (long)(timeleft - (req.tv_sec * 1000000000.0));
-
- res = nanosleep(&req, NULL);
- if (res) {
- if (errno == EINTR)
- /* caught signal, probably HUP! */
- break;
- log_error_errno(errno, "nanosleep() failed: %m");
- return EXIT_FAILURE;
- }
- } else {
- overrun++;
- /* calculate how many samples we lost and scrap them */
- arg_samples_len -= (int)(-timeleft / interval);
- }
- LIST_PREPEND(link, head, sampledata);
- }
-
- /* do some cleanup, close fd's */
- ps = ps_first;
- while (ps->next_ps) {
- ps = ps->next_ps;
- ps->schedstat = safe_close(ps->schedstat);
- ps->sched = safe_close(ps->sched);
- ps->smaps = safe_fclose(ps->smaps);
- }
-
- if (!of) {
- t = time(NULL);
- r = strftime(datestr, sizeof(datestr), "%Y%m%d-%H%M", localtime(&t));
- assert_se(r > 0);
-
- snprintf(output_file, PATH_MAX, "%s/bootchart-%s.svg", arg_output_path, datestr);
- of = fopen(output_file, "we");
- }
-
- if (!of) {
- log_error("Error opening output file '%s': %m\n", output_file);
- return EXIT_FAILURE;
- }
-
- r = svg_do(of, strna(build), head, ps_first,
- samples, pscount, n_cpus, graph_start,
- log_start, interval, overrun);
-
- if (r < 0) {
- log_error_errno(r, "Error generating svg file: %m");
- return EXIT_FAILURE;
- }
-
- log_info("systemd-bootchart wrote %s\n", output_file);
-
- r = do_journal_append(output_file);
- if (r < 0)
- return EXIT_FAILURE;
-
- /* nitpic cleanups */
- ps = ps_first->next_ps;
- while (ps->next_ps) {
- struct ps_struct *old;
-
- old = ps;
- old->sample = ps->first;
- ps = ps->next_ps;
- while (old->sample->next) {
- struct ps_sched_struct *oldsample = old->sample;
-
- old->sample = old->sample->next;
- free(oldsample);
- }
- free(old->cgroup);
- free(old->sample);
- free(old);
- }
-
- free(ps->cgroup);
- free(ps->sample);
- free(ps);
-
- sampledata = head;
- while (sampledata->link_prev) {
- struct list_sample_data *old_sampledata = sampledata;
- sampledata = sampledata->link_prev;
- free(old_sampledata);
- }
- free(sampledata);
-
- /* don't complain when overrun once, happens most commonly on 1st sample */
- if (overrun > 1)
- log_warning("systemd-bootchart: sample time overrun %i times\n", overrun);
-
- return 0;
-}
diff --git a/src/systemd-bootchart/bootchart.conf b/src/systemd-bootchart/bootchart.conf
deleted file mode 100644
index 4f5e50936e..0000000000
--- a/src/systemd-bootchart/bootchart.conf
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# Entries in this file show the compile time defaults.
-# You can change settings by editing this file.
-# Defaults can be restored by simply deleting this file.
-#
-# See bootchart.conf(5) for details.
-
-[Bootchart]
-#Samples=500
-#Frequency=25
-#Relative=no
-#Filter=yes
-#Output=<folder name, defaults to /run/log>
-#Init=/path/to/init-binary
-#PlotMemoryUsage=no
-#PlotEntropyGraph=no
-#ScaleX=100
-#ScaleY=20
-#ControlGroup=no
-#PerCPU=no
diff --git a/src/systemd-bootchart/bootchart.h b/src/systemd-bootchart/bootchart.h
deleted file mode 100644
index 1b445b954b..0000000000
--- a/src/systemd-bootchart/bootchart.h
+++ /dev/null
@@ -1,119 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 2009-2013 Intel Corporation
-
- Authors:
- Auke Kok <auke-jan.h.kok@intel.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-#include "list.h"
-
-#define MAXCPUS 16
-#define MAXPIDS 65535
-
-struct block_stat_struct {
- /* /proc/vmstat pgpgin & pgpgout */
- int bi;
- int bo;
-};
-
-struct cpu_stat_sample_struct {
- /* /proc/schedstat fields 10 & 11 (after name) */
- double runtime;
- double waittime;
-};
-
-/* per process, per sample data we will log */
-struct ps_sched_struct {
- /* /proc/<n>/schedstat fields 1 & 2 */
- double runtime;
- double waittime;
- int pss;
- struct list_sample_data *sampledata;
- struct ps_sched_struct *next;
- struct ps_sched_struct *prev;
- struct ps_sched_struct *cross; /* cross pointer */
- struct ps_struct *ps_new;
-};
-
-struct list_sample_data {
- double runtime[MAXCPUS];
- double waittime[MAXCPUS];
- double sampletime;
- int entropy_avail;
- struct block_stat_struct blockstat;
- LIST_FIELDS(struct list_sample_data, link); /* DLL */
- int counter;
-};
-
-/* process info */
-struct ps_struct {
- struct ps_struct *next_ps; /* SLL pointer */
- struct ps_struct *parent; /* ppid ref */
- struct ps_struct *children; /* children */
- struct ps_struct *next; /* siblings */
-
- /* must match - otherwise it's a new process with same PID */
- char name[256];
- int pid;
- int ppid;
- char *cgroup;
-
- /* cache fd's */
- int sched;
- int schedstat;
- FILE *smaps;
-
- /* pointers to first/last seen timestamps */
- struct ps_sched_struct *first;
- struct ps_sched_struct *last;
-
- /* records actual start time, may be way before bootchart runs */
- double starttime;
-
- /* record human readable total cpu time */
- double total;
-
- /* largest PSS size found */
- int pss_max;
-
- /* for drawing connection lines later */
- double pos_x;
- double pos_y;
-
- struct ps_sched_struct *sample;
-};
-
-extern bool arg_relative;
-extern bool arg_filter;
-extern bool arg_show_cmdline;
-extern bool arg_show_cgroup;
-extern bool arg_pss;
-extern bool arg_entropy;
-extern bool arg_percpu;
-extern bool arg_initcall;
-extern int arg_samples_len;
-extern double arg_hz;
-extern double arg_scale_x;
-extern double arg_scale_y;
-
-extern char arg_output_path[PATH_MAX];
-extern char arg_init_path[PATH_MAX];
diff --git a/src/systemd-bootchart/store.c b/src/systemd-bootchart/store.c
deleted file mode 100644
index 42cb8043ce..0000000000
--- a/src/systemd-bootchart/store.c
+++ /dev/null
@@ -1,555 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2009-2013 Intel Corporation
-
- Authors:
- Auke Kok <auke-jan.h.kok@intel.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
- ***/
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.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
- * PSS buffering from the default 1k stdin buffer to reduce
- * read() overhead.
- */
-static char smaps_buf[4096];
-static int skip = 0;
-
-double gettime_ns(void) {
- struct timespec n;
-
- clock_gettime(CLOCK_MONOTONIC, &n);
-
- return (n.tv_sec + (n.tv_nsec / (double) NSEC_PER_SEC));
-}
-
-static char *bufgetline(char *buf) {
- char *c;
-
- if (!buf)
- return NULL;
-
- c = strchr(buf, '\n');
- if (c)
- c++;
-
- return c;
-}
-
-static int pid_cmdline_strscpy(int procfd, char *buffer, size_t buf_len, int pid) {
- char filename[PATH_MAX];
- _cleanup_close_ int fd = -1;
- ssize_t n;
-
- sprintf(filename, "%d/cmdline", pid);
- fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- n = read(fd, buffer, buf_len-1);
- if (n > 0) {
- int i;
- for (i = 0; i < n; i++)
- if (buffer[i] == '\0')
- buffer[i] = ' ';
- buffer[n] = '\0';
- }
-
- return 0;
-}
-
-int log_sample(DIR *proc,
- int sample,
- struct ps_struct *ps_first,
- struct list_sample_data **ptr,
- int *pscount,
- int *cpus) {
-
- static int vmstat = -1;
- _cleanup_free_ char *buf_schedstat = NULL;
- char buf[4096];
- char key[256];
- char val[256];
- char rt[256];
- char wt[256];
- char *m;
- int r;
- int c;
- int p;
- int mod;
- static int e_fd = -1;
- ssize_t s;
- ssize_t n;
- struct dirent *ent;
- int fd;
- struct list_sample_data *sampledata;
- struct ps_sched_struct *ps_prev = NULL;
- int procfd;
- int taskfd = -1;
-
- sampledata = *ptr;
-
- procfd = dirfd(proc);
- if (procfd < 0)
- return -errno;
-
- if (vmstat < 0) {
- /* block stuff */
- vmstat = openat(procfd, "vmstat", O_RDONLY|O_CLOEXEC);
- if (vmstat < 0)
- return log_error_errno(errno, "Failed to open /proc/vmstat: %m");
- }
-
- n = pread(vmstat, buf, sizeof(buf) - 1, 0);
- if (n <= 0) {
- vmstat = safe_close(vmstat);
- if (n < 0)
- return -errno;
- return -ENODATA;
- }
-
- buf[n] = '\0';
-
- m = buf;
- while (m) {
- if (sscanf(m, "%s %s", key, val) < 2)
- goto vmstat_next;
- if (streq(key, "pgpgin"))
- sampledata->blockstat.bi = atoi(val);
- if (streq(key, "pgpgout")) {
- sampledata->blockstat.bo = atoi(val);
- break;
- }
-vmstat_next:
- m = bufgetline(m);
- if (!m)
- break;
- }
-
- /* Parse "/proc/schedstat" for overall CPU utilization */
- r = read_full_file("/proc/schedstat", &buf_schedstat, NULL);
- if (r < 0)
- return log_error_errno(r, "Unable to read schedstat: %m");
-
- m = buf_schedstat;
- while (m) {
- if (sscanf(m, "%s %*s %*s %*s %*s %*s %*s %s %s", key, rt, wt) < 3)
- goto schedstat_next;
-
- if (strstr(key, "cpu")) {
- r = safe_atoi((const char*)(key+3), &c);
- if (r < 0 || c > MAXCPUS -1)
- /* Oops, we only have room for MAXCPUS data */
- break;
- sampledata->runtime[c] = atoll(rt);
- sampledata->waittime[c] = atoll(wt);
-
- if (c == *cpus)
- *cpus = c + 1;
- }
-schedstat_next:
- m = bufgetline(m);
- if (!m)
- break;
- }
-
- if (arg_entropy) {
- if (e_fd < 0) {
- e_fd = openat(procfd, "sys/kernel/random/entropy_avail", O_RDONLY|O_CLOEXEC);
- if (e_fd < 0)
- return log_error_errno(errno, "Failed to open /proc/sys/kernel/random/entropy_avail: %m");
- }
-
- n = pread(e_fd, buf, sizeof(buf) - 1, 0);
- if (n <= 0) {
- e_fd = safe_close(e_fd);
- } else {
- buf[n] = '\0';
- sampledata->entropy_avail = atoi(buf);
- }
- }
-
- while ((ent = readdir(proc)) != NULL) {
- char filename[PATH_MAX];
- int pid;
- struct ps_struct *ps;
-
- if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9'))
- continue;
-
- pid = atoi(ent->d_name);
-
- if (pid >= MAXPIDS)
- continue;
-
- ps = ps_first;
- while (ps->next_ps) {
- ps = ps->next_ps;
- if (ps->pid == pid)
- break;
- }
-
- /* end of our LL? then append a new record */
- if (ps->pid != pid) {
- _cleanup_fclose_ FILE *st = NULL;
- char t[32];
- struct ps_struct *parent;
-
- ps->next_ps = new0(struct ps_struct, 1);
- if (!ps->next_ps)
- return log_oom();
-
- ps = ps->next_ps;
- ps->pid = pid;
- ps->sched = -1;
- ps->schedstat = -1;
-
- ps->sample = new0(struct ps_sched_struct, 1);
- if (!ps->sample)
- return log_oom();
-
- ps->sample->sampledata = sampledata;
-
- (*pscount)++;
-
- /* mark our first sample */
- ps->first = ps->last = ps->sample;
- ps->sample->runtime = atoll(rt);
- ps->sample->waittime = atoll(wt);
-
- /* get name, start time */
- if (ps->sched < 0) {
- sprintf(filename, "%d/sched", pid);
- ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
- if (ps->sched < 0)
- continue;
- }
-
- s = pread(ps->sched, buf, sizeof(buf) - 1, 0);
- if (s <= 0) {
- ps->sched = safe_close(ps->sched);
- continue;
- }
- buf[s] = '\0';
-
- if (!sscanf(buf, "%s %*s %*s", key))
- continue;
-
- strscpy(ps->name, sizeof(ps->name), key);
-
- /* cmdline */
- if (arg_show_cmdline)
- pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid);
-
- /* discard line 2 */
- m = bufgetline(buf);
- if (!m)
- continue;
-
- m = bufgetline(m);
- if (!m)
- continue;
-
- if (!sscanf(m, "%*s %*s %s", t))
- continue;
-
- r = safe_atod(t, &ps->starttime);
- if (r < 0)
- continue;
-
- ps->starttime /= 1000.0;
-
- if (arg_show_cgroup)
- /* if this fails, that's OK */
- cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER,
- ps->pid, &ps->cgroup);
-
- /* ppid */
- sprintf(filename, "%d/stat", pid);
- fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- continue;
-
- st = fdopen(fd, "re");
- if (!st) {
- close(fd);
- continue;
- }
-
- if (!fscanf(st, "%*s %*s %*s %i", &p))
- continue;
-
- ps->ppid = p;
-
- /*
- * setup child pointers
- *
- * these are used to paint the tree coherently later
- * each parent has a LL of children, and a LL of siblings
- */
- if (pid == 1)
- continue; /* nothing to do for init atm */
-
- /* kthreadd has ppid=0, which breaks our tree ordering */
- if (ps->ppid == 0)
- ps->ppid = 1;
-
- parent = ps_first;
- while ((parent->next_ps && parent->pid != ps->ppid))
- parent = parent->next_ps;
-
- if (parent->pid != ps->ppid) {
- /* orphan */
- ps->ppid = 1;
- parent = ps_first->next_ps;
- }
-
- ps->parent = parent;
-
- if (!parent->children) {
- /* it's the first child */
- parent->children = ps;
- } else {
- /* walk all children and append */
- struct ps_struct *children;
- children = parent->children;
- while (children->next)
- children = children->next;
-
- children->next = ps;
- }
- }
-
- /* else -> found pid, append data in ps */
-
- /* below here is all continuous logging parts - we get here on every
- * iteration */
-
- /* rt, wt */
- if (ps->schedstat < 0) {
- sprintf(filename, "%d/schedstat", pid);
- ps->schedstat = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
- if (ps->schedstat < 0)
- continue;
- }
-
- s = pread(ps->schedstat, buf, sizeof(buf) - 1, 0);
- if (s <= 0) {
- /* clean up our file descriptors - assume that the process exited */
- close(ps->schedstat);
- ps->schedstat = -1;
- ps->sched = safe_close(ps->sched);
- continue;
- }
-
- buf[s] = '\0';
-
- if (!sscanf(buf, "%s %s %*s", rt, wt))
- continue;
-
- ps->sample->next = new0(struct ps_sched_struct, 1);
- if (!ps->sample->next)
- return log_oom();
-
- ps->sample->next->prev = ps->sample;
- ps->sample = ps->sample->next;
- ps->last = ps->sample;
- ps->sample->runtime = atoll(rt);
- ps->sample->waittime = atoll(wt);
- ps->sample->sampledata = sampledata;
- ps->sample->ps_new = ps;
- if (ps_prev)
- ps_prev->cross = ps->sample;
-
- ps_prev = ps->sample;
- ps->total = (ps->last->runtime - ps->first->runtime)
- / 1000000000.0;
-
- /* Take into account CPU runtime/waittime spent in non-main threads of the process
- * by parsing "/proc/[pid]/task/[tid]/schedstat" for all [tid] != [pid]
- * See https://github.com/systemd/systemd/issues/139
- */
-
- /* Browse directory "/proc/[pid]/task" to know the thread ids of process [pid] */
- snprintf(filename, sizeof(filename), PID_FMT "/task", pid);
- taskfd = openat(procfd, filename, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
- if (taskfd >= 0) {
- _cleanup_closedir_ DIR *taskdir = NULL;
-
- taskdir = fdopendir(taskfd);
- if (!taskdir) {
- safe_close(taskfd);
- return -errno;
- }
- FOREACH_DIRENT(ent, taskdir, break) {
- int tid = -1;
- _cleanup_close_ int tid_schedstat = -1;
- long long delta_rt;
- long long delta_wt;
-
- if ((ent->d_name[0] < '0') || (ent->d_name[0] > '9'))
- continue;
-
- /* Skip main thread as it was already accounted */
- r = safe_atoi(ent->d_name, &tid);
- if (r < 0 || tid == pid)
- continue;
-
- /* Parse "/proc/[pid]/task/[tid]/schedstat" */
- snprintf(filename, sizeof(filename), PID_FMT "/schedstat", tid);
- tid_schedstat = openat(taskfd, filename, O_RDONLY|O_CLOEXEC);
-
- if (tid_schedstat == -1)
- continue;
-
- s = pread(tid_schedstat, buf, sizeof(buf) - 1, 0);
- if (s <= 0)
- continue;
- buf[s] = '\0';
-
- if (!sscanf(buf, "%s %s %*s", rt, wt))
- continue;
-
- r = safe_atolli(rt, &delta_rt);
- if (r < 0)
- continue;
- r = safe_atolli(rt, &delta_wt);
- if (r < 0)
- continue;
- ps->sample->runtime += delta_rt;
- ps->sample->waittime += delta_wt;
- }
- }
-
- if (!arg_pss)
- goto catch_rename;
-
- /* Pss */
- if (!ps->smaps) {
- sprintf(filename, "%d/smaps", pid);
- fd = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- continue;
- ps->smaps = fdopen(fd, "re");
- if (!ps->smaps) {
- close(fd);
- continue;
- }
- setvbuf(ps->smaps, smaps_buf, _IOFBF, sizeof(smaps_buf));
- } else {
- rewind(ps->smaps);
- }
-
- /* test to see if we need to skip another field */
- if (skip == 0) {
- if (fgets(buf, sizeof(buf), ps->smaps) == NULL) {
- continue;
- }
- if (fread(buf, 1, 28 * 15, ps->smaps) != (28 * 15)) {
- continue;
- }
- if (buf[392] == 'V') {
- skip = 2;
- }
- else {
- skip = 1;
- }
- rewind(ps->smaps);
- }
-
- while (1) {
- int pss_kb;
-
- /* skip one line, this contains the object mapped. */
- if (fgets(buf, sizeof(buf), ps->smaps) == NULL) {
- break;
- }
- /* then there's a 28 char 14 line block */
- if (fread(buf, 1, 28 * 14, ps->smaps) != 28 * 14) {
- break;
- }
- pss_kb = atoi(&buf[61]);
- ps->sample->pss += pss_kb;
-
- /* skip one more line if this is a newer kernel */
- if (skip == 2) {
- if (fgets(buf, sizeof(buf), ps->smaps) == NULL)
- break;
- }
- }
-
- if (ps->sample->pss > ps->pss_max)
- ps->pss_max = ps->sample->pss;
-
-catch_rename:
- /* catch process rename, try to randomize time */
- mod = (arg_hz < 4.0) ? 4.0 : (arg_hz / 4.0);
- if (((sample - ps->pid) + pid) % (int)(mod) == 0) {
-
- /* re-fetch name */
- /* get name, start time */
- if (ps->sched < 0) {
- sprintf(filename, "%d/sched", pid);
- ps->sched = openat(procfd, filename, O_RDONLY|O_CLOEXEC);
- if (ps->sched < 0)
- continue;
- }
-
- s = pread(ps->sched, buf, sizeof(buf) - 1, 0);
- if (s <= 0) {
- /* clean up file descriptors */
- ps->sched = safe_close(ps->sched);
- ps->schedstat = safe_close(ps->schedstat);
- continue;
- }
-
- buf[s] = '\0';
-
- if (!sscanf(buf, "%s %*s %*s", key))
- continue;
-
- strscpy(ps->name, sizeof(ps->name), key);
-
- /* cmdline */
- if (arg_show_cmdline)
- pid_cmdline_strscpy(procfd, ps->name, sizeof(ps->name), pid);
- }
- }
-
- return 0;
-}
diff --git a/src/systemd-bootchart/svg.c b/src/systemd-bootchart/svg.c
deleted file mode 100644
index f2af535061..0000000000
--- a/src/systemd-bootchart/svg.c
+++ /dev/null
@@ -1,1375 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright (C) 2009-2013 Intel Corporation
-
- Authors:
- Auke Kok <auke-jan.h.kok@intel.com>
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
- ***/
-
-#include <fcntl.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/utsname.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "architecture.h"
-#include "bootchart.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "list.h"
-#include "macro.h"
-#include "stdio-util.h"
-#include "store.h"
-#include "svg.h"
-#include "utf8.h"
-#include "util.h"
-
-#define time_to_graph(t) ((t) * arg_scale_x)
-#define ps_to_graph(n) ((n) * arg_scale_y)
-#define kb_to_graph(m) ((m) * arg_scale_y * 0.0001)
-#define to_color(n) (192.0 - ((n) * 192.0))
-
-static const char * const colorwheel[12] = {
- "rgb(255,32,32)", // red
- "rgb(32,192,192)", // cyan
- "rgb(255,128,32)", // orange
- "rgb(128,32,192)", // blue-violet
- "rgb(255,255,32)", // yellow
- "rgb(192,32,128)", // red-violet
- "rgb(32,255,32)", // green
- "rgb(255,64,32)", // red-orange
- "rgb(32,32,255)", // blue
- "rgb(255,192,32)", // yellow-orange
- "rgb(192,32,192)", // violet
- "rgb(32,192,32)" // yellow-green
-};
-
-static double idletime = -1.0;
-static int pfiltered = 0;
-static int pcount = 0;
-static int kcount = 0;
-static double psize = 0;
-static double ksize = 0;
-static double esize = 0;
-static struct list_sample_data *sampledata;
-static struct list_sample_data *prev_sampledata;
-
-static void svg_header(FILE *of, struct list_sample_data *head, double graph_start, int n_cpus) {
- double w;
- double h;
- struct list_sample_data *sampledata_last;
-
- assert(head);
-
- sampledata_last = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- sampledata_last = sampledata;
- }
-
- /* min width is about 1600px due to the label */
- w = 150.0 + 10.0 + time_to_graph(sampledata_last->sampletime - graph_start);
- w = ((w < 1600.0) ? 1600.0 : w);
-
- /* height is variable based on pss, psize, ksize */
- h = 400.0 + (arg_scale_y * 30.0) /* base graphs and title */
- + (arg_pss ? (100.0 * arg_scale_y) + (arg_scale_y * 7.0) : 0.0) /* pss estimate */
- + psize + ksize + esize + (n_cpus * 15 * arg_scale_y);
-
- fprintf(of, "<?xml version=\"1.0\" standalone=\"no\"?>\n");
- fprintf(of, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" ");
- fprintf(of, "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
-
- //fprintf(of, "<g transform=\"translate(10,%d)\">\n", 1000 + 150 + (pcount * 20));
- fprintf(of, "<svg width=\"%.0fpx\" height=\"%.0fpx\" version=\"1.1\" ", w, h);
- fprintf(of, "xmlns=\"http://www.w3.org/2000/svg\">\n\n");
-
- /* write some basic info as a comment, including some help */
- fprintf(of, "<!-- This file is a bootchart SVG file. It is best rendered in a browser -->\n");
- fprintf(of, "<!-- such as Chrome, Chromium, or Firefox. Other applications that -->\n");
- fprintf(of, "<!-- render these files properly but more slowly are ImageMagick, gimp, -->\n");
- fprintf(of, "<!-- inkscape, etc. To display the files on your system, just point -->\n");
- fprintf(of, "<!-- your browser to file:///run/log/ and click. This bootchart was -->\n\n");
-
- fprintf(of, "<!-- generated by bootchart version %s, running with options: -->\n", VERSION);
- fprintf(of, "<!-- hz=\"%f\" n=\"%d\" -->\n", arg_hz, arg_samples_len);
- fprintf(of, "<!-- x=\"%f\" y=\"%f\" -->\n", arg_scale_x, arg_scale_y);
- fprintf(of, "<!-- rel=\"%d\" f=\"%d\" -->\n", arg_relative, arg_filter);
- fprintf(of, "<!-- p=\"%d\" e=\"%d\" -->\n", arg_pss, arg_entropy);
- fprintf(of, "<!-- o=\"%s\" i=\"%s\" -->\n\n", arg_output_path, arg_init_path);
-
- /* style sheet */
- fprintf(of, "<defs>\n <style type=\"text/css\">\n <![CDATA[\n");
-
- fprintf(of, " rect { stroke-width: 1; }\n");
- fprintf(of, " rect.bg { fill: rgb(255,255,255); }\n");
- fprintf(of, " rect.cpu { fill: rgb(64,64,240); stroke-width: 0; fill-opacity: 0.7; }\n");
- fprintf(of, " rect.wait { fill: rgb(240,240,0); stroke-width: 0; fill-opacity: 0.7; }\n");
- fprintf(of, " rect.bi { fill: rgb(240,128,128); stroke-width: 0; fill-opacity: 0.7; }\n");
- fprintf(of, " rect.bo { fill: rgb(192,64,64); stroke-width: 0; fill-opacity: 0.7; }\n");
- fprintf(of, " rect.ps { fill: rgb(192,192,192); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
- fprintf(of, " rect.krnl { fill: rgb(240,240,0); stroke: rgb(128,128,128); fill-opacity: 0.7; }\n");
- fprintf(of, " rect.box { fill: rgb(240,240,240); stroke: rgb(192,192,192); }\n");
- fprintf(of, " rect.clrw { stroke-width: 0; fill-opacity: 0.7;}\n");
- fprintf(of, " line { stroke: rgb(64,64,64); stroke-width: 1; }\n");
- fprintf(of, "// line.sec1 { }\n");
- fprintf(of, " line.sec5 { stroke-width: 2; }\n");
- fprintf(of, " line.sec01 { stroke: rgb(224,224,224); stroke-width: 1; }\n");
- fprintf(of, " line.dot { stroke-dasharray: 2 4; }\n");
- fprintf(of, " line.idle { stroke: rgb(64,64,64); stroke-dasharray: 10 6; stroke-opacity: 0.7; }\n");
-
- fprintf(of, " .run { font-size: 8; font-style: italic; }\n");
- fprintf(of, " text { font-family: Verdana, Helvetica; font-size: 10; }\n");
- fprintf(of, " text.sec { font-size: 8; }\n");
- fprintf(of, " text.t1 { font-size: 24; }\n");
- fprintf(of, " text.t2 { font-size: 12; }\n");
- fprintf(of, " text.idle { font-size: 18; }\n");
-
- fprintf(of, " ]]>\n </style>\n</defs>\n\n");
-}
-
-static int svg_title(FILE *of, const char *build, int pscount, double log_start, int overrun) {
- _cleanup_free_ char *cmdline = NULL;
- _cleanup_free_ char *model = NULL;
- _cleanup_free_ char *buf = NULL;
- char date[256] = "Unknown";
- const char *cpu;
- char *c;
- time_t t;
- int r;
- struct utsname uts;
-
- r = read_one_line_file("/proc/cmdline", &cmdline);
- if (r < 0) {
- log_error_errno(r, "Unable to read cmdline: %m");
- return r;
- }
-
- /* extract root fs so we can find disk model name in sysfs */
- /* FIXME: this works only in the simple case */
- c = strstr(cmdline, "root=/dev/");
- if (c) {
- char rootbdev[4];
- char filename[32];
-
- strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1);
- rootbdev[3] = '\0';
- xsprintf(filename, "/sys/block/%s/device/model", rootbdev);
-
- r = read_one_line_file(filename, &model);
- if (r < 0)
- log_info("Error reading disk model for %s: %m\n", rootbdev);
- }
-
- /* various utsname parameters */
- r = uname(&uts);
- if (r < 0) {
- log_error("Error getting uname info\n");
- return -errno;
- }
-
- /* date */
- t = time(NULL);
- r = strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
- assert_se(r > 0);
-
- /* CPU type */
- r = get_proc_field("/proc/cpuinfo", PROC_CPUINFO_MODEL, "\n", &buf);
- if (r < 0)
- cpu = "Unknown";
- else
- cpu = buf;
-
- fprintf(of, "<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n",
- uts.nodename, date);
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"50\">System: %s %s %s %s</text>\n",
- uts.sysname, uts.release, uts.version, uts.machine);
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"65\">CPU: %s</text>\n", cpu);
- if (model)
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"80\">Disk: %s</text>\n", model);
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"95\">Boot options: %s</text>\n", cmdline);
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"110\">Build: %s</text>\n", build);
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"125\">Log start time: %.03fs</text>\n", log_start);
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"140\">Idle time: ");
-
- if (idletime >= 0.0)
- fprintf(of, "%.03fs", idletime);
- else
- fprintf(of, "Not detected");
-
- fprintf(of, "</text>\n");
- fprintf(of, "<text class=\"sec\" x=\"20\" y=\"155\">Graph data: %.03f samples/sec, recorded %i total, dropped %i samples, %i processes, %i filtered</text>\n",
- arg_hz, arg_samples_len, overrun, pscount, pfiltered);
-
- return 0;
-}
-
-static void svg_graph_box(FILE *of, struct list_sample_data *head, int height, double graph_start) {
- double d = 0.0;
- int i = 0;
- double finalsample = 0.0;
- struct list_sample_data *sampledata_last;
-
- sampledata_last = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- sampledata_last = sampledata;
- }
-
- finalsample = sampledata_last->sampletime;
-
- /* outside box, fill */
- fprintf(of, "<rect class=\"box\" x=\"%.03f\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(0.0),
- time_to_graph(finalsample - graph_start),
- ps_to_graph(height));
-
- for (d = graph_start; d <= finalsample;
- d += (arg_scale_x < 2.0 ? 60.0 : arg_scale_x < 10.0 ? 1.0 : 0.1)) {
- /* lines for each second */
- if (i % 50 == 0)
- fprintf(of, " <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(d - graph_start),
- time_to_graph(d - graph_start),
- ps_to_graph(height));
- else if (i % 10 == 0)
- fprintf(of, " <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(d - graph_start),
- time_to_graph(d - graph_start),
- ps_to_graph(height));
- else
- fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(d - graph_start),
- time_to_graph(d - graph_start),
- ps_to_graph(height));
-
- /* time label */
- if (i % 10 == 0)
- fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
- time_to_graph(d - graph_start),
- -5.0, d - graph_start);
-
- i++;
- }
-}
-
-/* xml comments must not contain "--" */
-static char* xml_comment_encode(const char* name) {
- char *enc_name, *p;
-
- enc_name = strdup(name);
- if (!enc_name)
- return NULL;
-
- for (p = enc_name; *p; p++)
- if (p[0] == '-' && p[1] == '-')
- p[1] = '_';
-
- return enc_name;
-}
-
-static void svg_pss_graph(FILE *of,
- struct list_sample_data *head,
- struct ps_struct *ps_first,
- double graph_start) {
- struct ps_struct *ps;
- int i;
- struct list_sample_data *sampledata_last;
-
- sampledata_last = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- sampledata_last = sampledata;
- }
-
-
- fprintf(of, "\n\n<!-- Pss memory size graph -->\n");
-
- fprintf(of, "\n <text class=\"t2\" x=\"5\" y=\"-15\">Memory allocation - Pss</text>\n");
-
- /* vsize 1000 == 1000mb */
- svg_graph_box(of, head, 100, graph_start);
- /* draw some hlines for usable memory sizes */
- for (i = 100000; i < 1000000; i += 100000) {
- fprintf(of, " <line class=\"sec01\" x1=\"%.03f\" y1=\"%.0f\" x2=\"%.03f\" y2=\"%.0f\"/>\n",
- time_to_graph(.0),
- kb_to_graph(i),
- time_to_graph(sampledata_last->sampletime - graph_start),
- kb_to_graph(i));
- fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.0f\">%dM</text>\n",
- time_to_graph(sampledata_last->sampletime - graph_start) + 5,
- kb_to_graph(i), (1000000 - i) / 1000);
- }
- fprintf(of, "\n");
-
- /* now plot the graph itself */
- i = 1;
- prev_sampledata = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int bottom;
- int top;
- struct ps_sched_struct *cross_place;
-
- bottom = 0;
- top = 0;
-
- /* put all the small pss blocks into the bottom */
- ps = ps_first;
- while (ps->next_ps) {
- ps = ps->next_ps;
- if (!ps)
- continue;
- ps->sample = ps->first;
- while (ps->sample->next) {
- ps->sample = ps->sample->next;
- if (ps->sample->sampledata == sampledata)
- break;
- }
- if (ps->sample->sampledata == sampledata) {
- if (ps->sample->pss <= (100 * arg_scale_y))
- top += ps->sample->pss;
- break;
- }
- }
- while (ps->sample->cross) {
- cross_place = ps->sample->cross;
- ps = ps->sample->cross->ps_new;
- ps->sample = cross_place;
- if (ps->sample->pss <= (100 * arg_scale_y))
- top += ps->sample->pss;
- }
-
- fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- "rgb(64,64,64)",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - top),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- kb_to_graph(top - bottom));
- bottom = top;
-
- /* now plot the ones that are of significant size */
- ps = ps_first;
- while (ps->next_ps) {
- ps = ps->next_ps;
- if (!ps)
- continue;
- ps->sample = ps->first;
- while (ps->sample->next) {
- ps->sample = ps->sample->next;
- if (ps->sample->sampledata == sampledata)
- break;
- }
- /* don't draw anything smaller than 2mb */
- if (ps->sample->sampledata != sampledata)
- continue;
- if (ps->sample->pss > (100 * arg_scale_y)) {
- top = bottom + ps->sample->pss;
- fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- colorwheel[ps->pid % 12],
- time_to_graph(prev_sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - top),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- kb_to_graph(top - bottom));
- bottom = top;
- }
- break;
- }
-
- while ((cross_place = ps->sample->cross)) {
- ps = ps->sample->cross->ps_new;
- ps->sample = cross_place;
- if (ps->sample->pss > (100 * arg_scale_y)) {
- top = bottom + ps->sample->pss;
- fprintf(of, " <rect class=\"clrw\" style=\"fill: %s\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- colorwheel[ps->pid % 12],
- time_to_graph(prev_sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - top),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- kb_to_graph(top - bottom));
- bottom = top;
- }
- }
-
- prev_sampledata = sampledata;
- i++;
- }
-
- /* overlay all the text labels */
- i = 1;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int bottom;
- int top = 0;
- struct ps_sched_struct *prev_sample;
- struct ps_sched_struct *cross_place;
-
- /* put all the small pss blocks into the bottom */
- ps = ps_first->next_ps;
- while (ps->next_ps) {
- ps = ps->next_ps;
- if (!ps)
- continue;
-
- ps->sample = ps->first;
- while (ps->sample->next) {
- ps->sample = ps->sample->next;
- if (ps->sample->sampledata == sampledata)
- break;
- }
-
- if (ps->sample->sampledata == sampledata) {
- if (ps->sample->pss <= (100 * arg_scale_y))
- top += ps->sample->pss;
-
- break;
- }
- }
-
- while ((cross_place = ps->sample->cross)) {
- ps = ps->sample->cross->ps_new;
- ps->sample = cross_place;
- if (ps->sample->pss <= (100 * arg_scale_y))
- top += ps->sample->pss;
- }
- bottom = top;
-
- /* now plot the ones that are of significant size */
- ps = ps_first;
- while (ps->next_ps) {
- prev_sample = ps->sample;
- ps = ps->next_ps;
- if (!ps)
- continue;
- ps->sample = ps->first;
- while (ps->sample->next) {
- prev_sample = ps->sample;
- ps->sample = ps->sample->next;
- if (ps->sample->sampledata == sampledata)
- break;
- }
- /* don't draw anything smaller than 2mb */
- if (ps->sample->sampledata == sampledata) {
- if (ps->sample->pss > (100 * arg_scale_y)) {
- top = bottom + ps->sample->pss;
- /* draw a label with the process / PID */
- if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y)))
- fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
- time_to_graph(sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
- ps->name, ps->pid);
- bottom = top;
- }
- break;
- }
- }
- while ((cross_place = ps->sample->cross)) {
- ps = ps->sample->cross->ps_new;
- ps->sample = cross_place;
- prev_sample = ps->sample->prev;
- if (ps->sample->pss > (100 * arg_scale_y)) {
- top = bottom + ps->sample->pss;
- /* draw a label with the process / PID */
- if ((i == 1) || (prev_sample->pss <= (100 * arg_scale_y)))
- fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]</text>\n",
- time_to_graph(sampledata->sampletime - graph_start),
- kb_to_graph(1000000.0 - bottom - ((top - bottom) / 2)),
- ps->name, ps->pid);
- bottom = top;
- }
- }
-
- i++;
- }
-
- /* debug output - full data dump */
- fprintf(of, "\n\n<!-- PSS map - csv format -->\n");
- ps = ps_first;
- while (ps->next_ps) {
- _cleanup_free_ char *enc_name = NULL;
- ps = ps->next_ps;
- if (!ps)
- continue;
-
- enc_name = xml_comment_encode(ps->name);
- if (!enc_name)
- continue;
-
- fprintf(of, "<!-- %s [%d] pss=", enc_name, ps->pid);
-
- ps->sample = ps->first;
- while (ps->sample->next) {
- ps->sample = ps->sample->next;
- fprintf(of, "%d," , ps->sample->pss);
- }
-
- fprintf(of, " -->\n");
- }
-
-}
-
-static void svg_io_bi_bar(FILE *of,
- struct list_sample_data *head,
- int n_samples,
- double graph_start,
- double interval) {
-
- double max = 0.0;
- double range;
- int max_here = 0;
- int i;
- int k;
- struct list_sample_data *start_sampledata;
- struct list_sample_data *stop_sampledata;
-
- fprintf(of, "<!-- IO utilization graph - In -->\n");
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - read</text>\n");
-
- /*
- * calculate rounding range
- *
- * We need to round IO data since IO block data is not updated on
- * each poll. Applying a smoothing function loses some burst data,
- * so keep the smoothing range short.
- */
- range = 0.25 / (1.0 / arg_hz);
- if (range < 2.0)
- range = 2.0; /* no smoothing */
-
- /* surrounding box */
- svg_graph_box(of, head, 5, graph_start);
-
- /* find the max IO first */
- i = 1;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int start;
- int stop;
- int diff;
- double tot;
-
- start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), n_samples - 1);
- diff = (stop - start);
-
- start_sampledata = sampledata;
- stop_sampledata = sampledata;
-
- for (k = 0; k < ((range/2) - 1) && start_sampledata->link_next; k++)
- start_sampledata = start_sampledata->link_next;
-
- for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
- stop_sampledata = stop_sampledata->link_prev;
-
- tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
-
- if (tot > max) {
- max = tot;
- max_here = i;
- }
-
- tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff;
-
- if (tot > max)
- max = tot;
-
- i++;
- }
-
- /* plot bi */
- i = 1;
- prev_sampledata = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int start;
- int stop;
- int diff;
- double tot;
- double pbi = 0;
-
- start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), n_samples);
- diff = (stop - start);
-
- start_sampledata = sampledata;
- stop_sampledata = sampledata;
-
- for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++)
- start_sampledata = start_sampledata->link_next;
-
- for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
- stop_sampledata = stop_sampledata->link_prev;
-
- tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
-
- if (max > 0)
- pbi = tot / max;
-
- if (pbi > 0.001)
- fprintf(of, "<rect class=\"bi\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- (arg_scale_y * 5) - (pbi * (arg_scale_y * 5)),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- pbi * (arg_scale_y * 5));
-
- /* labels around highest value */
- if (i == max_here)
- fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
- time_to_graph(sampledata->sampletime - graph_start) + 5,
- ((arg_scale_y * 5) - (pbi * (arg_scale_y * 5))) + 15,
- max / 1024.0 / (interval / 1000000000.0));
-
- i++;
- prev_sampledata = sampledata;
- }
-}
-
-static void svg_io_bo_bar(FILE *of,
- struct list_sample_data *head,
- int n_samples,
- double graph_start,
- double interval) {
- double max = 0.0;
- double range;
- int max_here = 0;
- int i;
- int k;
- struct list_sample_data *start_sampledata;
- struct list_sample_data *stop_sampledata;
-
- fprintf(of, "<!-- IO utilization graph - out -->\n");
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">IO utilization - write</text>\n");
-
- /*
- * calculate rounding range
- *
- * We need to round IO data since IO block data is not updated on
- * each poll. Applying a smoothing function loses some burst data,
- * so keep the smoothing range short.
- */
- range = 0.25 / (1.0 / arg_hz);
- if (range < 2.0)
- range = 2.0; /* no smoothing */
-
- /* surrounding box */
- svg_graph_box(of, head, 5, graph_start);
-
- /* find the max IO first */
- i = 0;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int start;
- int stop;
- int diff;
- double tot;
-
- start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), n_samples - 1);
- diff = (stop - start);
-
- start_sampledata = sampledata;
- stop_sampledata = sampledata;
-
- for (k = 0; k < (range/2) - 1 && start_sampledata->link_next; k++)
- start_sampledata = start_sampledata->link_next;
-
- for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
- stop_sampledata = stop_sampledata->link_prev;
-
- tot = (double)(stop_sampledata->blockstat.bi - start_sampledata->blockstat.bi) / diff;
- if (tot > max)
- max = tot;
-
- tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo) / diff;
- if (tot > max) {
- max = tot;
- max_here = i;
- }
-
- i++;
- }
-
- /* plot bo */
- prev_sampledata = head;
- i = 1;
-
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int start, stop, diff;
- double tot, pbo;
-
- pbo = 0;
-
- start = MAX(i - ((range / 2) - 1), 0);
- stop = MIN(i + (range / 2), n_samples);
- diff = (stop - start);
-
- start_sampledata = sampledata;
- stop_sampledata = sampledata;
-
- for (k = 0; k < ((range/2)-1) && start_sampledata->link_next; k++)
- start_sampledata = start_sampledata->link_next;
-
- for (k = 0; k < (range/2) && stop_sampledata->link_prev; k++)
- stop_sampledata = stop_sampledata->link_prev;
-
- tot = (double)(stop_sampledata->blockstat.bo - start_sampledata->blockstat.bo)
- / diff;
-
- if (max > 0)
- pbo = tot / max;
-
- if (pbo > 0.001)
- fprintf(of, "<rect class=\"bo\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- (arg_scale_y * 5) - (pbo * (arg_scale_y * 5)),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- pbo * (arg_scale_y * 5));
-
- /* labels around highest bo value */
- if (i == max_here)
- fprintf(of, " <text class=\"sec\" x=\"%.03f\" y=\"%.03f\">%0.2fmb/sec</text>\n",
- time_to_graph(sampledata->sampletime - graph_start) + 5,
- ((arg_scale_y * 5) - (pbo * (arg_scale_y * 5))),
- max / 1024.0 / (interval / 1000000000.0));
-
- i++;
- prev_sampledata = sampledata;
- }
-}
-
-static void svg_cpu_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) {
-
- fprintf(of, "<!-- CPU utilization graph -->\n");
-
- if (cpu_num < 0)
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] utilization</text>\n");
- else
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] utilization</text>\n", cpu_num);
-
- /* surrounding box */
- svg_graph_box(of, head, 5, graph_start);
-
- /* bars for each sample, proportional to the CPU util. */
- prev_sampledata = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int c;
- double trt;
- double ptrt;
-
- ptrt = trt = 0.0;
-
- if (cpu_num < 0)
- for (c = 0; c < n_cpus; c++)
- trt += sampledata->runtime[c] - prev_sampledata->runtime[c];
- else
- trt = sampledata->runtime[cpu_num] - prev_sampledata->runtime[cpu_num];
-
- trt = trt / 1000000000.0;
-
- if (cpu_num < 0)
- trt = trt / (double)n_cpus;
-
- if (trt > 0.0)
- ptrt = trt / (sampledata->sampletime - prev_sampledata->sampletime);
-
- if (ptrt > 1.0)
- ptrt = 1.0;
-
- if (ptrt > 0.001)
- fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- (arg_scale_y * 5) - (ptrt * (arg_scale_y * 5)),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- ptrt * (arg_scale_y * 5));
-
- prev_sampledata = sampledata;
- }
-}
-
-static void svg_wait_bar(FILE *of, struct list_sample_data *head, int n_cpus, int cpu_num, double graph_start) {
-
- fprintf(of, "<!-- Wait time aggregation box -->\n");
-
- if (cpu_num < 0)
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[overall] wait</text>\n");
- else
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">CPU[%d] wait</text>\n", cpu_num);
-
- /* surrounding box */
- svg_graph_box(of, head, 5, graph_start);
-
- /* bars for each sample, proportional to the CPU util. */
- prev_sampledata = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- int c;
- double twt;
- double ptwt;
-
- ptwt = twt = 0.0;
-
- if (cpu_num < 0)
- for (c = 0; c < n_cpus; c++)
- twt += sampledata->waittime[c] - prev_sampledata->waittime[c];
- else
- twt = sampledata->waittime[cpu_num] - prev_sampledata->waittime[cpu_num];
-
- twt = twt / 1000000000.0;
-
- if (cpu_num < 0)
- twt = twt / (double)n_cpus;
-
- if (twt > 0.0)
- ptwt = twt / (sampledata->sampletime - prev_sampledata->sampletime);
-
- if (ptwt > 1.0)
- ptwt = 1.0;
-
- if (ptwt > 0.001)
- fprintf(of, "<rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- ((arg_scale_y * 5) - (ptwt * (arg_scale_y * 5))),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- ptwt * (arg_scale_y * 5));
-
- prev_sampledata = sampledata;
- }
-}
-
-static void svg_entropy_bar(FILE *of, struct list_sample_data *head, double graph_start) {
-
- fprintf(of, "<!-- entropy pool graph -->\n");
-
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Entropy pool size</text>\n");
- /* surrounding box */
- svg_graph_box(of, head, 5, graph_start);
-
- /* bars for each sample, scale 0-4096 */
- prev_sampledata = head;
- LIST_FOREACH_BEFORE(link, sampledata, head) {
- fprintf(of, "<rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev_sampledata->sampletime - graph_start),
- ((arg_scale_y * 5) - ((sampledata->entropy_avail / 4096.) * (arg_scale_y * 5))),
- time_to_graph(sampledata->sampletime - prev_sampledata->sampletime),
- (sampledata->entropy_avail / 4096.) * (arg_scale_y * 5));
- prev_sampledata = sampledata;
- }
-}
-
-static struct ps_struct *get_next_ps(struct ps_struct *ps, struct ps_struct *ps_first) {
- /*
- * walk the list of processes and return the next one to be
- * painted
- */
- if (ps == ps_first)
- return ps->next_ps;
-
- /* go deep */
- if (ps->children)
- return ps->children;
-
- /* find siblings */
- if (ps->next)
- return ps->next;
-
- /* go back for parent siblings */
- for (;;) {
- if (ps->parent && ps->parent->next)
- return ps->parent->next;
-
- ps = ps->parent;
- if (!ps)
- return ps;
- }
-
- return NULL;
-}
-
-static bool ps_filter(struct ps_struct *ps) {
- if (!arg_filter)
- return false;
-
- /* can't draw data when there is only 1 sample (need start + stop) */
- if (ps->first == ps->last)
- return true;
-
- /* don't filter kthreadd */
- if (ps->pid == 2)
- return false;
-
- /* drop stuff that doesn't use any real CPU time */
- if (ps->total <= 0.001)
- return true;
-
- return 0;
-}
-
-static void svg_do_initcall(FILE *of, struct list_sample_data *head, int count_only, double graph_start) {
- _cleanup_pclose_ FILE *f = NULL;
- double t;
- char func[256];
- int ret;
- int usecs;
-
- /* can't plot initcall when disabled or in relative mode */
- if (!arg_initcall || arg_relative) {
- kcount = 0;
- return;
- }
-
- if (!count_only) {
- fprintf(of, "<!-- initcall -->\n");
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Kernel init threads</text>\n");
- /* surrounding box */
- svg_graph_box(of, head, kcount, graph_start);
- }
-
- kcount = 0;
-
- /*
- * Initcall graphing - parses dmesg buffer and displays kernel threads
- * This somewhat uses the same methods and scaling to show processes
- * but looks a lot simpler. It's overlaid entirely onto the PS graph
- * when appropriate.
- */
-
- f = popen("dmesg", "r");
- if (!f)
- return;
-
- while (!feof(f)) {
- int c;
- int z = 0;
- char l[256];
-
- if (fgets(l, sizeof(l) - 1, f) == NULL)
- continue;
-
- c = sscanf(l, "[%lf] initcall %s %*s %d %*s %d %*s",
- &t, func, &ret, &usecs);
- if (c != 4) {
- /* also parse initcalls done by module loading */
- c = sscanf(l, "[%lf] initcall %s %*s %*s %d %*s %d %*s",
- &t, func, &ret, &usecs);
- if (c != 4)
- continue;
- }
-
- /* chop the +0xXX/0xXX stuff */
- while(func[z] != '+')
- z++;
- func[z] = 0;
-
- if (count_only) {
- /* filter out irrelevant stuff */
- if (usecs >= 1000)
- kcount++;
- continue;
- }
-
- fprintf(of, "<!-- thread=\"%s\" time=\"%.3f\" elapsed=\"%d\" result=\"%d\" -->\n",
- func, t, usecs, ret);
-
- if (usecs < 1000)
- continue;
-
- /* rect */
- fprintf(of, " <rect class=\"krnl\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(t - (usecs / 1000000.0)),
- ps_to_graph(kcount),
- time_to_graph(usecs / 1000000.0),
- ps_to_graph(1));
-
- /* label */
- fprintf(of, " <text x=\"%.03f\" y=\"%.03f\">%s <tspan class=\"run\">%.03fs</tspan></text>\n",
- time_to_graph(t - (usecs / 1000000.0)) + 5,
- ps_to_graph(kcount) + 15,
- func, usecs / 1000000.0);
-
- kcount++;
- }
-}
-
-static void svg_ps_bars(FILE *of,
- struct list_sample_data *head,
- int n_samples,
- int n_cpus,
- struct ps_struct *ps_first,
- double graph_start,
- double interval) {
-
- struct ps_struct *ps;
- int i = 0;
- int j = 0;
- int pid;
- double w = 0.0;
-
- fprintf(of, "<!-- Process graph -->\n");
- fprintf(of, "<text class=\"t2\" x=\"5\" y=\"-15\">Processes</text>\n");
-
- /* surrounding box */
- svg_graph_box(of, head, pcount, graph_start);
-
- /* pass 2 - ps boxes */
- ps = ps_first;
- while ((ps = get_next_ps(ps, ps_first))) {
- _cleanup_free_ char *enc_name = NULL, *escaped = NULL;
- double endtime;
- double starttime;
- int t;
-
- if (!utf8_is_printable(ps->name, strlen(ps->name)))
- escaped = utf8_escape_non_printable(ps->name);
-
- enc_name = xml_comment_encode(escaped ? escaped : ps->name);
- if (!enc_name)
- continue;
-
- /* leave some trace of what we actually filtered etc. */
- fprintf(of, "<!-- %s [%i] ppid=%i runtime=%.03fs -->\n", enc_name, ps->pid,
- ps->ppid, ps->total);
-
- starttime = ps->first->sampledata->sampletime;
-
- if (!ps_filter(ps)) {
- /* remember where _to_ our children need to draw a line */
- ps->pos_x = time_to_graph(starttime - graph_start);
- ps->pos_y = ps_to_graph(j+1); /* bottom left corner */
- } else if (ps->parent){
- /* hook children to our parent coords instead */
- ps->pos_x = ps->parent->pos_x;
- ps->pos_y = ps->parent->pos_y;
-
- /* if this is the last child, we might still need to draw a connecting line */
- if ((!ps->next) && (ps->parent))
- fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- ps->parent->pos_x,
- ps_to_graph(j-1) + 10.0, /* whee, use the last value here */
- ps->parent->pos_x,
- ps->parent->pos_y);
- continue;
- }
-
- endtime = ps->last->sampledata->sampletime;
- fprintf(of, " <rect class=\"ps\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(starttime - graph_start),
- ps_to_graph(j),
- time_to_graph(ps->last->sampledata->sampletime - starttime),
- ps_to_graph(1));
-
- /* paint cpu load over these */
- ps->sample = ps->first;
- t = 1;
- while (ps->sample->next) {
- double rt, prt;
- double wt, wrt;
- struct ps_sched_struct *prev;
-
- prev = ps->sample;
- ps->sample = ps->sample->next;
-
- /* calculate over interval */
- rt = ps->sample->runtime - prev->runtime;
- wt = ps->sample->waittime - prev->waittime;
-
- prt = (rt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime);
- wrt = (wt / 1000000000) / (ps->sample->sampledata->sampletime - prev->sampledata->sampletime);
-
- /* this can happen if timekeeping isn't accurate enough */
- if (prt > 1.0)
- prt = 1.0;
- if (wrt > 1.0)
- wrt = 1.0;
-
- if ((prt < 0.1) && (wrt < 0.1)) /* =~ 26 (color threshold) */
- continue;
-
- fprintf(of, " <rect class=\"wait\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev->sampledata->sampletime - graph_start),
- ps_to_graph(j),
- time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
- ps_to_graph(wrt));
-
- /* draw cpu over wait - TODO figure out how/why run + wait > interval */
- fprintf(of, " <rect class=\"cpu\" x=\"%.03f\" y=\"%.03f\" width=\"%.03f\" height=\"%.03f\" />\n",
- time_to_graph(prev->sampledata->sampletime - graph_start),
- ps_to_graph(j + (1.0 - prt)),
- time_to_graph(ps->sample->sampledata->sampletime - prev->sampledata->sampletime),
- ps_to_graph(prt));
- t++;
- }
-
- /* determine where to display the process name */
- if ((endtime - starttime) < 1.5)
- /* too small to fit label inside the box */
- w = endtime;
- else
- w = starttime;
-
- /* text label of process name */
- fprintf(of, " <text x=\"%.03f\" y=\"%.03f\"><![CDATA[%s]]> [%i]<tspan class=\"run\">%.03fs</tspan> %s</text>\n",
- time_to_graph(w - graph_start) + 5.0,
- ps_to_graph(j) + 14.0,
- escaped ? escaped : ps->name,
- ps->pid,
- (ps->last->runtime - ps->first->runtime) / 1000000000.0,
- arg_show_cgroup ? ps->cgroup : "");
- /* paint lines to the parent process */
- if (ps->parent) {
- /* horizontal part */
- fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(starttime - graph_start),
- ps_to_graph(j) + 10.0,
- ps->parent->pos_x,
- ps_to_graph(j) + 10.0);
-
- /* one vertical line connecting all the horizontal ones up */
- if (!ps->next)
- fprintf(of, " <line class=\"dot\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- ps->parent->pos_x,
- ps_to_graph(j) + 10.0,
- ps->parent->pos_x,
- ps->parent->pos_y);
- }
-
- j++; /* count boxes */
-
- fprintf(of, "\n");
- }
-
- /* last pass - determine when idle */
- pid = getpid();
- /* make sure we start counting from the point where we actually have
- * data: assume that bootchart's first sample is when data started
- */
-
- ps = ps_first;
- while (ps->next_ps) {
- ps = ps->next_ps;
- if (ps->pid == pid)
- break;
- }
-
- /* need to know last node first */
- ps->sample = ps->first;
- i = ps->sample->next->sampledata->counter;
-
- while (ps->sample->next && i<(n_samples-(arg_hz/2))) {
- double crt;
- double brt;
- int c;
- int ii;
- struct ps_sched_struct *sample_hz;
-
- ps->sample = ps->sample->next;
- sample_hz = ps->sample;
- for (ii = 0; (ii < (int)arg_hz/2) && sample_hz->next; ii++)
- sample_hz = sample_hz->next;
-
- /* subtract bootchart cpu utilization from total */
- crt = 0.0;
- for (c = 0; c < n_cpus; c++)
- crt += sample_hz->sampledata->runtime[c] - ps->sample->sampledata->runtime[c];
-
- brt = sample_hz->runtime - ps->sample->runtime;
- /*
- * our definition of "idle":
- *
- * if for (hz / 2) we've used less CPU than (interval / 2) ...
- * defaults to 4.0%, which experimentally, is where atom idles
- */
- if ((crt - brt) < (interval / 2.0)) {
- idletime = ps->sample->sampledata->sampletime - graph_start;
- fprintf(of, "\n<!-- idle detected at %.03f seconds -->\n", idletime);
- fprintf(of, "<line class=\"idle\" x1=\"%.03f\" y1=\"%.03f\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- time_to_graph(idletime),
- -arg_scale_y,
- time_to_graph(idletime),
- ps_to_graph(pcount) + arg_scale_y);
- fprintf(of, "<text class=\"idle\" x=\"%.03f\" y=\"%.03f\">%.01fs</text>\n",
- time_to_graph(idletime) + 5.0,
- ps_to_graph(pcount) + arg_scale_y,
- idletime);
- break;
- }
-
- i++;
- }
-}
-
-static void svg_top_ten_cpu(FILE *of, struct ps_struct *ps_first) {
- struct ps_struct *top[10];
- struct ps_struct emptyps = {};
- struct ps_struct *ps;
- int n, m;
-
- for (n = 0; n < (int) ELEMENTSOF(top); n++)
- top[n] = &emptyps;
-
- /* walk all ps's and setup ptrs */
- ps = ps_first;
- while ((ps = get_next_ps(ps, ps_first))) {
- for (n = 0; n < 10; n++) {
- if (ps->total <= top[n]->total)
- continue;
- /* cascade insert */
- for (m = 9; m > n; m--)
- top[m] = top[m-1];
- top[n] = ps;
- break;
- }
- }
-
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top CPU consumers:</text>\n");
- for (n = 0; n < 10; n++)
- fprintf(of, "<text class=\"t3\" x=\"20\" y=\"%d\">%3.03fs - <![CDATA[%s]]> [%d]</text>\n",
- 20 + (n * 13),
- top[n]->total,
- top[n]->name,
- top[n]->pid);
-}
-
-static void svg_top_ten_pss(FILE *of, struct ps_struct *ps_first) {
- struct ps_struct *top[10];
- struct ps_struct emptyps = {};
- struct ps_struct *ps;
- int n, m;
-
- for (n = 0; n < (int) ELEMENTSOF(top); n++)
- top[n] = &emptyps;
-
- /* walk all ps's and setup ptrs */
- ps = ps_first;
- while ((ps = get_next_ps(ps, ps_first))) {
- for (n = 0; n < 10; n++) {
- if (ps->pss_max <= top[n]->pss_max)
- continue;
-
- /* cascade insert */
- for (m = 9; m > n; m--)
- top[m] = top[m-1];
- top[n] = ps;
- break;
- }
- }
-
- fprintf(of, "<text class=\"t2\" x=\"20\" y=\"0\">Top PSS consumers:</text>\n");
- for (n = 0; n < 10; n++)
- fprintf(of, "<text class=\"t3\" x=\"20\" y=\"%d\">%dK - <![CDATA[%s]]> [%d]</text>\n",
- 20 + (n * 13),
- top[n]->pss_max,
- top[n]->name,
- top[n]->pid);
-}
-
-int svg_do(FILE *of,
- const char *build,
- struct list_sample_data *head,
- struct ps_struct *ps_first,
- int n_samples,
- int pscount,
- int n_cpus,
- double graph_start,
- double log_start,
- double interval,
- int overrun) {
-
- struct ps_struct *ps;
- double offset = 7;
- int r, c;
-
- sampledata = head;
- LIST_FIND_TAIL(link, sampledata, head);
- ps = ps_first;
-
- /* count initcall thread count first */
- svg_do_initcall(of, head, 1, graph_start);
- ksize = kcount ? ps_to_graph(kcount) + (arg_scale_y * 2) : 0;
-
- /* then count processes */
- while ((ps = get_next_ps(ps, ps_first))) {
- if (!ps_filter(ps))
- pcount++;
- else
- pfiltered++;
- }
- psize = ps_to_graph(pcount) + (arg_scale_y * 2);
-
- esize = (arg_entropy ? arg_scale_y * 7 : 0);
-
- /* after this, we can draw the header with proper sizing */
- svg_header(of, head, graph_start, arg_percpu ? n_cpus : 0);
- fprintf(of, "<rect class=\"bg\" width=\"100%%\" height=\"100%%\" />\n\n");
-
- fprintf(of, "<g transform=\"translate(10,400)\">\n");
- svg_io_bi_bar(of, head, n_samples, graph_start, interval);
- fprintf(of, "</g>\n\n");
-
- fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_io_bo_bar(of, head, n_samples, graph_start, interval);
- fprintf(of, "</g>\n\n");
-
- for (c = -1; c < (arg_percpu ? n_cpus : 0); c++) {
- offset += 7;
- fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_cpu_bar(of, head, n_cpus, c, graph_start);
- fprintf(of, "</g>\n\n");
-
- offset += 7;
- fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_wait_bar(of, head, n_cpus, c, graph_start);
- fprintf(of, "</g>\n\n");
- }
-
- if (kcount) {
- offset += 7;
- fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset));
- svg_do_initcall(of, head, 0, graph_start);
- fprintf(of, "</g>\n\n");
- }
-
- offset += 7;
- fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize);
- svg_ps_bars(of, head, n_samples, n_cpus, ps_first, graph_start, interval);
- fprintf(of, "</g>\n\n");
-
- fprintf(of, "<g transform=\"translate(10, 0)\">\n");
- r = svg_title(of, build, pscount, log_start, overrun);
- fprintf(of, "</g>\n\n");
-
- if (r < 0)
- return r;
-
- fprintf(of, "<g transform=\"translate(10,200)\">\n");
- svg_top_ten_cpu(of, ps_first);
- fprintf(of, "</g>\n\n");
-
- if (arg_entropy) {
- fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize);
- svg_entropy_bar(of, head, graph_start);
- fprintf(of, "</g>\n\n");
- }
-
- if (arg_pss) {
- fprintf(of, "<g transform=\"translate(10,%.03f)\">\n", 400.0 + (arg_scale_y * offset) + ksize + psize + esize);
- svg_pss_graph(of, head, ps_first, graph_start);
- fprintf(of, "</g>\n\n");
-
- fprintf(of, "<g transform=\"translate(410,200)\">\n");
- svg_top_ten_pss(of, ps_first);
- fprintf(of, "</g>\n\n");
- }
-
- /* fprintf footer */
- fprintf(of, "\n</svg>\n");
-
- return 0;
-}
diff --git a/src/systemd-bus-proxyd/bus-proxyd.c b/src/systemd-bus-proxyd/bus-proxyd.c
deleted file mode 100644
index 17b80c3e9a..0000000000
--- a/src/systemd-bus-proxyd/bus-proxyd.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2013 Daniel Mack
- Copyright 2014 Kay Sievers
- Copyright 2015 David Herrmann
-
- 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 <getopt.h>
-#include <pthread.h>
-#include <stddef.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <systemd/sd-daemon.h>
-
-#include "alloc-util.h"
-#include "bus-internal.h"
-#include "bus-xml-policy.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;
-
-typedef struct {
- int fd;
- SharedPolicy *policy;
- uid_t bus_uid;
-} ClientContext;
-
-static ClientContext *client_context_free(ClientContext *c) {
- if (!c)
- return NULL;
-
- safe_close(c->fd);
- free(c);
-
- return NULL;
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(ClientContext*, client_context_free);
-
-static int client_context_new(ClientContext **out) {
- _cleanup_(client_context_freep) ClientContext *c = NULL;
-
- c = new0(ClientContext, 1);
- if (!c)
- return -ENOMEM;
-
- c->fd = -1;
-
- *out = c;
- c = NULL;
- return 0;
-}
-
-static void *run_client(void *userdata) {
- _cleanup_(client_context_freep) ClientContext *c = userdata;
- _cleanup_(proxy_freep) Proxy *p = NULL;
- char comm[16];
- int r;
-
- r = proxy_new(&p, c->fd, c->fd, arg_address);
- c->fd = -1;
-
- if (r < 0)
- goto exit;
-
- /* 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))
- comm[sizeof(comm) - 2] = '*';
- (void) prctl(PR_SET_NAME, comm);
-
- r = proxy_set_policy(p, c->policy, arg_configuration);
- if (r < 0)
- goto exit;
-
- r = proxy_hello_policy(p, c->bus_uid);
- if (r < 0)
- goto exit;
-
- r = proxy_run(p);
-
-exit:
- return NULL;
-}
-
-static int loop_clients(int accept_fd, uid_t bus_uid) {
- _cleanup_(shared_policy_freep) SharedPolicy *sp = NULL;
- pthread_attr_t attr;
- int r;
-
- r = pthread_attr_init(&attr);
- 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(r, "Cannot mark pthread attributes as detached: %m");
- goto finish;
- }
-
- r = shared_policy_new(&sp);
- if (r < 0)
- goto finish;
-
- for (;;) {
- ClientContext *c;
- pthread_t tid;
- int fd;
-
- fd = accept4(accept_fd, NULL, NULL, SOCK_NONBLOCK | SOCK_CLOEXEC);
- if (fd < 0) {
- if (errno == EAGAIN || errno == EINTR)
- continue;
-
- r = log_error_errno(errno, "accept4() failed: %m");
- goto finish;
- }
-
- r = client_context_new(&c);
- if (r < 0) {
- log_oom();
- close(fd);
- continue;
- }
-
- c->fd = fd;
- c->policy = sp;
- c->bus_uid = bus_uid;
-
- r = pthread_create(&tid, &attr, run_client, c);
- if (r != 0) {
- log_warning_errno(r, "Cannot spawn thread, ignoring: %m");
- client_context_free(c);
- continue;
- }
- }
-
-finish:
- pthread_attr_destroy(&attr);
- return r;
-}
-
-static int help(void) {
-
- printf("%s [OPTIONS...]\n\n"
- "DBus proxy server.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --configuration=PATH Configuration file or directory\n"
- " --machine=MACHINE Connect to specified machine\n"
- " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
- " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
- program_invocation_short_name);
-
- return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
- enum {
- ARG_VERSION = 0x100,
- ARG_ADDRESS,
- ARG_CONFIGURATION,
- ARG_MACHINE,
- };
-
- static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "address", required_argument, NULL, ARG_ADDRESS },
- { "configuration", required_argument, NULL, ARG_CONFIGURATION },
- { "machine", required_argument, NULL, ARG_MACHINE },
- {},
- };
-
- int c, r;
-
- assert(argc >= 0);
- assert(argv);
-
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
-
- switch (c) {
-
- case 'h':
- help();
- return 0;
-
- case ARG_VERSION:
- return version();
-
- case ARG_ADDRESS:
- r = free_and_strdup(&arg_address, optarg);
- if (r < 0)
- return log_oom();
- break;
-
- case ARG_CONFIGURATION:
- r = strv_extend(&arg_configuration, optarg);
- if (r < 0)
- return log_oom();
- break;
-
- case ARG_MACHINE: {
- _cleanup_free_ char *e = NULL;
- char *a;
-
- e = bus_address_escape(optarg);
- if (!e)
- return log_oom();
-
- a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
- if (!a)
- return log_oom();
-
- free(arg_address);
- arg_address = a;
-
- break;
- }
-
- case '?':
- return -EINVAL;
-
- default:
- assert_not_reached("Unhandled option");
- }
-
- if (argc > optind) {
- log_error("Too many arguments");
- return -EINVAL;
- }
-
- if (!arg_address) {
- arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
- if (!arg_address)
- return log_oom();
- }
-
- return 1;
-}
-
-int main(int argc, char *argv[]) {
- int r, accept_fd;
- uid_t uid, bus_uid;
- gid_t gid;
-
- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
- log_parse_environment();
- log_open();
-
- bus_uid = getuid();
-
- if (geteuid() == 0) {
- const char *user = "systemd-bus-proxy";
-
- r = get_user_creds(&user, &uid, &gid, NULL, NULL);
- if (r < 0) {
- log_error_errno(r, "Cannot resolve user name %s: %m", user);
- goto finish;
- }
-
- r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER);
- if (r < 0) {
- log_error_errno(r, "Cannot drop privileges: %m");
- goto finish;
- }
- }
-
- r = parse_argv(argc, argv);
- if (r <= 0)
- goto finish;
-
- r = sd_listen_fds(0);
- if (r != 1) {
- log_error("Illegal number of file descriptors passed");
- goto finish;
- }
-
- accept_fd = SD_LISTEN_FDS_START;
-
- r = fd_nonblock(accept_fd, false);
- if (r < 0) {
- log_error_errno(r, "Cannot mark accept-fd non-blocking: %m");
- goto finish;
- }
-
- r = loop_clients(accept_fd, bus_uid);
-
-finish:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down.");
-
- strv_free(arg_configuration);
- free(arg_address);
-
- return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
-}
diff --git a/src/systemd-cgls/cgls.c b/src/systemd-cgls/cgls.c
index 5862cdb282..ed2846ee57 100644
--- a/src/systemd-cgls/cgls.c
+++ b/src/systemd-cgls/cgls.c
@@ -184,14 +184,15 @@ int main(int argc, char *argv[]) {
goto finish;
if (!arg_no_pager) {
- r = pager_open(false);
+ r = pager_open(arg_no_pager, false);
if (r > 0 && arg_full < 0)
arg_full = true;
}
output_flags =
arg_all * OUTPUT_SHOW_ALL |
- (arg_full > 0) * OUTPUT_FULL_WIDTH;
+ (arg_full > 0) * OUTPUT_FULL_WIDTH |
+ arg_kernel_threads * OUTPUT_KERNEL_THREADS;
if (optind < argc) {
_cleanup_free_ char *root = NULL;
@@ -209,7 +210,7 @@ int main(int argc, char *argv[]) {
printf("Directory %s:\n", argv[i]);
fflush(stdout);
- q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags);
+ q = show_cgroup_by_path(argv[i], NULL, 0, output_flags);
} else {
_cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
const char *controller, *path;
@@ -235,7 +236,7 @@ int main(int argc, char *argv[]) {
show_cg_info(controller, path);
- q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags);
+ q = show_cgroup(controller, path, NULL, 0, output_flags);
}
if (q < 0)
@@ -258,7 +259,7 @@ int main(int argc, char *argv[]) {
printf("Working directory %s:\n", cwd);
fflush(stdout);
- r = show_cgroup_by_path(cwd, NULL, 0, arg_kernel_threads, output_flags);
+ r = show_cgroup_by_path(cwd, NULL, 0, output_flags);
done = true;
}
}
@@ -273,7 +274,7 @@ int main(int argc, char *argv[]) {
show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
printf("-.slice\n");
- r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
+ r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags);
}
}
diff --git a/src/systemd-cgroups-agent/cgroups-agent.c b/src/systemd-cgroups-agent/cgroups-agent.c
index 79098b5f2c..d7c722ac3d 100644
--- a/src/systemd-cgroups-agent/cgroups-agent.c
+++ b/src/systemd-cgroups-agent/cgroups-agent.c
@@ -18,15 +18,22 @@
***/
#include <stdlib.h>
+#include <sys/socket.h>
-#include <systemd/sd-bus.h>
-
-#include "bus-util.h"
+#include "fd-util.h"
#include "log.h"
+#include "socket-util.h"
int main(int argc, char *argv[]) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- int r;
+
+ static const union sockaddr_union sa = {
+ .un.sun_family = AF_UNIX,
+ .un.sun_path = "/run/systemd/cgroups-agent",
+ };
+
+ _cleanup_close_ int fd = -1;
+ ssize_t n;
+ size_t l;
if (argc != 2) {
log_error("Incorrect number of arguments.");
@@ -37,27 +44,22 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- /* We send this event to the private D-Bus socket and then the
- * system instance will forward this to the system bus. We do
- * this to avoid an activation loop when we start dbus when we
- * are called when the dbus service is shut down. */
-
- 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
- * initrd to the system, so let's ignore this */
- log_debug_errno(r, "Failed to get D-Bus connection: %m");
+ fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ log_debug_errno(errno, "Failed to allocate socket: %m");
+ return EXIT_FAILURE;
+ }
+
+ l = strlen(argv[1]);
+
+ n = sendto(fd, argv[1], l, 0, &sa.sa, SOCKADDR_UN_LEN(sa.un));
+ if (n < 0) {
+ log_debug_errno(errno, "Failed to send cgroups agent message: %m");
return EXIT_FAILURE;
}
- r = sd_bus_emit_signal(bus,
- "/org/freedesktop/systemd1/agent",
- "org.freedesktop.systemd1.Agent",
- "Released",
- "s", argv[1]);
- if (r < 0) {
- log_debug_errno(r, "Failed to send signal message on private connection: %m");
+ if ((size_t) n != l) {
+ log_debug("Datagram size mismatch");
return EXIT_FAILURE;
}
diff --git a/src/systemd-cgtop/cgtop.c b/src/systemd-cgtop/cgtop.c
index 5d021e5ef4..6cbea86070 100644
--- a/src/systemd-cgtop/cgtop.c
+++ b/src/systemd-cgtop/cgtop.c
@@ -72,13 +72,13 @@ static bool arg_batch = false;
static bool arg_raw = false;
static usec_t arg_delay = 1*USEC_PER_SEC;
static char* arg_machine = NULL;
+static bool arg_recursive = true;
-enum {
+static enum {
COUNT_PIDS,
COUNT_USERSPACE_PROCESSES,
COUNT_ALL_PROCESSES,
} arg_count = COUNT_PIDS;
-static bool arg_recursive = true;
static enum {
ORDER_PATH,
@@ -269,13 +269,15 @@ static int process(
if (g->memory > 0)
g->memory_valid = true;
- } else if (streq(controller, "blkio") && cg_unified() <= 0) {
+ } else if ((streq(controller, "io") && cg_unified() > 0) ||
+ (streq(controller, "blkio") && cg_unified() <= 0)) {
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
+ bool unified = cg_unified() > 0;
uint64_t wr = 0, rd = 0;
nsec_t timestamp;
- r = cg_get_path(controller, path, "blkio.io_service_bytes", &p);
+ r = cg_get_path(controller, path, unified ? "io.stat" : "blkio.io_service_bytes", &p);
if (r < 0)
return r;
@@ -293,25 +295,38 @@ static int process(
if (!fgets(line, sizeof(line), f))
break;
+ /* Trim and skip the device */
l = strstrip(line);
l += strcspn(l, WHITESPACE);
l += strspn(l, WHITESPACE);
- if (first_word(l, "Read")) {
- l += 4;
- q = &rd;
- } else if (first_word(l, "Write")) {
- l += 5;
- q = &wr;
- } else
- continue;
+ if (unified) {
+ while (!isempty(l)) {
+ if (sscanf(l, "rbytes=%" SCNu64, &k))
+ rd += k;
+ else if (sscanf(l, "wbytes=%" SCNu64, &k))
+ wr += k;
- l += strspn(l, WHITESPACE);
- r = safe_atou64(l, &k);
- if (r < 0)
- continue;
-
- *q += k;
+ l += strcspn(l, WHITESPACE);
+ l += strspn(l, WHITESPACE);
+ }
+ } else {
+ if (first_word(l, "Read")) {
+ l += 4;
+ q = &rd;
+ } else if (first_word(l, "Write")) {
+ l += 5;
+ q = &wr;
+ } else
+ continue;
+
+ l += strspn(l, WHITESPACE);
+ r = safe_atou64(l, &k);
+ if (r < 0)
+ continue;
+
+ *q += k;
+ }
}
timestamp = now_nsec(CLOCK_MONOTONIC);
@@ -362,7 +377,7 @@ static int refresh_one(
Group **ret) {
_cleanup_closedir_ DIR *d = NULL;
- Group *ours;
+ Group *ours = NULL;
int r;
assert(controller);
@@ -439,6 +454,9 @@ static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration)
r = refresh_one("memory", root, a, b, iteration, 0, NULL);
if (r < 0)
return r;
+ r = refresh_one("io", root, a, b, iteration, 0, NULL);
+ if (r < 0)
+ return r;
r = refresh_one("blkio", root, a, b, iteration, 0, NULL);
if (r < 0)
return r;
diff --git a/src/systemd-cryptsetup/cryptsetup.c b/src/systemd-cryptsetup/cryptsetup.c
index 9d8156697d..8024f80e36 100644
--- a/src/systemd-cryptsetup/cryptsetup.c
+++ b/src/systemd-cryptsetup/cryptsetup.c
@@ -719,8 +719,12 @@ int main(int argc, char *argv[]) {
int k;
k = crypt_init_by_name(&cd, argv[2]);
- if (k) {
- log_error_errno(k, "crypt_init() failed: %m");
+ if (k == -ENODEV) {
+ log_info("Volume %s already inactive.", argv[2]);
+ r = EXIT_SUCCESS;
+ goto finish;
+ } else if (k) {
+ log_error_errno(k, "crypt_init_by_name() failed: %m");
goto finish;
}
diff --git a/src/systemd-delta/delta.c b/src/systemd-delta/delta.c
index a54fc89de6..f32744def2 100644
--- a/src/systemd-delta/delta.c
+++ b/src/systemd-delta/delta.c
@@ -85,14 +85,6 @@ static enum {
(SHOW_MASKED | SHOW_EQUIVALENT | SHOW_REDIRECTED | SHOW_OVERRIDDEN | SHOW_EXTENDED)
} arg_flags = 0;
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager)
- return;
-
- pager_open(false);
-}
-
static int equivalent(const char *a, const char *b) {
_cleanup_free_ char *x = NULL, *y = NULL;
@@ -113,7 +105,7 @@ static int notify_override_masked(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight_red(), "[MASKED]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -123,7 +115,7 @@ static int notify_override_equivalent(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight_green(), "[EQUIVALENT]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -133,7 +125,7 @@ static int notify_override_redirected(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight(), "[REDIRECTED]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -143,7 +135,7 @@ static int notify_override_overridden(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight(), "[OVERRIDDEN]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -153,7 +145,7 @@ static int notify_override_extended(const char *top, const char *bottom) {
printf("%s%s%s %s %s %s\n",
ansi_highlight(), "[EXTENDED]", ansi_normal(),
- top, draw_special_char(DRAW_ARROW), bottom);
+ top, special_glyph(ARROW), bottom);
return 1;
}
@@ -255,7 +247,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
return -ENOMEM;
d = p + strlen(toppath) + 1;
- log_debug("Adding at top: %s %s %s", d, draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at top: %s %s %s", d, special_glyph(ARROW), p);
k = hashmap_put(top, d, p);
if (k >= 0) {
p = strdup(p);
@@ -267,7 +259,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
return k;
}
- log_debug("Adding at bottom: %s %s %s", d, draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at bottom: %s %s %s", d, special_glyph(ARROW), p);
free(hashmap_remove(bottom, d));
k = hashmap_put(bottom, d, p);
if (k < 0) {
@@ -291,7 +283,7 @@ static int enumerate_dir_d(Hashmap *top, Hashmap *bottom, Hashmap *drops, const
return -ENOMEM;
log_debug("Adding to drops: %s %s %s %s %s",
- unit, draw_special_char(DRAW_ARROW), basename(p), draw_special_char(DRAW_ARROW), p);
+ unit, special_glyph(ARROW), basename(p), special_glyph(ARROW), p);
k = hashmap_put(h, basename(p), p);
if (k < 0) {
free(p);
@@ -342,7 +334,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
if (!p)
return -ENOMEM;
- log_debug("Adding at top: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at top: %s %s %s", basename(p), special_glyph(ARROW), p);
k = hashmap_put(top, basename(p), p);
if (k >= 0) {
p = strdup(p);
@@ -353,7 +345,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch
return k;
}
- log_debug("Adding at bottom: %s %s %s", basename(p), draw_special_char(DRAW_ARROW), p);
+ log_debug("Adding at bottom: %s %s %s", basename(p), special_glyph(ARROW), p);
free(hashmap_remove(bottom, basename(p)));
k = hashmap_put(bottom, basename(p), p);
if (k < 0) {
@@ -431,7 +423,7 @@ finish:
hashmap_free_free(top);
hashmap_free_free(bottom);
- HASHMAP_FOREACH_KEY(h, key, drops, i){
+ HASHMAP_FOREACH_KEY(h, key, drops, i) {
hashmap_free_free(hashmap_remove(drops, key));
hashmap_remove(drops, key);
free(key);
@@ -610,7 +602,7 @@ int main(int argc, char *argv[]) {
else if (arg_diff)
arg_flags |= SHOW_OVERRIDDEN;
- pager_open_if_enabled();
+ pager_open(arg_no_pager, false);
if (optind < argc) {
int i;
diff --git a/src/systemd-firstboot/firstboot.c b/src/systemd-firstboot/firstboot.c
index 8e57a24a70..1e1a592b7c 100644
--- a/src/systemd-firstboot/firstboot.c
+++ b/src/systemd-firstboot/firstboot.c
@@ -160,7 +160,7 @@ static int prompt_loop(const char *text, char **l, bool (*is_valid)(const char *
_cleanup_free_ char *p = NULL;
unsigned u;
- r = ask_string(&p, "%s %s (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET), text);
+ r = ask_string(&p, "%s %s (empty to skip): ", special_glyph(TRIANGULAR_BULLET), text);
if (r < 0)
return log_error_errno(r, "Failed to query user: %m");
@@ -245,7 +245,7 @@ static int process_locale(void) {
int r;
etc_localeconf = prefix_roota(arg_root, "/etc/locale.conf");
- if (faccessat(AT_FDCWD, etc_localeconf, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ if (laccess(etc_localeconf, F_OK) >= 0)
return 0;
if (arg_copy_locale && arg_root) {
@@ -319,7 +319,7 @@ static int process_timezone(void) {
int r;
etc_localtime = prefix_roota(arg_root, "/etc/localtime");
- if (faccessat(AT_FDCWD, etc_localtime, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ if (laccess(etc_localtime, F_OK) >= 0)
return 0;
if (arg_copy_timezone && arg_root) {
@@ -371,7 +371,7 @@ static int prompt_hostname(void) {
for (;;) {
_cleanup_free_ char *h = NULL;
- r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", draw_special_char(DRAW_TRIANGULAR_BULLET));
+ r = ask_string(&h, "%s Please enter hostname for new system (empty to skip): ", special_glyph(TRIANGULAR_BULLET));
if (r < 0)
return log_error_errno(r, "Failed to query hostname: %m");
@@ -399,7 +399,7 @@ static int process_hostname(void) {
int r;
etc_hostname = prefix_roota(arg_root, "/etc/hostname");
- if (faccessat(AT_FDCWD, etc_hostname, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ if (laccess(etc_hostname, F_OK) >= 0)
return 0;
r = prompt_hostname();
@@ -424,7 +424,7 @@ static int process_machine_id(void) {
int r;
etc_machine_id = prefix_roota(arg_root, "/etc/machine-id");
- if (faccessat(AT_FDCWD, etc_machine_id, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ if (laccess(etc_machine_id, F_OK) >= 0)
return 0;
if (sd_id128_equal(arg_machine_id, SD_ID128_NULL))
@@ -450,14 +450,14 @@ static int prompt_root_password(void) {
return 0;
etc_shadow = prefix_roota(arg_root, "/etc/shadow");
- if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ if (laccess(etc_shadow, F_OK) >= 0)
return 0;
print_welcome();
putchar('\n');
- msg1 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): ");
- msg2 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: ");
+ msg1 = strjoina(special_glyph(TRIANGULAR_BULLET), " Please enter a new root password (empty to skip): ");
+ msg2 = strjoina(special_glyph(TRIANGULAR_BULLET), " Please enter new root password again: ");
for (;;) {
_cleanup_string_free_erase_ char *a = NULL, *b = NULL;
@@ -533,7 +533,7 @@ static int process_root_password(void) {
int r;
etc_shadow = prefix_roota(arg_root, "/etc/shadow");
- if (faccessat(AT_FDCWD, etc_shadow, F_OK, AT_SYMLINK_NOFOLLOW) >= 0)
+ if (laccess(etc_shadow, F_OK) >= 0)
return 0;
mkdir_parents(etc_shadow, 0755);
diff --git a/src/systemd-fsck/fsck.c b/src/systemd-fsck/fsck.c
index f21433c0ad..d7f0829ffc 100644
--- a/src/systemd-fsck/fsck.c
+++ b/src/systemd-fsck/fsck.c
@@ -262,7 +262,7 @@ static int fsck_progress_socket(void) {
if (fd < 0)
return log_warning_errno(errno, "socket(): %m");
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
+ if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
r = log_full_errno(errno == ECONNREFUSED || errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
errno, "Failed to connect to progress socket %s, ignoring: %m", sa.un.sun_path);
safe_close(fd);
diff --git a/src/systemd-fstab-generator/fstab-generator.c b/src/systemd-fstab-generator/fstab-generator.c
index 97a48764ae..108522873e 100644
--- a/src/systemd-fstab-generator/fstab-generator.c
+++ b/src/systemd-fstab-generator/fstab-generator.c
@@ -336,8 +336,8 @@ static int add_mount(
if (r < 0)
return log_error_errno(r, "Failed to write unit file %s: %m", unit);
- if (!noauto) {
- lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL);
+ if (!noauto && !automount) {
+ lnk = strjoin(arg_dest, "/", post, nofail ? ".wants/" : ".requires/", name, NULL);
if (!lnk)
return log_oom();
@@ -379,6 +379,7 @@ static int add_mount(
}
fprintf(f,
+ "\n"
"[Automount]\n"
"Where=%s\n",
where);
@@ -488,6 +489,7 @@ static int parse_fstab(bool initrd) {
static int add_sysroot_mount(void) {
_cleanup_free_ char *what = NULL;
const char *opts;
+ int r;
if (isempty(arg_root_what)) {
log_debug("Could not find a root= entry on the kernel command line.");
@@ -507,6 +509,13 @@ static int add_sysroot_mount(void) {
opts = arg_root_options;
log_debug("Found entry what=%s where=/sysroot type=%s", what, strna(arg_root_fstype));
+
+ if (is_device_path(what)) {
+ r = generator_write_initrd_root_device_deps(arg_dest, what);
+ if (r < 0)
+ return r;
+ }
+
return add_mount(what,
"/sysroot",
arg_root_fstype,
diff --git a/src/systemd-gpt-auto-generator/gpt-auto-generator.c b/src/systemd-gpt-auto-generator/gpt-auto-generator.c
index a8149b8756..73e32da751 100644
--- a/src/systemd-gpt-auto-generator/gpt-auto-generator.c
+++ b/src/systemd-gpt-auto-generator/gpt-auto-generator.c
@@ -956,6 +956,12 @@ static int add_root_mount(void) {
* wait for a root device to show up. A udev rule will create
* the link for us under the right name. */
+ if (in_initrd()) {
+ r = generator_write_initrd_root_device_deps(arg_dest, "/dev/gpt-auto-root");
+ if (r < 0)
+ return 0;
+ }
+
return add_mount(
"root",
"/dev/gpt-auto-root",
diff --git a/src/systemd-nspawn/Makefile b/src/systemd-nspawn/Makefile
index b276bd6ceb..e66a68c898 100644
--- a/src/systemd-nspawn/Makefile
+++ b/src/systemd-nspawn/Makefile
@@ -41,10 +41,14 @@ systemd_nspawn_SOURCES = \
src/nspawn/nspawn-setuid.h \
src/nspawn/nspawn-stub-pid1.c \
src/nspawn/nspawn-stub-pid1.h \
+ src/nspawn/nspawn-patch-uid.c \
+ src/nspawn/nspawn-patch-uid.h \
src/core/mount-setup.c \
src/core/mount-setup.h \
src/core/loopback-setup.c \
- src/core/loopback-setup.h
+ src/core/loopback-setup.h \
+ src/core/machine-id-setup.c \
+ src/core/machine-id-setup.h
nodist_systemd_nspawn_SOURCES = \
src/nspawn/nspawn-gperf.c
@@ -66,4 +70,15 @@ systemd_nspawn_LDADD += \
libfirewall.la
endif # HAVE_LIBIPTC
+test_patch_uid_SOURCES = \
+ src/nspawn/nspawn-patch-uid.c \
+ src/nspawn/nspawn-patch-uid.h \
+ src/nspawn/test-patch-uid.c
+
+test_patch_uid_LDADD = \
+ libshared.la
+
+manual_tests += \
+ test-patch-uid
+
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/systemd-nspawn/nspawn-cgroup.c b/src/systemd-nspawn/nspawn-cgroup.c
index 1db5ba7116..f50f1ad6c2 100644
--- a/src/systemd-nspawn/nspawn-cgroup.c
+++ b/src/systemd-nspawn/nspawn-cgroup.c
@@ -55,8 +55,7 @@ int chown_cgroup(pid_t pid, uid_t uid_shift) {
"cgroup.events",
"cgroup.clone_children",
"cgroup.controllers",
- "cgroup.subtree_control",
- "cgroup.populated")
+ "cgroup.subtree_control")
if (fchownat(fd, fn, uid_shift, uid_shift, 0) < 0)
log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
"Failed to chown() cgroup file %s, ignoring: %m", fn);
@@ -73,7 +72,7 @@ int sync_cgroup(pid_t pid, bool unified_requested) {
unified = cg_unified();
if (unified < 0)
- return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m");
+ return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m");
if ((unified > 0) == unified_requested)
return 0;
@@ -94,7 +93,7 @@ int sync_cgroup(pid_t pid, bool unified_requested) {
if (unified)
r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "none,name=systemd,xattr");
else
- r = mount("cgroup", tree, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "__DEVEL__sane_behavior");
+ r = mount("cgroup", tree, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
if (r < 0) {
r = log_error_errno(errno, "Failed to mount unified hierarchy: %m");
goto finish;
@@ -135,7 +134,7 @@ int create_subcgroup(pid_t pid, bool unified_requested) {
unified = cg_unified();
if (unified < 0)
- return log_error_errno(unified, "Failed to determine whether the unified hierachy is used: %m");
+ return log_error_errno(unified, "Failed to determine whether the unified hierarchy is used: %m");
if (unified == 0)
return 0;
diff --git a/src/systemd-nspawn/nspawn-gperf.gperf b/src/systemd-nspawn/nspawn-gperf.gperf
index 116655cdd2..2b5d452662 100644
--- a/src/systemd-nspawn/nspawn-gperf.gperf
+++ b/src/systemd-nspawn/nspawn-gperf.gperf
@@ -16,7 +16,7 @@ struct ConfigPerfItem;
%includes
%%
Exec.Boot, config_parse_boot, 0, 0
-Exec.ProcessTwo, config_parse_pid2, 0, 0,
+Exec.ProcessTwo, config_parse_pid2, 0, 0
Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters)
Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment)
Exec.User, config_parse_string, 0, offsetof(Settings, user)
@@ -26,16 +26,19 @@ Exec.KillSignal, config_parse_signal, 0, offsetof(Settings,
Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality)
Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id)
Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory)
+Exec.PrivateUsers, config_parse_private_users, 0, 0
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
Files.Bind, config_parse_bind, 0, 0
Files.BindReadOnly, config_parse_bind, 1, 0
Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0
+Files.PrivateUsersChown, config_parse_tristate, 0, offsetof(Settings, userns_chown)
Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network)
Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces)
Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan)
Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan)
Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth)
Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0
-Network.Bridge, config_parse_string, 0, offsetof(Settings, network_bridge)
+Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge)
+Network.Zone, config_parse_network_zone, 0, 0
Network.Port, config_parse_expose_port, 0, 0
diff --git a/src/systemd-nspawn/nspawn-mount.c b/src/systemd-nspawn/nspawn-mount.c
index 70cca15278..8e2d2d543c 100644
--- a/src/systemd-nspawn/nspawn-mount.c
+++ b/src/systemd-nspawn/nspawn-mount.c
@@ -438,21 +438,22 @@ static int mount_bind(const char *dest, CustomMount *m) {
r = mkdir_parents_label(where, 0755);
if (r < 0)
return log_error_errno(r, "Failed to make parents of %s: %m", where);
+
+ /* Create the mount point. Any non-directory file can be
+ * mounted on any non-directory file (regular, fifo, socket,
+ * char, block).
+ */
+ if (S_ISDIR(source_st.st_mode))
+ r = mkdir_label(where, 0755);
+ else
+ r = touch(where);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create mount point %s: %m", where);
+
} else {
return log_error_errno(errno, "Failed to stat %s: %m", where);
}
- /* Create the mount point. Any non-directory file can be
- * mounted on any non-directory file (regular, fifo, socket,
- * char, block).
- */
- if (S_ISDIR(source_st.st_mode))
- r = mkdir_label(where, 0755);
- else
- r = touch(where);
- if (r < 0 && r != -EEXIST)
- return log_error_errno(r, "Failed to create mount point %s: %m", where);
-
if (mount(m->source, where, NULL, mount_flags, mount_opts) < 0)
return log_error_errno(errno, "mount(%s) failed: %m", where);
@@ -750,7 +751,7 @@ static int mount_unified_cgroups(const char *dest) {
return -EINVAL;
}
- if (mount("cgroup", p, "cgroup", MS_NOSUID|MS_NOEXEC|MS_NODEV, "__DEVEL__sane_behavior") < 0)
+ if (mount("cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0)
return log_error_errno(errno, "Failed to mount unified cgroup hierarchy to %s: %m", p);
return 0;
diff --git a/src/systemd-nspawn/nspawn-network.c b/src/systemd-nspawn/nspawn-network.c
index d03fd001a7..7052fb5804 100644
--- a/src/systemd-nspawn/nspawn-network.c
+++ b/src/systemd-nspawn/nspawn-network.c
@@ -26,9 +26,12 @@
#include "alloc-util.h"
#include "ether-addr-util.h"
+#include "lockfile-util.h"
#include "netlink-util.h"
#include "nspawn-network.h"
#include "siphash24.h"
+#include "socket-util.h"
+#include "stat-util.h"
#include "string-util.h"
#include "udev-util.h"
#include "util.h"
@@ -39,6 +42,30 @@
#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
+static int remove_one_link(sd_netlink *rtnl, const char *name) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ if (isempty(name))
+ return 0;
+
+ r = sd_rtnl_message_new_link(rtnl, &m, RTM_DELLINK, 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate netlink message: %m");
+
+ r = sd_netlink_message_append_string(m, IFLA_IFNAME, name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add netlink interface name: %m");
+
+ r = sd_netlink_call(rtnl, m, 0, NULL);
+ if (r == -ENODEV) /* Already gone */
+ return 0;
+ if (r < 0)
+ return log_error_errno(r, "Failed to remove interface %s: %m", name);
+
+ return 1;
+}
+
static int generate_mac(
const char *machine_name,
struct ether_addr *mac,
@@ -232,51 +259,155 @@ int setup_veth_extra(
if (r < 0)
return r;
- idx ++;
+ idx++;
}
return 0;
}
-int setup_bridge(const char *veth_name, const char *bridge_name) {
+static int join_bridge(sd_netlink *rtnl, const char *veth_name, const char *bridge_name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
int r, bridge_ifi;
+ assert(rtnl);
assert(veth_name);
assert(bridge_name);
bridge_ifi = (int) if_nametoindex(bridge_name);
if (bridge_ifi <= 0)
- return log_error_errno(errno, "Failed to resolve interface %s: %m", bridge_name);
-
- r = sd_netlink_open(&rtnl);
- if (r < 0)
- return log_error_errno(r, "Failed to connect to netlink: %m");
+ return -errno;
r = sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, 0);
if (r < 0)
- return log_error_errno(r, "Failed to allocate netlink message: %m");
+ return r;
r = sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP);
if (r < 0)
- return log_error_errno(r, "Failed to set IFF_UP flag: %m");
+ return r;
r = sd_netlink_message_append_string(m, IFLA_IFNAME, veth_name);
if (r < 0)
- return log_error_errno(r, "Failed to add netlink interface name field: %m");
+ return r;
r = sd_netlink_message_append_u32(m, IFLA_MASTER, bridge_ifi);
if (r < 0)
- return log_error_errno(r, "Failed to add netlink master field: %m");
+ return r;
r = sd_netlink_call(rtnl, m, 0, NULL);
if (r < 0)
- return log_error_errno(r, "Failed to add veth interface to bridge: %m");
+ return r;
return bridge_ifi;
}
+static int create_bridge(sd_netlink *rtnl, const char *bridge_name) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+ int r;
+
+ r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(m, IFLA_IFNAME, bridge_name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "bridge");
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(rtnl, m, 0, NULL);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+int setup_bridge(const char *veth_name, const char *bridge_name, bool create) {
+ _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ int r, bridge_ifi;
+ unsigned n = 0;
+
+ assert(veth_name);
+ assert(bridge_name);
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
+
+ if (create) {
+ /* We take a system-wide lock here, so that we can safely check whether there's still a member in the
+ * bridge before removing it, without risking interferance from other nspawn instances. */
+
+ r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
+ if (r < 0)
+ return log_error_errno(r, "Failed to take network zone lock: %m");
+ }
+
+ for (;;) {
+ bridge_ifi = join_bridge(rtnl, veth_name, bridge_name);
+ if (bridge_ifi >= 0)
+ return bridge_ifi;
+ if (bridge_ifi != -ENODEV || !create || n > 10)
+ return log_error_errno(bridge_ifi, "Failed to add interface %s to bridge %s: %m", veth_name, bridge_name);
+
+ /* Count attempts, so that we don't enter an endless loop here. */
+ n++;
+
+ /* The bridge doesn't exist yet. Let's create it */
+ r = create_bridge(rtnl, bridge_name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bridge interface %s: %m", bridge_name);
+
+ /* Try again, now that the bridge exists */
+ }
+}
+
+int remove_bridge(const char *bridge_name) {
+ _cleanup_release_lock_file_ LockFile bridge_lock = LOCK_FILE_INIT;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ const char *path;
+ int r;
+
+ /* Removes the specified bridge, but only if it is currently empty */
+
+ if (isempty(bridge_name))
+ return 0;
+
+ r = make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX, &bridge_lock);
+ if (r < 0)
+ return log_error_errno(r, "Failed to take network zone lock: %m");
+
+ path = strjoina("/sys/class/net/", bridge_name, "/brif");
+
+ r = dir_is_empty(path);
+ if (r == -ENOENT) /* Already gone? */
+ return 0;
+ if (r < 0)
+ return log_error_errno(r, "Can't detect if bridge %s is empty: %m", bridge_name);
+ if (r == 0) /* Still populated, leave it around */
+ return 0;
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
+
+ return remove_one_link(rtnl, bridge_name);
+}
+
static int parse_interface(struct udev *udev, const char *name) {
_cleanup_udev_device_unref_ struct udev_device *d = NULL;
char ifi_str[2 + DECIMAL_STR_MAX(int)];
@@ -515,13 +646,13 @@ int veth_extra_parse(char ***l, const char *p) {
r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
- if (r == 0 || isempty(a))
+ if (r == 0 || !ifname_valid(a))
return -EINVAL;
r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return r;
- if (r == 0 || isempty(b)) {
+ if (r == 0 || !ifname_valid(b)) {
free(b);
b = strdup(a);
if (!b)
@@ -538,3 +669,26 @@ int veth_extra_parse(char ***l, const char *p) {
a = b = NULL;
return 0;
}
+
+int remove_veth_links(const char *primary, char **pairs) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ char **a, **b;
+ int r;
+
+ /* In some cases the kernel might pin the veth links between host and container even after the namespace
+ * died. Hence, let's better remove them explicitly too. */
+
+ if (isempty(primary) && strv_isempty(pairs))
+ return 0;
+
+ r = sd_netlink_open(&rtnl);
+ if (r < 0)
+ return log_error_errno(r, "Failed to connect to netlink: %m");
+
+ remove_one_link(rtnl, primary);
+
+ STRV_FOREACH_PAIR(a, b, pairs)
+ remove_one_link(rtnl, *a);
+
+ return 0;
+}
diff --git a/src/systemd-nspawn/nspawn-network.h b/src/systemd-nspawn/nspawn-network.h
index 9ab1606d1c..3d8861e1e5 100644
--- a/src/systemd-nspawn/nspawn-network.h
+++ b/src/systemd-nspawn/nspawn-network.h
@@ -26,7 +26,8 @@
int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge);
int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
-int setup_bridge(const char *veth_name, const char *bridge_name);
+int setup_bridge(const char *veth_name, const char *bridge_name, bool create);
+int remove_bridge(const char *bridge_name);
int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces);
int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces);
@@ -34,3 +35,5 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces);
int move_network_interfaces(pid_t pid, char **ifaces);
int veth_extra_parse(char ***l, const char *p);
+
+int remove_veth_links(const char *primary, char **pairs);
diff --git a/src/systemd-nspawn/nspawn-patch-uid.c b/src/systemd-nspawn/nspawn-patch-uid.c
new file mode 100644
index 0000000000..c7382d412d
--- /dev/null
+++ b/src/systemd-nspawn/nspawn-patch-uid.c
@@ -0,0 +1,469 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <fcntl.h>
+#include <linux/magic.h>
+#ifdef HAVE_ACL
+#include <sys/acl.h>
+#endif
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+
+#include "acl-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "missing.h"
+#include "nspawn-patch-uid.h"
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+
+#ifdef HAVE_ACL
+
+static int get_acl(int fd, const char *name, acl_type_t type, acl_t *ret) {
+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+ acl_t acl;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ if (name) {
+ _cleanup_close_ int child_fd = -1;
+
+ child_fd = openat(fd, name, O_PATH|O_CLOEXEC|O_NOFOLLOW);
+ if (child_fd < 0)
+ return -errno;
+
+ xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
+ acl = acl_get_file(procfs_path, type);
+ } else if (type == ACL_TYPE_ACCESS)
+ acl = acl_get_fd(fd);
+ else {
+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+ acl = acl_get_file(procfs_path, type);
+ }
+ if (!acl)
+ return -errno;
+
+ *ret = acl;
+ return 0;
+}
+
+static int set_acl(int fd, const char *name, acl_type_t type, acl_t acl) {
+ char procfs_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
+ int r;
+
+ assert(fd >= 0);
+ assert(acl);
+
+ if (name) {
+ _cleanup_close_ int child_fd = -1;
+
+ child_fd = openat(fd, name, O_PATH|O_CLOEXEC|O_NOFOLLOW);
+ if (child_fd < 0)
+ return -errno;
+
+ xsprintf(procfs_path, "/proc/self/fd/%i", child_fd);
+ r = acl_set_file(procfs_path, type, acl);
+ } else if (type == ACL_TYPE_ACCESS)
+ r = acl_set_fd(fd, acl);
+ else {
+ xsprintf(procfs_path, "/proc/self/fd/%i", fd);
+ r = acl_set_file(procfs_path, type, acl);
+ }
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int shift_acl(acl_t acl, uid_t shift, acl_t *ret) {
+ _cleanup_(acl_freep) acl_t copy = NULL;
+ acl_entry_t i;
+ int r;
+
+ assert(acl);
+ assert(ret);
+
+ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+ if (r < 0)
+ return -errno;
+ while (r > 0) {
+ uid_t *old_uid, new_uid;
+ bool modify = false;
+ acl_tag_t tag;
+
+ if (acl_get_tag_type(i, &tag) < 0)
+ return -errno;
+
+ if (IN_SET(tag, ACL_USER, ACL_GROUP)) {
+
+ /* We don't distuingish here between uid_t and gid_t, let's make sure the compiler checks that
+ * this is actually OK */
+ assert_cc(sizeof(uid_t) == sizeof(gid_t));
+
+ old_uid = acl_get_qualifier(i);
+ if (!old_uid)
+ return -errno;
+
+ new_uid = shift | (*old_uid & UINT32_C(0xFFFF));
+ if (!uid_is_valid(new_uid))
+ return -EINVAL;
+
+ modify = new_uid != *old_uid;
+ if (modify && !copy) {
+ int n;
+
+ /* There's no copy of the ACL yet? if so, let's create one, and start the loop from the
+ * beginning, so that we copy all entries, starting from the first, this time. */
+
+ n = acl_entries(acl);
+ if (n < 0)
+ return -errno;
+
+ copy = acl_init(n);
+ if (!copy)
+ return -errno;
+
+ /* Seek back to the beginning */
+ r = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+ if (r < 0)
+ return -errno;
+ continue;
+ }
+ }
+
+ if (copy) {
+ acl_entry_t new_entry;
+
+ if (acl_create_entry(&copy, &new_entry) < 0)
+ return -errno;
+
+ if (acl_copy_entry(new_entry, i) < 0)
+ return -errno;
+
+ if (modify)
+ if (acl_set_qualifier(new_entry, &new_uid) < 0)
+ return -errno;
+ }
+
+ r = acl_get_entry(acl, ACL_NEXT_ENTRY, &i);
+ if (r < 0)
+ return -errno;
+ }
+
+ *ret = copy;
+ copy = NULL;
+
+ return !!*ret;
+}
+
+static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shift) {
+ _cleanup_(acl_freep) acl_t acl = NULL, shifted = NULL;
+ bool changed = false;
+ int r;
+
+ assert(fd >= 0);
+ assert(st);
+
+ /* ACLs are not supported on symlinks, there's no point in trying */
+ if (S_ISLNK(st->st_mode))
+ return 0;
+
+ r = get_acl(fd, name, ACL_TYPE_ACCESS, &acl);
+ if (r == -EOPNOTSUPP)
+ return 0;
+ if (r < 0)
+ return r;
+
+ r = shift_acl(acl, shift, &shifted);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ r = set_acl(fd, name, ACL_TYPE_ACCESS, shifted);
+ if (r < 0)
+ return r;
+
+ changed = true;
+ }
+
+ if (S_ISDIR(st->st_mode)) {
+ acl_free(acl);
+ acl_free(shifted);
+
+ acl = shifted = NULL;
+
+ r = get_acl(fd, name, ACL_TYPE_DEFAULT, &acl);
+ if (r < 0)
+ return r;
+
+ r = shift_acl(acl, shift, &shifted);
+ if (r < 0)
+ return r;
+ if (r > 0) {
+ r = set_acl(fd, name, ACL_TYPE_DEFAULT, shifted);
+ if (r < 0)
+ return r;
+
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+#else
+
+static int patch_acls(int fd, const char *name, const struct stat *st, uid_t shift) {
+ return 0;
+}
+
+#endif
+
+static int patch_fd(int fd, const char *name, const struct stat *st, uid_t shift) {
+ uid_t new_uid;
+ gid_t new_gid;
+ bool changed = false;
+ int r;
+
+ assert(fd >= 0);
+ assert(st);
+
+ new_uid = shift | (st->st_uid & UINT32_C(0xFFFF));
+ new_gid = (gid_t) shift | (st->st_gid & UINT32_C(0xFFFF));
+
+ if (!uid_is_valid(new_uid) || !gid_is_valid(new_gid))
+ return -EINVAL;
+
+ if (st->st_uid != new_uid || st->st_gid != new_gid) {
+ if (name)
+ r = fchownat(fd, name, new_uid, new_gid, AT_SYMLINK_NOFOLLOW);
+ else
+ r = fchown(fd, new_uid, new_gid);
+ if (r < 0)
+ return -errno;
+
+ /* The Linux kernel alters the mode in some cases of chown(). Let's undo this. */
+ if (name && !S_ISLNK(st->st_mode))
+ r = fchmodat(fd, name, st->st_mode, 0);
+ else
+ r = fchmod(fd, st->st_mode);
+ if (r < 0)
+ return -errno;
+
+ changed = true;
+ }
+
+ r = patch_acls(fd, name, st, shift);
+ if (r < 0)
+ return r;
+
+ return r > 0 || changed;
+}
+
+static int is_procfs_sysfs_or_suchlike(int fd) {
+ struct statfs sfs;
+
+ assert(fd >= 0);
+
+ if (fstatfs(fd, &sfs) < 0)
+ return -errno;
+
+ return F_TYPE_EQUAL(sfs.f_type, BINFMTFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, CGROUP_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, CGROUP2_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, DEBUGFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, DEVPTS_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, EFIVARFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, HUGETLBFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, MQUEUE_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, PROC_SUPER_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, PSTOREFS_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, SELINUX_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, SMACK_MAGIC) ||
+ F_TYPE_EQUAL(sfs.f_type, SYSFS_MAGIC);
+}
+
+static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift, bool is_toplevel) {
+ bool changed = false;
+ int r;
+
+ assert(fd >= 0);
+
+ /* We generally want to permit crossing of mount boundaries when patching the UIDs/GIDs. However, we
+ * probably shouldn't do this for /proc and /sys if that is already mounted into place. Hence, let's
+ * stop the recursion when we hit a procfs or sysfs file system. */
+ r = is_procfs_sysfs_or_suchlike(fd);
+ if (r < 0)
+ goto finish;
+ if (r > 0) {
+ r = 0; /* don't recurse */
+ goto finish;
+ }
+
+ r = patch_fd(fd, NULL, st, shift);
+ if (r == -EROFS) {
+ _cleanup_free_ char *name = NULL;
+
+ if (!is_toplevel) {
+ /* When we hit a ready-only subtree we simply skip it, but log about it. */
+ (void) fd_get_path(fd, &name);
+ log_debug("Skippping read-only file or directory %s.", strna(name));
+ r = 0;
+ }
+
+ goto finish;
+ }
+ if (r < 0)
+ goto finish;
+
+ if (S_ISDIR(st->st_mode)) {
+ _cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
+
+ if (!donate_fd) {
+ int copy;
+
+ copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (copy < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ fd = copy;
+ donate_fd = true;
+ }
+
+ d = fdopendir(fd);
+ if (!d) {
+ r = -errno;
+ goto finish;
+ }
+ fd = -1;
+
+ FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {
+ struct stat fst;
+
+ if (STR_IN_SET(de->d_name, ".", ".."))
+ continue;
+
+ if (fstatat(dirfd(d), de->d_name, &fst, AT_SYMLINK_NOFOLLOW) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (S_ISDIR(fst.st_mode)) {
+ int subdir_fd;
+
+ subdir_fd = openat(dirfd(d), de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (subdir_fd < 0) {
+ r = -errno;
+ goto finish;
+
+ }
+
+ r = recurse_fd(subdir_fd, true, &fst, shift, false);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ changed = true;
+
+ } else {
+ r = patch_fd(dirfd(d), de->d_name, &fst, shift);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ changed = true;
+ }
+ }
+ }
+
+ r = changed;
+
+finish:
+ if (donate_fd)
+ safe_close(fd);
+
+ return r;
+}
+
+static int fd_patch_uid_internal(int fd, bool donate_fd, uid_t shift, uid_t range) {
+ struct stat st;
+ int r;
+
+ assert(fd >= 0);
+
+ /* Recursively adjusts the UID/GIDs of all files of a directory tree. This is used to automatically fix up an
+ * OS tree to the used user namespace UID range. Note that this automatic adjustment only works for UID ranges
+ * following the concept that the upper 16bit of a UID identify the container, and the lower 16bit are the actual
+ * UID within the container. */
+
+ if ((shift & 0xFFFF) != 0) {
+ /* We only support containers where the shift starts at a 2^16 boundary */
+ r = -EOPNOTSUPP;
+ goto finish;
+ }
+
+ if (range != 0x10000) {
+ /* We only support containers with 16bit UID ranges for the patching logic */
+ r = -EOPNOTSUPP;
+ goto finish;
+ }
+
+ if (fstat(fd, &st) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if ((uint32_t) st.st_uid >> 16 != (uint32_t) st.st_gid >> 16) {
+ /* We only support containers where the uid/gid container ID match */
+ r = -EBADE;
+ goto finish;
+ }
+
+ /* Try to detect if the range is already right. Of course, this a pretty drastic optimization, as we assume
+ * that if the top-level dir has the right upper 16bit assigned, then everything below will have too... */
+ if (((uint32_t) (st.st_uid ^ shift) >> 16) == 0)
+ return 0;
+
+ return recurse_fd(fd, donate_fd, &st, shift, true);
+
+finish:
+ if (donate_fd)
+ safe_close(fd);
+
+ return r;
+}
+
+int fd_patch_uid(int fd, uid_t shift, uid_t range) {
+ return fd_patch_uid_internal(fd, false, shift, range);
+}
+
+int path_patch_uid(const char *path, uid_t shift, uid_t range) {
+ int fd;
+
+ fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME);
+ if (fd < 0)
+ return -errno;
+
+ return fd_patch_uid_internal(fd, true, shift, range);
+}
diff --git a/src/libbus-proxy-core/driver.h b/src/systemd-nspawn/nspawn-patch-uid.h
index cad7aa7851..55d0990016 100644
--- a/src/libbus-proxy-core/driver.h
+++ b/src/systemd-nspawn/nspawn-patch-uid.h
@@ -1,9 +1,7 @@
-#pragma once
-
/***
This file is part of systemd.
- Copyright 2014 Lennart Poettering
+ Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -19,9 +17,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <systemd/sd-bus.h>
-
-#include "bus-xml-policy.h"
-#include "proxy.h"
+#include <sys/types.h>
-int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, SharedPolicy *sp, const struct ucred *ucred, Set *owned_names);
+int fd_patch_uid(int fd, uid_t shift, uid_t range);
+int path_patch_uid(const char *path, uid_t shift, uid_t range);
diff --git a/src/systemd-nspawn/nspawn-register.c b/src/systemd-nspawn/nspawn-register.c
index 3b0d778f43..adef200cb5 100644
--- a/src/systemd-nspawn/nspawn-register.c
+++ b/src/systemd-nspawn/nspawn-register.c
@@ -20,6 +20,7 @@
#include <systemd/sd-bus.h>
#include "bus-error.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "nspawn-register.h"
#include "stat-util.h"
diff --git a/src/systemd-nspawn/nspawn-settings.c b/src/systemd-nspawn/nspawn-settings.c
index 4fb0054698..5f1522cfb6 100644
--- a/src/systemd-nspawn/nspawn-settings.c
+++ b/src/systemd-nspawn/nspawn-settings.c
@@ -24,7 +24,10 @@
#include "nspawn-settings.h"
#include "parse-util.h"
#include "process-util.h"
+#include "socket-util.h"
+#include "string-util.h"
#include "strv.h"
+#include "user-util.h"
#include "util.h"
int settings_load(FILE *f, const char *path, Settings **ret) {
@@ -40,9 +43,13 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
s->start_mode = _START_MODE_INVALID;
s->personality = PERSONALITY_INVALID;
+ s->userns_mode = _USER_NAMESPACE_MODE_INVALID;
+ s->uid_shift = UID_INVALID;
+ s->uid_range = UID_INVALID;
s->read_only = -1;
s->volatile_mode = _VOLATILE_MODE_INVALID;
+ s->userns_chown = -1;
s->private_network = -1;
s->network_veth = -1;
@@ -59,6 +66,16 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
if (r < 0)
return r;
+ /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
+ * both fields shall be initialized or neither. */
+ if (s->userns_mode == USER_NAMESPACE_PICK)
+ s->userns_chown = true;
+ else if (s->userns_mode != _USER_NAMESPACE_MODE_INVALID && s->userns_chown < 0)
+ s->userns_chown = false;
+
+ if (s->userns_chown >= 0 && s->userns_mode == _USER_NAMESPACE_MODE_INVALID)
+ s->userns_mode = USER_NAMESPACE_NO;
+
*ret = s;
s = NULL;
@@ -80,6 +97,7 @@ Settings* settings_free(Settings *s) {
strv_free(s->network_ipvlan);
strv_free(s->network_veth_extra);
free(s->network_bridge);
+ free(s->network_zone);
expose_port_free_all(s->expose_ports);
custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
@@ -95,6 +113,7 @@ bool settings_private_network(Settings *s) {
s->private_network > 0 ||
s->network_veth > 0 ||
s->network_bridge ||
+ s->network_zone ||
s->network_interfaces ||
s->network_macvlan ||
s->network_ipvlan ||
@@ -106,7 +125,8 @@ bool settings_network_veth(Settings *s) {
return
s->network_veth > 0 ||
- s->network_bridge;
+ s->network_bridge ||
+ s->network_zone;
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
@@ -303,6 +323,38 @@ int config_parse_veth_extra(
return 0;
}
+int config_parse_network_zone(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Settings *settings = data;
+ _cleanup_free_ char *j = NULL;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ j = strappend("vz-", rvalue);
+ if (!ifname_valid(j)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid network zone name %s, ignoring: %m", rvalue);
+ return 0;
+ }
+
+ free(settings->network_zone);
+ settings->network_zone = j;
+ j = NULL;
+
+ return 0;
+}
+
int config_parse_boot(
const char *unit,
const char *filename,
@@ -392,3 +444,73 @@ conflict:
log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
return 0;
}
+
+int config_parse_private_users(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Settings *settings = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ r = parse_boolean(rvalue);
+ if (r == 0) {
+ /* no: User namespacing off */
+ settings->userns_mode = USER_NAMESPACE_NO;
+ settings->uid_shift = UID_INVALID;
+ settings->uid_range = UINT32_C(0x10000);
+ } else if (r > 0) {
+ /* yes: User namespacing on, UID range is read from root dir */
+ settings->userns_mode = USER_NAMESPACE_FIXED;
+ settings->uid_shift = UID_INVALID;
+ settings->uid_range = UINT32_C(0x10000);
+ } else if (streq(rvalue, "pick")) {
+ /* pick: User namespacing on, UID range is picked randomly */
+ settings->userns_mode = USER_NAMESPACE_PICK;
+ settings->uid_shift = UID_INVALID;
+ settings->uid_range = UINT32_C(0x10000);
+ } else {
+ const char *range, *shift;
+ uid_t sh, rn;
+
+ /* anything else: User namespacing on, UID range is explicitly configured */
+
+ range = strchr(rvalue, ':');
+ if (range) {
+ shift = strndupa(rvalue, range - rvalue);
+ range++;
+
+ r = safe_atou32(range, &rn);
+ if (r < 0 || rn <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID range invalid, ignoring: %s", range);
+ return 0;
+ }
+ } else {
+ shift = rvalue;
+ rn = UINT32_C(0x10000);
+ }
+
+ r = parse_uid(shift, &sh);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "UID/GID shift invalid, ignoring: %s", range);
+ return 0;
+ }
+
+ settings->userns_mode = USER_NAMESPACE_FIXED;
+ settings->uid_shift = sh;
+ settings->uid_range = rn;
+ }
+
+ return 0;
+}
diff --git a/src/systemd-nspawn/nspawn-settings.h b/src/systemd-nspawn/nspawn-settings.h
index a017405cd9..1c47e37912 100644
--- a/src/systemd-nspawn/nspawn-settings.h
+++ b/src/systemd-nspawn/nspawn-settings.h
@@ -33,6 +33,14 @@ typedef enum StartMode {
_START_MODE_INVALID = -1
} StartMode;
+typedef enum UserNamespaceMode {
+ USER_NAMESPACE_NO,
+ USER_NAMESPACE_FIXED,
+ USER_NAMESPACE_PICK,
+ _USER_NAMESPACE_MODE_MAX,
+ _USER_NAMESPACE_MODE_INVALID = -1,
+} UserNamespaceMode;
+
typedef enum SettingsMask {
SETTING_START_MODE = 1 << 0,
SETTING_ENVIRONMENT = 1 << 1,
@@ -47,7 +55,8 @@ typedef enum SettingsMask {
SETTING_VOLATILE_MODE = 1 << 10,
SETTING_CUSTOM_MOUNTS = 1 << 11,
SETTING_WORKING_DIRECTORY = 1 << 12,
- _SETTINGS_MASK_ALL = (1 << 13) -1
+ SETTING_USERNS = 1 << 13,
+ _SETTINGS_MASK_ALL = (1 << 14) -1
} SettingsMask;
typedef struct Settings {
@@ -62,17 +71,21 @@ typedef struct Settings {
unsigned long personality;
sd_id128_t machine_id;
char *working_directory;
+ UserNamespaceMode userns_mode;
+ uid_t uid_shift, uid_range;
/* [Image] */
int read_only;
VolatileMode volatile_mode;
CustomMount *custom_mounts;
unsigned n_custom_mounts;
+ int userns_chown;
/* [Network] */
int private_network;
int network_veth;
char *network_bridge;
+ char *network_zone;
char **network_interfaces;
char **network_macvlan;
char **network_ipvlan;
@@ -97,5 +110,7 @@ int config_parse_volatile_mode(const char *unit, const char *filename, unsigned
int config_parse_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_tmpfs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_veth_extra(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_network_zone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_boot(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/systemd-nspawn/nspawn.c b/src/systemd-nspawn/nspawn.c
index add66be183..bdf054e5c6 100644
--- a/src/systemd-nspawn/nspawn.c
+++ b/src/systemd-nspawn/nspawn.c
@@ -22,7 +22,9 @@
#endif
#include <errno.h>
#include <getopt.h>
+#include <grp.h>
#include <linux/loop.h>
+#include <pwd.h>
#include <sched.h>
#ifdef HAVE_SECCOMP
#include <seccomp.h>
@@ -64,6 +66,7 @@
#include "hostname-util.h"
#include "log.h"
#include "loopback-setup.h"
+#include "machine-id-setup.h"
#include "machine-image.h"
#include "macro.h"
#include "missing.h"
@@ -74,6 +77,7 @@
#include "nspawn-expose-ports.h"
#include "nspawn-mount.h"
#include "nspawn-network.h"
+#include "nspawn-patch-uid.h"
#include "nspawn-register.h"
#include "nspawn-settings.h"
#include "nspawn-setuid.h"
@@ -87,6 +91,7 @@
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "selinux-util.h"
#include "signal-util.h"
#include "socket-util.h"
#include "stat-util.h"
@@ -99,6 +104,11 @@
#include "user-util.h"
#include "util.h"
+/* Note that devpts's gid= parameter parses GIDs as signed values, hence we stay away from the upper half of the 32bit
+ * UID range here */
+#define UID_SHIFT_PICK_MIN ((uid_t) UINT32_C(0x00080000))
+#define UID_SHIFT_PICK_MAX ((uid_t) UINT32_C(0x6FFF0000))
+
typedef enum ContainerStatus {
CONTAINER_TERMINATED,
CONTAINER_REBOOTED
@@ -166,13 +176,15 @@ static char **arg_network_ipvlan = NULL;
static bool arg_network_veth = false;
static char **arg_network_veth_extra = NULL;
static char *arg_network_bridge = NULL;
+static char *arg_network_zone = NULL;
static unsigned long arg_personality = PERSONALITY_INVALID;
static char *arg_image = NULL;
static VolatileMode arg_volatile_mode = VOLATILE_NO;
static ExposePort *arg_expose_ports = NULL;
static char **arg_property = NULL;
+static UserNamespaceMode arg_userns_mode = USER_NAMESPACE_NO;
static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U;
-static bool arg_userns = false;
+static bool arg_userns_chown = false;
static int arg_kill_signal = 0;
static bool arg_unified_cgroup_hierarchy = false;
static SettingsMask arg_settings_mask = 0;
@@ -200,8 +212,10 @@ static void help(void) {
" --uuid=UUID Set a specific machine UUID for the container\n"
" -S --slice=SLICE Place the container in the specified slice\n"
" --property=NAME=VALUE Set scope unit property\n"
+ " -U --private-users=pick Run within user namespace, pick UID/GID range automatically\n"
" --private-users[=UIDBASE[:NUIDS]]\n"
- " Run within user namespace\n"
+ " Run within user namespace, user configured UID/GID range\n"
+ " --private-user-chown Adjust OS tree file ownership for private UID/GID range\n"
" --private-network Disable network in container\n"
" --network-interface=INTERFACE\n"
" Assign an existing network interface to the\n"
@@ -221,6 +235,8 @@ static void help(void) {
" Add a virtual Ethernet connection between host\n"
" and container and add it to an existing bridge on\n"
" the host\n"
+ " --network-zone=NAME Add a virtual Ethernet connection to the container,\n"
+ " and add it to an automatically managed bridge interface\n"
" -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n"
" Expose a container IP port on the host\n"
" -Z --selinux-context=SECLABEL\n"
@@ -248,7 +264,7 @@ static void help(void) {
" the container\n"
" --overlay-ro=PATH[:PATH...]:PATH\n"
" Similar, but creates a read-only overlay mount\n"
- " --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
+ " -E --setenv=NAME=VALUE Pass an environment variable to PID 1\n"
" --share-system Share system namespaces with host\n"
" --register=BOOLEAN Register container as machine\n"
" --keep-unit Do not register a scope for the machine, reuse\n"
@@ -270,9 +286,15 @@ static int custom_mounts_prepare(void) {
for (i = 0; i < arg_n_custom_mounts; i++) {
CustomMount *m = &arg_custom_mounts[i];
- if (arg_userns && arg_uid_shift == UID_INVALID && path_equal(m->destination, "/")) {
- log_error("--private-users with automatic UID shift may not be combined with custom root mounts.");
- return -EINVAL;
+ if (path_equal(m->destination, "/") && arg_userns_mode != USER_NAMESPACE_NO) {
+
+ if (arg_userns_chown) {
+ log_error("--private-users-chown may not be combined with custom root mounts.");
+ return -EINVAL;
+ } else if (arg_uid_shift == UID_INVALID) {
+ log_error("--private-users with automatic UID shift may not be combined with custom root mounts.");
+ return -EINVAL;
+ }
}
if (m->type != CUSTOM_MOUNT_OVERLAY)
@@ -331,7 +353,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_TMPFS,
ARG_OVERLAY,
ARG_OVERLAY_RO,
- ARG_SETENV,
ARG_SHARE_SYSTEM,
ARG_REGISTER,
ARG_KEEP_UNIT,
@@ -339,6 +360,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NETWORK_MACVLAN,
ARG_NETWORK_IPVLAN,
ARG_NETWORK_BRIDGE,
+ ARG_NETWORK_ZONE,
ARG_NETWORK_VETH_EXTRA,
ARG_PERSONALITY,
ARG_VOLATILE,
@@ -348,6 +370,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_KILL_SIGNAL,
ARG_SETTINGS,
ARG_CHDIR,
+ ARG_PRIVATE_USERS_CHOWN,
};
static const struct option options[] = {
@@ -372,7 +395,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO },
{ "machine", required_argument, NULL, 'M' },
{ "slice", required_argument, NULL, 'S' },
- { "setenv", required_argument, NULL, ARG_SETENV },
+ { "setenv", required_argument, NULL, 'E' },
{ "selinux-context", required_argument, NULL, 'Z' },
{ "selinux-apifs-context", required_argument, NULL, 'L' },
{ "quiet", no_argument, NULL, 'q' },
@@ -385,12 +408,14 @@ static int parse_argv(int argc, char *argv[]) {
{ "network-veth", no_argument, NULL, 'n' },
{ "network-veth-extra", required_argument, NULL, ARG_NETWORK_VETH_EXTRA},
{ "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE },
+ { "network-zone", required_argument, NULL, ARG_NETWORK_ZONE },
{ "personality", required_argument, NULL, ARG_PERSONALITY },
{ "image", required_argument, NULL, 'i' },
{ "volatile", optional_argument, NULL, ARG_VOLATILE },
{ "port", required_argument, NULL, 'p' },
{ "property", required_argument, NULL, ARG_PROPERTY },
{ "private-users", optional_argument, NULL, ARG_PRIVATE_USERS },
+ { "private-users-chown", optional_argument, NULL, ARG_PRIVATE_USERS_CHOWN},
{ "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL },
{ "settings", required_argument, NULL, ARG_SETTINGS },
{ "chdir", required_argument, NULL, ARG_CHDIR },
@@ -405,7 +430,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:n", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nU", options, NULL)) >= 0)
switch (c) {
@@ -446,7 +471,35 @@ static int parse_argv(int argc, char *argv[]) {
arg_settings_mask |= SETTING_USER;
break;
+ case ARG_NETWORK_ZONE: {
+ char *j;
+
+ j = strappend("vz-", optarg);
+ if (!j)
+ return log_oom();
+
+ if (!ifname_valid(j)) {
+ log_error("Network zone name not valid: %s", j);
+ free(j);
+ return -EINVAL;
+ }
+
+ free(arg_network_zone);
+ arg_network_zone = j;
+
+ arg_network_veth = true;
+ arg_private_network = true;
+ arg_settings_mask |= SETTING_NETWORK;
+ break;
+ }
+
case ARG_NETWORK_BRIDGE:
+
+ if (!ifname_valid(optarg)) {
+ log_error("Bridge interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
r = free_and_strdup(&arg_network_bridge, optarg);
if (r < 0)
return log_oom();
@@ -469,6 +522,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_INTERFACE:
+
+ if (!ifname_valid(optarg)) {
+ log_error("Network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_interfaces, optarg) < 0)
return log_oom();
@@ -477,6 +536,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_MACVLAN:
+
+ if (!ifname_valid(optarg)) {
+ log_error("MACVLAN network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_macvlan, optarg) < 0)
return log_oom();
@@ -485,6 +550,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_IPVLAN:
+
+ if (!ifname_valid(optarg)) {
+ log_error("IPVLAN network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_ipvlan, optarg) < 0)
return log_oom();
@@ -561,7 +632,7 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CAPABILITY:
case ARG_DROP_CAPABILITY: {
p = optarg;
- for(;;) {
+ for (;;) {
_cleanup_free_ char *t = NULL;
r = extract_first_word(&p, &t, ",", 0);
@@ -709,7 +780,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
- case ARG_SETENV: {
+ case 'E': {
char **n;
if (!env_assignment_is_valid(optarg)) {
@@ -796,10 +867,29 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_PRIVATE_USERS:
- if (optarg) {
+
+ r = optarg ? parse_boolean(optarg) : 1;
+ if (r == 0) {
+ /* no: User namespacing off */
+ arg_userns_mode = USER_NAMESPACE_NO;
+ arg_uid_shift = UID_INVALID;
+ arg_uid_range = UINT32_C(0x10000);
+ } else if (r > 0) {
+ /* yes: User namespacing on, UID range is read from root dir */
+ arg_userns_mode = USER_NAMESPACE_FIXED;
+ arg_uid_shift = UID_INVALID;
+ arg_uid_range = UINT32_C(0x10000);
+ } else if (streq(optarg, "pick")) {
+ /* pick: User namespacing on, UID range is picked randomly */
+ arg_userns_mode = USER_NAMESPACE_PICK;
+ arg_uid_shift = UID_INVALID;
+ arg_uid_range = UINT32_C(0x10000);
+ } else {
_cleanup_free_ char *buffer = NULL;
const char *range, *shift;
+ /* anything else: User namespacing on, UID range is explicitly configured */
+
range = strchr(optarg, ':');
if (range) {
buffer = strndup(optarg, range - optarg);
@@ -819,9 +909,28 @@ static int parse_argv(int argc, char *argv[]) {
log_error("Failed to parse UID: %s", optarg);
return -EINVAL;
}
+
+ arg_userns_mode = USER_NAMESPACE_FIXED;
}
- arg_userns = true;
+ arg_settings_mask |= SETTING_USERNS;
+ break;
+
+ case 'U':
+ if (userns_supported()) {
+ arg_userns_mode = USER_NAMESPACE_PICK;
+ arg_uid_shift = UID_INVALID;
+ arg_uid_range = UINT32_C(0x10000);
+
+ arg_settings_mask |= SETTING_USERNS;
+ }
+
+ break;
+
+ case ARG_PRIVATE_USERS_CHOWN:
+ arg_userns_chown = true;
+
+ arg_settings_mask |= SETTING_USERNS;
break;
case ARG_KILL_SIGNAL:
@@ -892,6 +1001,9 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_share_system)
arg_register = false;
+ if (arg_userns_mode == USER_NAMESPACE_PICK)
+ arg_userns_chown = true;
+
if (arg_start_mode != START_PID1 && arg_share_system) {
log_error("--boot and --share-system may not be combined.");
return -EINVAL;
@@ -932,8 +1044,20 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
- if (arg_userns && access("/proc/self/uid_map", F_OK) < 0)
- return log_error_errno(EOPNOTSUPP, "--private-users= is not supported, kernel compiled without user namespace support.");
+ if (arg_userns_mode != USER_NAMESPACE_NO && !userns_supported()) {
+ log_error("--private-users= is not supported, kernel compiled without user namespace support.");
+ return -EOPNOTSUPP;
+ }
+
+ if (arg_userns_chown && arg_read_only) {
+ log_error("--read-only and --private-users-chown may not be combined.");
+ return -EINVAL;
+ }
+
+ if (arg_network_bridge && arg_network_zone) {
+ log_error("--network-bridge= and --network-zone= may not be combined.");
+ return -EINVAL;
+ }
if (argc > optind) {
arg_parameters = strv_copy(argv + optind);
@@ -976,6 +1100,13 @@ static int verify_arguments(void) {
return -EINVAL;
}
+#ifndef HAVE_LIBIPTC
+ if (arg_expose_ports) {
+ log_error("--port= is not supported, compiled without libiptc support.");
+ return -EOPNOTSUPP;
+ }
+#endif
+
if (arg_start_mode == START_BOOT && arg_kill_signal <= 0)
arg_kill_signal = SIGRTMIN+3;
@@ -985,7 +1116,7 @@ static int verify_arguments(void) {
static int userns_lchown(const char *p, uid_t uid, gid_t gid) {
assert(p);
- if (!arg_userns)
+ if (arg_userns_mode == USER_NAMESPACE_NO)
return 0;
if (uid == UID_INVALID && gid == GID_INVALID)
@@ -1367,11 +1498,11 @@ static int setup_hostname(void) {
}
static int setup_journal(const char *directory) {
- sd_id128_t machine_id, this_id;
- _cleanup_free_ char *b = NULL, *d = NULL;
- const char *etc_machine_id, *p, *q;
+ sd_id128_t this_id;
+ _cleanup_free_ char *d = NULL;
+ const char *p, *q;
bool try;
- char *id;
+ char id[33];
int r;
/* Don't link journals in ephemeral mode */
@@ -1383,30 +1514,13 @@ static int setup_journal(const char *directory) {
try = arg_link_journal_try || arg_link_journal == LINK_AUTO;
- etc_machine_id = prefix_roota(directory, "/etc/machine-id");
-
- r = read_one_line_file(etc_machine_id, &b);
- if (r == -ENOENT && try)
- return 0;
- else if (r < 0)
- return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
-
- id = strstrip(b);
- if (isempty(id) && try)
- return 0;
-
- /* Verify validity */
- r = sd_id128_from_string(id, &machine_id);
- if (r < 0)
- return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
-
r = sd_id128_get_machine(&this_id);
if (r < 0)
return log_error_errno(r, "Failed to retrieve machine ID: %m");
- if (sd_id128_equal(machine_id, this_id)) {
+ if (sd_id128_equal(arg_uuid, this_id)) {
log_full(try ? LOG_WARNING : LOG_ERR,
- "Host and machine ids are equal (%s): refusing to link journals", id);
+ "Host and machine ids are equal (%s): refusing to link journals", sd_id128_to_string(arg_uuid, id));
if (try)
return 0;
return -EEXIST;
@@ -1424,6 +1538,8 @@ static int setup_journal(const char *directory) {
if (r < 0)
return log_error_errno(r, "Failed to create /var/log/journal: %m");
+ (void) sd_id128_to_string(arg_uuid, id);
+
p = strjoina("/var/log/journal/", id);
q = prefix_roota(directory, p);
@@ -1488,7 +1604,7 @@ static int setup_journal(const char *directory) {
}
if (arg_link_journal == LINK_HOST) {
- /* don't create parents here -- if the host doesn't have
+ /* don't create parents here — if the host doesn't have
* permanent journal set up, don't force it here */
if (mkdir(p, 0755) < 0 && errno != EEXIST) {
@@ -1597,7 +1713,6 @@ static int setup_seccomp(void) {
}
}
-
/*
Audit is broken in containers, much of the userspace audit
hookup will fail if running inside a container. We don't
@@ -2193,6 +2308,61 @@ static int mount_device(const char *what, const char *where, const char *directo
#endif
}
+static int setup_machine_id(const char *directory) {
+ int r;
+ const char *etc_machine_id, *t;
+ _cleanup_free_ char *s = NULL;
+
+ etc_machine_id = prefix_roota(directory, "/etc/machine-id");
+
+ r = read_one_line_file(etc_machine_id, &s);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id);
+
+ t = strstrip(s);
+
+ if (!isempty(t)) {
+ r = sd_id128_from_string(t, &arg_uuid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse machine ID from %s: %m", etc_machine_id);
+ } else {
+ if (sd_id128_is_null(arg_uuid)) {
+ r = sd_id128_randomize(&arg_uuid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to generate random machine ID: %m");
+ }
+ }
+
+ r = machine_id_setup(directory, arg_uuid);
+ if (r < 0)
+ return log_error_errno(r, "Failed to setup machine ID: %m");
+
+ return 0;
+}
+
+static int recursive_chown(const char *directory, uid_t shift, uid_t range) {
+ int r;
+
+ assert(directory);
+
+ if (arg_userns_mode == USER_NAMESPACE_NO || !arg_userns_chown)
+ return 0;
+
+ r = path_patch_uid(directory, arg_uid_shift, arg_uid_range);
+ if (r == -EOPNOTSUPP)
+ return log_error_errno(r, "Automatic UID/GID adjusting is only supported for UID/GID ranges starting at multiples of 2^16 with a range of 2^16.");
+ if (r == -EBADE)
+ return log_error_errno(r, "Upper 16 bits of root directory UID and GID do not match.");
+ if (r < 0)
+ return log_error_errno(r, "Failed to adjust UID/GID shift of OS tree: %m");
+ if (r == 0)
+ log_debug("Root directory of image is already owned by the right UID/GID range, skipping recursive chown operation.");
+ else
+ log_debug("Patched directory tree to match UID/GID range.");
+
+ return r;
+}
+
static int mount_devices(
const char *where,
const char *root_device, bool root_device_rw,
@@ -2410,7 +2580,7 @@ static int determine_names(void) {
static int determine_uid_shift(const char *directory) {
int r;
- if (!arg_userns) {
+ if (arg_userns_mode == USER_NAMESPACE_NO) {
arg_uid_shift = 0;
return 0;
}
@@ -2437,7 +2607,6 @@ static int determine_uid_shift(const char *directory) {
return -EINVAL;
}
- log_info("Using user namespaces with base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
return 0;
}
@@ -2450,6 +2619,7 @@ static int inner_child(
FDSet *fds) {
_cleanup_free_ char *home = NULL;
+ char as_uuid[37];
unsigned n_env = 1;
const char *envp[] = {
"PATH=" DEFAULT_PATH_SPLIT_USR,
@@ -2473,7 +2643,7 @@ static int inner_child(
cg_unified_flush();
- if (arg_userns) {
+ if (arg_userns_mode != USER_NAMESPACE_NO) {
/* Tell the parent, that it now can write the UID map. */
(void) barrier_place(barrier); /* #1 */
@@ -2484,7 +2654,14 @@ static int inner_child(
}
}
- r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_all(NULL,
+ arg_userns_mode != USER_NAMESPACE_NO,
+ true,
+ arg_private_network,
+ arg_uid_shift,
+ arg_uid_range,
+ arg_selinux_apifs_context);
+
if (r < 0)
return r;
@@ -2560,19 +2737,17 @@ static int inner_child(
envp[n_env] = strv_find_prefix(environ, "TERM=");
if (envp[n_env])
- n_env ++;
+ n_env++;
if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) ||
(asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) ||
(asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0))
return log_oom();
- if (!sd_id128_equal(arg_uuid, SD_ID128_NULL)) {
- char as_uuid[37];
+ assert(!sd_id128_equal(arg_uuid, SD_ID128_NULL));
- if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
- return log_oom();
- }
+ if (asprintf((char**)(envp + n_env++), "container_uuid=%s", id128_format_as_uuid(arg_uuid, as_uuid)) < 0)
+ return log_oom();
if (fdset_size(fds) > 0) {
r = fdset_cloexec(fds, false);
@@ -2623,12 +2798,10 @@ static int inner_child(
/* Automatically search for the init system */
- m = 1 + strv_length(arg_parameters);
- a = newa(char*, m + 1);
- if (strv_isempty(arg_parameters))
- a[1] = NULL;
- else
- memcpy(a + 1, arg_parameters, m * sizeof(char*));
+ m = strv_length(arg_parameters);
+ a = newa(char*, m + 2);
+ memcpy_safe(a + 1, arg_parameters, m * sizeof(char*));
+ a[1 + m] = NULL;
a[0] = (char*) "/usr/lib/systemd/systemd";
execve(a[0], a, env_use);
@@ -2642,7 +2815,8 @@ static int inner_child(
execvpe(arg_parameters[0], arg_parameters, env_use);
else {
if (!arg_chdir)
- chdir(home ?: "/root");
+ /* If we cannot change the directory, we'll end up in /, that is expected. */
+ (void) chdir(home ?: "/root");
execle("/bin/bash", "-bash", NULL, env_use);
execle("/bin/sh", "-sh", NULL, env_use);
@@ -2663,6 +2837,7 @@ static int outer_child(
bool interactive,
bool secondary,
int pid_socket,
+ int uuid_socket,
int kmsg_socket,
int rtnl_socket,
int uid_shift_socket,
@@ -2676,6 +2851,7 @@ static int outer_child(
assert(directory);
assert(console);
assert(pid_socket >= 0);
+ assert(uuid_socket >= 0);
assert(kmsg_socket >= 0);
cg_unified_flush();
@@ -2724,7 +2900,8 @@ static int outer_child(
if (r < 0)
return r;
- if (arg_userns) {
+ if (arg_userns_mode != USER_NAMESPACE_NO) {
+ /* Let the parent know which UID shift we read from the image */
l = send(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL);
if (l < 0)
return log_error_errno(errno, "Failed to send UID shift: %m");
@@ -2732,17 +2909,49 @@ static int outer_child(
log_error("Short write while sending UID shift.");
return -EIO;
}
+
+ if (arg_userns_mode == USER_NAMESPACE_PICK) {
+ /* When we are supposed to pick the UID shift, the parent will check now whether the UID shift
+ * we just read from the image is available. If yes, it will send the UID shift back to us, if
+ * not it will pick a different one, and send it back to us. */
+
+ l = recv(uid_shift_socket, &arg_uid_shift, sizeof(arg_uid_shift), 0);
+ if (l < 0)
+ return log_error_errno(errno, "Failed to recv UID shift: %m");
+ if (l != sizeof(arg_uid_shift)) {
+ log_error("Short read while recieving UID shift.");
+ return -EIO;
+ }
+ }
+
+ log_info("Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
}
/* Turn directory into bind mount */
if (mount(directory, directory, NULL, MS_BIND|MS_REC, NULL) < 0)
return log_error_errno(errno, "Failed to make bind mount: %m");
- r = setup_volatile(directory, arg_volatile_mode, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_context);
+ r = recursive_chown(directory, arg_uid_shift, arg_uid_range);
if (r < 0)
return r;
- r = setup_volatile_state(directory, arg_volatile_mode, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_context);
+ r = setup_volatile(
+ directory,
+ arg_volatile_mode,
+ arg_userns_mode != USER_NAMESPACE_NO,
+ arg_uid_shift,
+ arg_uid_range,
+ arg_selinux_context);
+ if (r < 0)
+ return r;
+
+ r = setup_volatile_state(
+ directory,
+ arg_volatile_mode,
+ arg_userns_mode != USER_NAMESPACE_NO,
+ arg_uid_shift,
+ arg_uid_range,
+ arg_selinux_context);
if (r < 0)
return r;
@@ -2756,7 +2965,13 @@ static int outer_child(
return log_error_errno(r, "Failed to make tree read-only: %m");
}
- r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_all(directory,
+ arg_userns_mode != USER_NAMESPACE_NO,
+ false,
+ arg_private_network,
+ arg_uid_shift,
+ arg_uid_range,
+ arg_selinux_apifs_context);
if (r < 0)
return r;
@@ -2790,15 +3005,32 @@ static int outer_child(
if (r < 0)
return r;
+ r = setup_machine_id(directory);
+ if (r < 0)
+ return r;
+
r = setup_journal(directory);
if (r < 0)
return r;
- r = mount_custom(directory, arg_custom_mounts, arg_n_custom_mounts, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_custom(
+ directory,
+ arg_custom_mounts,
+ arg_n_custom_mounts,
+ arg_userns_mode != USER_NAMESPACE_NO,
+ arg_uid_shift,
+ arg_uid_range,
+ arg_selinux_apifs_context);
if (r < 0)
return r;
- r = mount_cgroups(directory, arg_unified_cgroup_hierarchy, arg_userns, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
+ r = mount_cgroups(
+ directory,
+ arg_unified_cgroup_hierarchy,
+ arg_userns_mode != USER_NAMESPACE_NO,
+ arg_uid_shift,
+ arg_uid_range,
+ arg_selinux_apifs_context);
if (r < 0)
return r;
@@ -2809,12 +3041,13 @@ static int outer_child(
pid = raw_clone(SIGCHLD|CLONE_NEWNS|
(arg_share_system ? 0 : CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS) |
(arg_private_network ? CLONE_NEWNET : 0) |
- (arg_userns ? CLONE_NEWUSER : 0),
+ (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0),
NULL);
if (pid < 0)
return log_error_errno(errno, "Failed to fork inner child: %m");
if (pid == 0) {
pid_socket = safe_close(pid_socket);
+ uuid_socket = safe_close(uuid_socket);
uid_shift_socket = safe_close(uid_shift_socket);
/* The inner child has all namespaces that are
@@ -2836,13 +3069,77 @@ static int outer_child(
return -EIO;
}
+ l = send(uuid_socket, &arg_uuid, sizeof(arg_uuid), MSG_NOSIGNAL);
+ if (l < 0)
+ return log_error_errno(errno, "Failed to send machine ID: %m");
+ if (l != sizeof(arg_uuid)) {
+ log_error("Short write while sending machine ID.");
+ return -EIO;
+ }
+
pid_socket = safe_close(pid_socket);
+ uuid_socket = safe_close(uuid_socket);
kmsg_socket = safe_close(kmsg_socket);
rtnl_socket = safe_close(rtnl_socket);
return 0;
}
+static int uid_shift_pick(uid_t *shift, LockFile *ret_lock_file) {
+ unsigned n_tries = 100;
+ uid_t candidate;
+ int r;
+
+ assert(shift);
+ assert(ret_lock_file);
+ assert(arg_userns_mode == USER_NAMESPACE_PICK);
+ assert(arg_uid_range == 0x10000U);
+
+ candidate = *shift;
+
+ (void) mkdir("/run/systemd/nspawn-uid", 0755);
+
+ for (;;) {
+ char lock_path[strlen("/run/systemd/nspawn-uid/") + DECIMAL_STR_MAX(uid_t) + 1];
+ _cleanup_release_lock_file_ LockFile lf = LOCK_FILE_INIT;
+
+ if (--n_tries <= 0)
+ return -EBUSY;
+
+ if (candidate < UID_SHIFT_PICK_MIN || candidate > UID_SHIFT_PICK_MAX)
+ goto next;
+ if ((candidate & UINT32_C(0xFFFF)) != 0)
+ goto next;
+
+ xsprintf(lock_path, "/run/systemd/nspawn-uid/" UID_FMT, candidate);
+ r = make_lock_file(lock_path, LOCK_EX|LOCK_NB, &lf);
+ if (r == -EBUSY) /* Range already taken by another nspawn instance */
+ goto next;
+ if (r < 0)
+ return r;
+
+ /* Make some superficial checks whether the range is currently known in the user database */
+ if (getpwuid(candidate))
+ goto next;
+ if (getpwuid(candidate + UINT32_C(0xFFFE)))
+ goto next;
+ if (getgrgid(candidate))
+ goto next;
+ if (getgrgid(candidate + UINT32_C(0xFFFE)))
+ goto next;
+
+ *ret_lock_file = lf;
+ lf = (struct LockFile) LOCK_FILE_INIT;
+ *shift = candidate;
+ return 0;
+
+ next:
+ random_bytes(&candidate, sizeof(candidate));
+ candidate = (candidate % (UID_SHIFT_PICK_MAX - UID_SHIFT_PICK_MIN)) + UID_SHIFT_PICK_MIN;
+ candidate &= (uid_t) UINT32_C(0xFFFF0000);
+ }
+}
+
static int setup_uid_map(pid_t pid) {
char uid_map[strlen("/proc//uid_map") + DECIMAL_STR_MAX(uid_t) + 1], line[DECIMAL_STR_MAX(uid_t)*3+3+1];
int r;
@@ -3029,6 +3326,7 @@ static int load_settings(void) {
(settings->private_network >= 0 ||
settings->network_veth >= 0 ||
settings->network_bridge ||
+ settings->network_zone ||
settings->network_interfaces ||
settings->network_macvlan ||
settings->network_ipvlan ||
@@ -3059,6 +3357,10 @@ static int load_settings(void) {
free(arg_network_bridge);
arg_network_bridge = settings->network_bridge;
settings->network_bridge = NULL;
+
+ free(arg_network_zone);
+ arg_network_zone = settings->network_zone;
+ settings->network_zone = NULL;
}
}
@@ -3074,6 +3376,19 @@ static int load_settings(void) {
}
}
+ if ((arg_settings_mask & SETTING_USERNS) == 0 &&
+ settings->userns_mode != _USER_NAMESPACE_MODE_INVALID) {
+
+ if (!arg_settings_trusted)
+ log_warning("Ignoring PrivateUsers= and PrivateUsersChown= settings, file %s is not trusted.", p);
+ else {
+ arg_userns_mode = settings->userns_mode;
+ arg_uid_shift = settings->uid_shift;
+ arg_uid_range = settings->uid_range;
+ arg_userns_chown = settings->userns_chown;
+ }
+ }
+
return 0;
}
@@ -3084,14 +3399,14 @@ int main(int argc, char *argv[]) {
_cleanup_close_ int master = -1, image_fd = -1;
_cleanup_fdset_free_ FDSet *fds = NULL;
int r, n_fd_passed, loop_nr = -1;
- char veth_name[IFNAMSIZ];
+ char veth_name[IFNAMSIZ] = "";
bool secondary = false, remove_subvol = false;
sigset_t mask_chld;
pid_t pid = 0;
int ret = EXIT_SUCCESS;
union in_addr_union exposed = {};
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
- bool interactive;
+ bool interactive, veth_created = false;
log_parse_environment();
log_open();
@@ -3286,6 +3601,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (arg_selinux_apifs_context) {
+ r = mac_selinux_apply(console, arg_selinux_apifs_context);
+ if (r < 0)
+ goto finish;
+ }
+
if (unlockpt(master) < 0) {
r = log_error_errno(errno, "Failed to unlock tty: %m");
goto finish;
@@ -3306,19 +3627,42 @@ int main(int argc, char *argv[]) {
}
for (;;) {
- _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 };
- ContainerStatus container_status;
- _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
static const struct sigaction sa = {
.sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP,
};
- int ifi = 0;
- ssize_t l;
+
+ _cleanup_release_lock_file_ LockFile uid_shift_lock = LOCK_FILE_INIT;
+ _cleanup_close_ int etc_passwd_lock = -1;
+ _cleanup_close_pair_ int
+ kmsg_socket_pair[2] = { -1, -1 },
+ rtnl_socket_pair[2] = { -1, -1 },
+ pid_socket_pair[2] = { -1, -1 },
+ uuid_socket_pair[2] = { -1, -1 },
+ uid_shift_socket_pair[2] = { -1, -1 };
+ _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
_cleanup_(sd_event_unrefp) sd_event *event = NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
+ ContainerStatus container_status;
char last_char = 0;
+ int ifi = 0;
+ ssize_t l;
+
+ if (arg_userns_mode == USER_NAMESPACE_PICK) {
+ /* When we shall pick the UID/GID range, let's first lock /etc/passwd, so that we can safely
+ * check with getpwuid() if the specific user already exists. Note that /etc might be
+ * read-only, in which case this will fail with EROFS. But that's really OK, as in that case we
+ * can be reasonably sure that no users are going to be added. Note that getpwuid() checks are
+ * really just an extra safety net. We kinda assume that the UID range we allocate from is
+ * really ours. */
+
+ etc_passwd_lock = take_etc_passwd_lock(NULL);
+ if (etc_passwd_lock < 0 && etc_passwd_lock != -EROFS) {
+ log_error_errno(r, "Failed to take /etc/passwd lock: %m");
+ goto finish;
+ }
+ }
r = barrier_create(&barrier);
if (r < 0) {
@@ -3341,7 +3685,12 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (arg_userns)
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uuid_socket_pair) < 0) {
+ r = log_error_errno(errno, "Failed to create id socket pair: %m");
+ goto finish;
+ }
+
+ if (arg_userns_mode != USER_NAMESPACE_NO)
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, uid_shift_socket_pair) < 0) {
r = log_error_errno(errno, "Failed to create uid shift socket pair: %m");
goto finish;
@@ -3381,6 +3730,7 @@ int main(int argc, char *argv[]) {
kmsg_socket_pair[0] = safe_close(kmsg_socket_pair[0]);
rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
pid_socket_pair[0] = safe_close(pid_socket_pair[0]);
+ uuid_socket_pair[0] = safe_close(uuid_socket_pair[0]);
uid_shift_socket_pair[0] = safe_close(uid_shift_socket_pair[0]);
(void) reset_all_signal_handlers();
@@ -3395,6 +3745,7 @@ int main(int argc, char *argv[]) {
interactive,
secondary,
pid_socket_pair[1],
+ uuid_socket_pair[1],
kmsg_socket_pair[1],
rtnl_socket_pair[1],
uid_shift_socket_pair[1],
@@ -3412,8 +3763,46 @@ int main(int argc, char *argv[]) {
kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
pid_socket_pair[1] = safe_close(pid_socket_pair[1]);
+ uuid_socket_pair[1] = safe_close(uuid_socket_pair[1]);
uid_shift_socket_pair[1] = safe_close(uid_shift_socket_pair[1]);
+ if (arg_userns_mode != USER_NAMESPACE_NO) {
+ /* The child just let us know the UID shift it might have read from the image. */
+ l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0);
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to read UID shift: %m");
+ goto finish;
+ }
+ if (l != sizeof(arg_uid_shift)) {
+ log_error("Short read while reading UID shift.");
+ r = EIO;
+ goto finish;
+ }
+
+ if (arg_userns_mode == USER_NAMESPACE_PICK) {
+ /* If we are supposed to pick the UID shift, let's try to use the shift read from the
+ * image, but if that's already in use, pick a new one, and report back to the child,
+ * which one we now picked. */
+
+ r = uid_shift_pick(&arg_uid_shift, &uid_shift_lock);
+ if (r < 0) {
+ log_error_errno(r, "Failed to pick suitable UID/GID range: %m");
+ goto finish;
+ }
+
+ l = send(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), MSG_NOSIGNAL);
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to send UID shift: %m");
+ goto finish;
+ }
+ if (l != sizeof(arg_uid_shift)) {
+ log_error("Short write while writing UID shift.");
+ r = -EIO;
+ goto finish;
+ }
+ }
+ }
+
/* Wait for the outer child. */
r = wait_for_terminate_and_warn("namespace helper", pid, NULL);
if (r < 0)
@@ -3436,26 +3825,27 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ /* We also retrieve container UUID in case it was generated by outer child */
+ l = recv(uuid_socket_pair[0], &arg_uuid, sizeof(arg_uuid), 0);
+ if (l < 0) {
+ r = log_error_errno(errno, "Failed to read container machine ID: %m");
+ goto finish;
+ }
+ if (l != sizeof(arg_uuid)) {
+ log_error("Short read while reading container machined ID.");
+ r = EIO;
+ goto finish;
+ }
+
log_debug("Init process invoked as PID " PID_FMT, pid);
- if (arg_userns) {
+ if (arg_userns_mode != USER_NAMESPACE_NO) {
if (!barrier_place_and_sync(&barrier)) { /* #1 */
log_error("Child died too early.");
r = -ESRCH;
goto finish;
}
- l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof(arg_uid_shift), 0);
- if (l < 0) {
- r = log_error_errno(errno, "Failed to read UID shift: %m");
- goto finish;
- }
- if (l != sizeof(arg_uid_shift)) {
- log_error("Short read while reading UID shift.");
- r = EIO;
- goto finish;
- }
-
r = setup_uid_map(pid);
if (r < 0)
goto finish;
@@ -3470,14 +3860,23 @@ int main(int argc, char *argv[]) {
goto finish;
if (arg_network_veth) {
- r = setup_veth(arg_machine, pid, veth_name, !!arg_network_bridge);
+ r = setup_veth(arg_machine, pid, veth_name,
+ arg_network_bridge || arg_network_zone);
if (r < 0)
goto finish;
else if (r > 0)
ifi = r;
if (arg_network_bridge) {
- r = setup_bridge(veth_name, arg_network_bridge);
+ /* Add the interface to a bridge */
+ r = setup_bridge(veth_name, arg_network_bridge, false);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ ifi = r;
+ } else if (arg_network_zone) {
+ /* Add the interface to a bridge, possibly creating it */
+ r = setup_bridge(veth_name, arg_network_zone, true);
if (r < 0)
goto finish;
if (r > 0)
@@ -3489,6 +3888,12 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
+ /* We created the primary and extra veth links now; let's remember this, so that we know to
+ remove them later on. Note that we don't bother with removing veth links that were created
+ here when their setup failed half-way, because in that case the kernel should be able to
+ remove them on its own, since they cannot be referenced by anything yet. */
+ veth_created = true;
+
r = setup_macvlan(arg_machine, pid, arg_network_macvlan);
if (r < 0)
goto finish;
@@ -3553,6 +3958,10 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ /* At this point we have made use of the UID we picked, and thus nss-mymachines will make them appear
+ * in getpwuid(), thus we can release the /etc/passwd lock. */
+ etc_passwd_lock = safe_close(etc_passwd_lock);
+
sd_notifyf(false,
"READY=1\n"
"STATUS=Container running.\n"
@@ -3620,7 +4029,7 @@ int main(int argc, char *argv[]) {
/* We failed to wait for the container, or the
* container exited abnormally */
goto finish;
- else if (r > 0 || container_status == CONTAINER_TERMINATED){
+ else if (r > 0 || container_status == CONTAINER_TERMINATED) {
/* The container exited with a non-zero
* status, or with zero status and no reboot
* was requested. */
@@ -3647,6 +4056,9 @@ int main(int argc, char *argv[]) {
}
expose_port_flush(arg_expose_ports, &exposed);
+
+ (void) remove_veth_links(veth_name, arg_network_veth_extra);
+ veth_created = false;
}
finish:
@@ -3680,6 +4092,10 @@ finish:
expose_port_flush(arg_expose_ports, &exposed);
+ if (veth_created)
+ (void) remove_veth_links(veth_name, arg_network_veth_extra);
+ (void) remove_bridge(arg_network_zone);
+
free(arg_directory);
free(arg_template);
free(arg_image);
diff --git a/src/systemd-nspawn/test-patch-uid.c b/src/systemd-nspawn/test-patch-uid.c
new file mode 100644
index 0000000000..11c5321788
--- /dev/null
+++ b/src/systemd-nspawn/test-patch-uid.c
@@ -0,0 +1,61 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+
+#include "log.h"
+#include "nspawn-patch-uid.h"
+#include "user-util.h"
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+ uid_t shift, range;
+ int r;
+
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+ log_open();
+
+ if (argc != 4) {
+ log_error("Expected PATH SHIFT RANGE parameters.");
+ return EXIT_FAILURE;
+ }
+
+ r = parse_uid(argv[2], &shift);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse UID shift %s.", argv[2]);
+ return EXIT_FAILURE;
+ }
+
+ r = parse_gid(argv[3], &range);
+ if (r < 0) {
+ log_error_errno(r, "Failed to parse UID range %s.", argv[3]);
+ return EXIT_FAILURE;
+ }
+
+ r = path_patch_uid(argv[1], shift, range);
+ if (r < 0) {
+ log_error_errno(r, "Failed to patch directory tree: %m");
+ return EXIT_FAILURE;
+ }
+
+ log_info("Changed: %s", yes_no(r));
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/systemd-rc-local-generator/rc-local-generator.c b/src/systemd-rc-local-generator/rc-local-generator.c
index 9e9c161993..618bbe428d 100644
--- a/src/systemd-rc-local-generator/rc-local-generator.c
+++ b/src/systemd-rc-local-generator/rc-local-generator.c
@@ -36,7 +36,7 @@
#define RC_LOCAL_SCRIPT_PATH_STOP "/sbin/halt.local"
#endif
-const char *arg_dest = "/tmp";
+static const char *arg_dest = "/tmp";
static int add_symlink(const char *service, const char *where) {
_cleanup_free_ char *from = NULL, *to = NULL;
diff --git a/src/systemd-reply-password/reply-password.c b/src/systemd-reply-password/reply-password.c
index e291758969..17eab9772e 100644
--- a/src/systemd-reply-password/reply-password.c
+++ b/src/systemd-reply-password/reply-password.c
@@ -26,14 +26,12 @@
#include "fd-util.h"
#include "log.h"
#include "macro.h"
+#include "socket-util.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) {
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa = {
+ union sockaddr_union sa = {
.un.sun_family = AF_UNIX,
};
@@ -43,7 +41,7 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0)
+ if (sendto(fd, packet, size, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0)
return log_error_errno(errno, "Failed to send: %m");
return 0;
diff --git a/src/systemd-run/run.c b/src/systemd-run/run.c
index 67706f84a0..29b5131f70 100644
--- a/src/systemd-run/run.c
+++ b/src/systemd-run/run.c
@@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "bus-error.h"
+#include "bus-unit-util.h"
#include "bus-util.h"
#include "calendarspec.h"
#include "env-util.h"
@@ -83,8 +84,8 @@ static void polkit_agent_open_if_enabled(void) {
static void help(void) {
printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
"Run the specified command in a transient scope or service or timer\n"
- "unit. If timer option is specified and unit is exist which is\n"
- "specified with --unit option then command can be omitted.\n\n"
+ "unit. If a timer option is specified and the unit specified with\n"
+ "the --unit option exists, the command can be omitted.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-ask-password Do not prompt for password\n"
@@ -103,7 +104,7 @@ static void help(void) {
" --uid=USER Run as system user\n"
" --gid=GROUP Run as system group\n"
" --nice=NICE Nice level\n"
- " --setenv=NAME=VALUE Set environment\n"
+ " -E --setenv=NAME=VALUE Set environment\n"
" -t --pty Run service on pseudo tty\n"
" -q --quiet Suppress information messages during runtime\n\n"
"Timer options:\n\n"
@@ -125,7 +126,6 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
- ARG_NO_ASK_PASSWORD,
ARG_USER,
ARG_SYSTEM,
ARG_SCOPE,
@@ -133,12 +133,10 @@ static int parse_argv(int argc, char *argv[]) {
ARG_DESCRIPTION,
ARG_SLICE,
ARG_SEND_SIGHUP,
+ ARG_SERVICE_TYPE,
ARG_EXEC_USER,
ARG_EXEC_GROUP,
- ARG_SERVICE_TYPE,
ARG_NICE,
- ARG_SETENV,
- ARG_TTY,
ARG_ON_ACTIVE,
ARG_ON_BOOT,
ARG_ON_STARTUP,
@@ -147,6 +145,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_ON_CALENDAR,
ARG_TIMER_PROPERTY,
ARG_NO_BLOCK,
+ ARG_NO_ASK_PASSWORD,
};
static const struct option options[] = {
@@ -166,9 +165,10 @@ static int parse_argv(int argc, char *argv[]) {
{ "uid", required_argument, NULL, ARG_EXEC_USER },
{ "gid", required_argument, NULL, ARG_EXEC_GROUP },
{ "nice", required_argument, NULL, ARG_NICE },
- { "setenv", required_argument, NULL, ARG_SETENV },
+ { "setenv", required_argument, NULL, 'E' },
{ "property", required_argument, NULL, 'p' },
- { "tty", no_argument, NULL, 't' },
+ { "tty", no_argument, NULL, 't' }, /* deprecated */
+ { "pty", no_argument, NULL, 't' },
{ "quiet", no_argument, NULL, 'q' },
{ "on-active", required_argument, NULL, ARG_ON_ACTIVE },
{ "on-boot", required_argument, NULL, ARG_ON_BOOT },
@@ -266,7 +266,7 @@ static int parse_argv(int argc, char *argv[]) {
arg_nice_set = true;
break;
- case ARG_SETENV:
+ case 'E':
if (strv_extend(&arg_environment, optarg) < 0)
return log_oom();
@@ -621,6 +621,10 @@ static int transient_scope_set_properties(sd_bus_message *m) {
if (r < 0)
return r;
+ r = transient_cgroup_set_properties(m);
+ if (r < 0)
+ return r;
+
r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
if (r < 0)
return r;
@@ -756,6 +760,7 @@ static int start_transient_service(
} else if (arg_transport == BUS_TRANSPORT_MACHINE) {
_cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL;
const char *s;
r = sd_bus_default_system(&system_bus);
@@ -768,19 +773,17 @@ static int start_transient_service(
"org.freedesktop.machine1.Manager",
"OpenMachinePTY",
&error,
- &reply,
+ &pty_reply,
"s", arg_host);
if (r < 0) {
log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
return r;
}
- r = sd_bus_message_read(reply, "hs", &master, &s);
+ r = sd_bus_message_read(pty_reply, "hs", &master, &s);
if (r < 0)
return bus_log_parse_error(r);
- reply = sd_bus_message_unref(reply);
-
master = fcntl(master, F_DUPFD_CLOEXEC, 3);
if (master < 0)
return log_error_errno(errno, "Failed to duplicate master fd: %m");
@@ -878,7 +881,7 @@ static int start_transient_service(
(void) sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
if (!arg_quiet)
- log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service);
+ log_info("Running as unit: %s\nPress ^] three times within 1s to disconnect TTY.", service);
r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward);
if (r < 0)
@@ -896,7 +899,7 @@ static int start_transient_service(
fputc('\n', stdout);
} else if (!arg_quiet)
- log_info("Running as unit %s.", service);
+ log_info("Running as unit: %s", service);
return 0;
}
@@ -1038,7 +1041,7 @@ static int start_transient_scope(
return r;
if (!arg_quiet)
- log_info("Running scope as unit %s.", scope);
+ log_info("Running scope as unit: %s", scope);
execvpe(argv[0], argv, env);
@@ -1189,9 +1192,9 @@ static int start_transient_timer(
if (r < 0)
return r;
- log_info("Running timer as unit %s.", timer);
+ log_info("Running timer as unit: %s", timer);
if (argv[0])
- log_info("Will run service as unit %s.", service);
+ log_info("Will run service as unit: %s", service);
return 0;
}
diff --git a/src/systemd-stdio-bridge/Makefile b/src/systemd-stdio-bridge/Makefile
index 650240a908..dd6d433fc6 100644
--- a/src/systemd-stdio-bridge/Makefile
+++ b/src/systemd-stdio-bridge/Makefile
@@ -24,10 +24,9 @@ include $(dir $(lastword $(MAKEFILE_LIST)))/../../config.mk
include $(topsrcdir)/build-aux/Makefile.head.mk
systemd_stdio_bridge_SOURCES = \
- src/bus-proxyd/stdio-bridge.c
+ src/stdio-bridge/stdio-bridge.c
systemd_stdio_bridge_LDADD = \
- libbus-proxy-core.la \
libshared.la
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/systemd-stdio-bridge/stdio-bridge.c b/src/systemd-stdio-bridge/stdio-bridge.c
index 60c4a08325..dce959cae3 100644
--- a/src/systemd-stdio-bridge/stdio-bridge.c
+++ b/src/systemd-stdio-bridge/stdio-bridge.c
@@ -2,8 +2,6 @@
This file is part of systemd.
Copyright 2010 Lennart Poettering
- Copyright 2013 Daniel Mack
- Copyright 2014 Kay Sievers
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -21,6 +19,7 @@
#include <errno.h>
#include <getopt.h>
+#include <poll.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
@@ -28,30 +27,24 @@
#include <systemd/sd-bus.h>
#include <systemd/sd-daemon.h>
-#include "alloc-util.h"
#include "bus-internal.h"
#include "bus-util.h"
-#include "def.h"
-#include "formats-util.h"
+#include "build.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;
+#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
+
+const char *arg_bus_path = DEFAULT_BUS_PATH;
static int help(void) {
printf("%s [OPTIONS...]\n\n"
- "Connect STDIO to a given bus address.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --machine=MACHINE Connect to specified machine\n"
- " --address=ADDRESS Connect to the bus specified by ADDRESS\n"
- " (default: " DEFAULT_SYSTEM_BUS_ADDRESS ")\n",
- program_invocation_short_name);
+ "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --bus-path=PATH Path to the kernel bus (default: %s)\n",
+ program_invocation_short_name, DEFAULT_BUS_PATH);
return 0;
}
@@ -60,16 +53,12 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
- ARG_ADDRESS,
- ARG_MACHINE,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "address", required_argument, NULL, ARG_ADDRESS },
- { "machine", required_argument, NULL, ARG_MACHINE },
- {},
+ { "help", no_argument, NULL, 'h' },
+ { "bus-path", required_argument, NULL, 'p' },
+ { NULL, 0, NULL, 0 }
};
int c;
@@ -77,7 +66,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
switch (c) {
@@ -88,157 +77,226 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_VERSION:
return version();
- case ARG_ADDRESS: {
- char *a;
-
- a = strdup(optarg);
- if (!a)
- return log_oom();
+ case '?':
+ return -EINVAL;
- free(arg_address);
- arg_address = a;
+ case 'p':
+ arg_bus_path = optarg;
break;
+
+ default:
+ log_error("Unknown option code %c", c);
+ return -EINVAL;
}
+ }
- case ARG_MACHINE: {
- _cleanup_free_ char *e = NULL;
- char *a;
+ return 1;
+}
- e = bus_address_escape(optarg);
- if (!e)
- return log_oom();
+int main(int argc, char *argv[]) {
+ _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL;
+ sd_id128_t server_id;
+ bool is_unix;
+ int r, in_fd, out_fd;
- a = strjoin("x-machine-kernel:machine=", e, ";x-machine-unix:machine=", e, NULL);
- if (!a)
- return log_oom();
+ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
+ log_parse_environment();
+ log_open();
- free(arg_address);
- arg_address = a;
+ r = parse_argv(argc, argv);
+ if (r <= 0)
+ goto finish;
- break;
- }
+ r = sd_listen_fds(0);
+ if (r == 0) {
+ in_fd = STDIN_FILENO;
+ out_fd = STDOUT_FILENO;
+ } else if (r == 1) {
+ in_fd = SD_LISTEN_FDS_START;
+ out_fd = SD_LISTEN_FDS_START;
+ } else {
+ log_error("Illegal number of file descriptors passed\n");
+ goto finish;
+ }
- case '?':
- return -EINVAL;
+ is_unix =
+ sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
+ sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
- default:
- assert_not_reached("Unhandled option");
- }
+ r = sd_bus_new(&a);
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate bus: %m");
+ goto finish;
+ }
- /* If the first command line argument is only "x" characters
- * we'll write who we are talking to into it, so that "ps" is
- * explanatory */
- arg_command_line_buffer = argv[optind];
- if (argc > optind + 1 || (arg_command_line_buffer && !in_charset(arg_command_line_buffer, "x"))) {
- log_error("Too many arguments");
- return -EINVAL;
+ r = sd_bus_set_address(a, arg_bus_path);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set address to connect to: %m");
+ goto finish;
}
- if (!arg_address) {
- arg_address = strdup(DEFAULT_SYSTEM_BUS_ADDRESS);
- if (!arg_address)
- return log_oom();
+ r = sd_bus_negotiate_fds(a, is_unix);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set FD negotiation: %m");
+ goto finish;
}
- return 1;
-}
+ r = sd_bus_start(a);
+ if (r < 0) {
+ log_error_errno(r, "Failed to start bus client: %m");
+ goto finish;
+ }
-static int rename_service(sd_bus *a, sd_bus *b) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- _cleanup_free_ char *p = NULL, *name = NULL;
- const char *comm;
- char **cmdline;
- uid_t uid;
- pid_t pid;
- int r;
-
- assert(a);
- assert(b);
-
- r = sd_bus_get_owner_creds(b, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_euid(creds, &uid);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_cmdline(creds, &cmdline);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_comm(creds, &comm);
- if (r < 0)
- return r;
-
- name = uid_to_name(uid);
- if (!name)
- return -ENOMEM;
-
- p = strv_join(cmdline, " ");
- if (!p)
- return -ENOMEM;
-
- /* The status string gets the full command line ... */
- sd_notifyf(false,
- "STATUS=Processing requests from client PID "PID_FMT" (%s); UID "UID_FMT" (%s)",
- pid, p,
- uid, name);
-
- /* ... and the argv line only the short comm */
- if (arg_command_line_buffer) {
- size_t m, w;
-
- m = strlen(arg_command_line_buffer);
- w = snprintf(arg_command_line_buffer, m,
- "[PID "PID_FMT"/%s; UID "UID_FMT"/%s]",
- pid, comm,
- uid, name);
-
- if (m > w)
- memzero(arg_command_line_buffer + w, m - w);
+ r = sd_bus_get_bus_id(a, &server_id);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get server ID: %m");
+ goto finish;
}
- log_debug("Running on behalf of PID "PID_FMT" (%s), UID "UID_FMT" (%s), %s",
- pid, p,
- uid, name,
- a->unique_name);
+ r = sd_bus_new(&b);
+ if (r < 0) {
+ log_error_errno(r, "Failed to allocate bus: %m");
+ goto finish;
+ }
- return 0;
-}
+ r = sd_bus_set_fd(b, in_fd, out_fd);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set fds: %m");
+ goto finish;
+ }
-int main(int argc, char *argv[]) {
- _cleanup_(proxy_freep) Proxy *p = NULL;
- int r;
+ r = sd_bus_set_server(b, 1, server_id);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set server mode: %m");
+ goto finish;
+ }
- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
- log_parse_environment();
- log_open();
+ r = sd_bus_negotiate_fds(b, is_unix);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set FD negotiation: %m");
+ goto finish;
+ }
- r = parse_argv(argc, argv);
- if (r <= 0)
+ r = sd_bus_set_anonymous(b, true);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set anonymous authentication: %m");
goto finish;
+ }
- r = proxy_new(&p, STDIN_FILENO, STDOUT_FILENO, arg_address);
- if (r < 0)
+ r = sd_bus_start(b);
+ if (r < 0) {
+ log_error_errno(r, "Failed to start bus client: %m");
goto finish;
+ }
- r = rename_service(p->destination_bus, p->local_bus);
- if (r < 0)
- log_debug_errno(r, "Failed to rename process: %m");
+ for (;;) {
+ _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL;
+ int events_a, events_b, fd;
+ uint64_t timeout_a, timeout_b, t;
+ struct timespec _ts, *ts;
- r = proxy_run(p);
+ r = sd_bus_process(a, &m);
+ if (r < 0) {
+ log_error_errno(r, "Failed to process bus a: %m");
+ goto finish;
+ }
-finish:
- sd_notify(false,
- "STOPPING=1\n"
- "STATUS=Shutting down.");
+ if (m) {
+ r = sd_bus_send(b, m, NULL);
+ if (r < 0) {
+ log_error_errno(r, "Failed to send message: %m");
+ goto finish;
+ }
+ }
+
+ if (r > 0)
+ continue;
+
+ r = sd_bus_process(b, &m);
+ if (r < 0) {
+ /* treat 'connection reset by peer' as clean exit condition */
+ if (r == -ECONNRESET)
+ r = 0;
- free(arg_address);
+ goto finish;
+ }
+
+ if (m) {
+ r = sd_bus_send(a, m, NULL);
+ if (r < 0) {
+ log_error_errno(r, "Failed to send message: %m");
+ goto finish;
+ }
+ }
+ if (r > 0)
+ continue;
+
+ fd = sd_bus_get_fd(a);
+ if (fd < 0) {
+ r = fd;
+ log_error_errno(r, "Failed to get fd: %m");
+ goto finish;
+ }
+
+ events_a = sd_bus_get_events(a);
+ if (events_a < 0) {
+ r = events_a;
+ log_error_errno(r, "Failed to get events mask: %m");
+ goto finish;
+ }
+
+ r = sd_bus_get_timeout(a, &timeout_a);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get timeout: %m");
+ goto finish;
+ }
+
+ events_b = sd_bus_get_events(b);
+ if (events_b < 0) {
+ r = events_b;
+ log_error_errno(r, "Failed to get events mask: %m");
+ goto finish;
+ }
+
+ r = sd_bus_get_timeout(b, &timeout_b);
+ if (r < 0) {
+ log_error_errno(r, "Failed to get timeout: %m");
+ goto finish;
+ }
+
+ t = timeout_a;
+ if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
+ t = timeout_b;
+
+ if (t == (uint64_t) -1)
+ ts = NULL;
+ else {
+ usec_t nw;
+
+ nw = now(CLOCK_MONOTONIC);
+ if (t > nw)
+ t -= nw;
+ else
+ t = 0;
+
+ ts = timespec_store(&_ts, t);
+ }
+
+ {
+ struct pollfd p[3] = {
+ {.fd = fd, .events = events_a, },
+ {.fd = STDIN_FILENO, .events = events_b & POLLIN, },
+ {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
+
+ r = ppoll(p, ELEMENTSOF(p), ts, NULL);
+ }
+ if (r < 0) {
+ log_error("ppoll() failed: %m");
+ goto finish;
+ }
+ }
+
+finish:
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/systemd-sysv-generator/sysv-generator.c b/src/systemd-sysv-generator/sysv-generator.c
index 5a6818a79d..fe4bbeeb75 100644
--- a/src/systemd-sysv-generator/sysv-generator.c
+++ b/src/systemd-sysv-generator/sysv-generator.c
@@ -70,7 +70,7 @@ static const struct {
UP must be read before DOWN */
};
-const char *arg_dest = "/tmp";
+static const char *arg_dest = "/tmp";
typedef struct SysvStub {
char *name;
@@ -729,14 +729,50 @@ static int fix_order(SysvStub *s, Hashmap *all_services) {
return 0;
}
+static int acquire_search_path(const char *def, const char *envvar, char ***ret) {
+ _cleanup_strv_free_ char **l = NULL;
+ const char *e;
+ int r;
+
+ assert(def);
+ assert(envvar);
+
+ e = getenv(envvar);
+ if (e) {
+ r = path_split_and_make_absolute(e, &l);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make $%s search path absolute: %m", envvar);
+ }
+
+ if (strv_isempty(l)) {
+ strv_free(l);
+
+ l = strv_new(def, NULL);
+ if (!l)
+ return log_oom();
+ }
+
+ if (!path_strv_resolve_uniq(l, NULL))
+ return log_oom();
+
+ *ret = l;
+ l = NULL;
+
+ return 0;
+}
+
static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
+ _cleanup_strv_free_ char **sysvinit_path = NULL;
char **path;
int r;
assert(lp);
- assert(all_services);
- STRV_FOREACH(path, lp->sysvinit_path) {
+ r = acquire_search_path(SYSTEM_SYSVINIT_PATH, "SYSTEMD_SYSVINIT_PATH", &sysvinit_path);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(path, sysvinit_path) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
@@ -770,11 +806,11 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
if (hashmap_contains(all_services, name))
continue;
- r = unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name, NULL);
- if (r < 0 && r != -ENOENT) {
+ r = unit_file_exists(UNIT_FILE_SYSTEM, lp, name);
+ if (r < 0 && !IN_SET(r, -ELOOP, -ERFKILL, -EADDRNOTAVAIL)) {
log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name);
continue;
- } else if (r >= 0) {
+ } else if (r != 0) {
log_debug("Native unit for %s already exists, skipping.", name);
continue;
}
@@ -806,6 +842,7 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
_cleanup_set_free_ Set *shutdown_services = NULL;
+ _cleanup_strv_free_ char **sysvrcnd_path = NULL;
SysvStub *service;
unsigned i;
Iterator j;
@@ -814,7 +851,11 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
assert(lp);
- STRV_FOREACH(p, lp->sysvrcnd_path) {
+ r = acquire_search_path(SYSTEM_SYSVRCND_PATH, "SYSTEMD_SYSVRCND_PATH", &sysvrcnd_path);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, sysvrcnd_path) {
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
_cleanup_closedir_ DIR *d = NULL;
@@ -864,7 +905,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
}
service = hashmap_get(all_services, name);
- if (!service){
+ if (!service) {
log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name);
continue;
}
@@ -963,7 +1004,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL);
+ r = lookup_paths_init(&lp, UNIT_FILE_SYSTEM, LOOKUP_PATHS_EXCLUDE_GENERATED, NULL);
if (r < 0) {
log_error_errno(r, "Failed to find lookup paths: %m");
goto finish;
diff --git a/src/systemd-timesync/timesyncd.c b/src/systemd-timesync/timesyncd.c
index 388eefac48..9e538a82f2 100644
--- a/src/systemd-timesync/timesyncd.c
+++ b/src/systemd-timesync/timesyncd.c
@@ -122,7 +122,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (clock_is_localtime() > 0) {
+ if (clock_is_localtime(NULL) > 0) {
log_info("The system is configured to read the RTC time in the local time zone. "
"This mode can not be fully supported. All system time to RTC updates are disabled.");
m->rtc_local_time = true;
diff --git a/src/systemd-tmpfiles/tmpfiles.c b/src/systemd-tmpfiles/tmpfiles.c
index 7b105a6bd4..2053d35a67 100644
--- a/src/systemd-tmpfiles/tmpfiles.c
+++ b/src/systemd-tmpfiles/tmpfiles.c
@@ -94,6 +94,7 @@ typedef enum ItemType {
/* These ones take globs */
WRITE_FILE = 'w',
+ EMPTY_DIRECTORY = 'e',
SET_XATTR = 't',
RECURSIVE_SET_XATTR = 'T',
SET_ACL = 'a',
@@ -179,6 +180,7 @@ static bool needs_glob(ItemType t) {
IGNORE_DIRECTORY_PATH,
REMOVE_PATH,
RECURSIVE_REMOVE_PATH,
+ EMPTY_DIRECTORY,
ADJUST_MODE,
RELABEL_PATH,
RECURSIVE_RELABEL_PATH,
@@ -195,6 +197,7 @@ static bool takes_ownership(ItemType t) {
CREATE_FILE,
TRUNCATE_FILE,
CREATE_DIRECTORY,
+ EMPTY_DIRECTORY,
TRUNCATE_DIRECTORY,
CREATE_SUBVOLUME,
CREATE_SUBVOLUME_INHERIT_QUOTA,
@@ -613,7 +616,7 @@ static int path_set_perms(Item *i, const char *path) {
* with AT_SYMLINK_NOFOLLOW, hence we emulate it here via
* O_PATH. */
- fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME);
+ fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
if (fd < 0)
return log_error_errno(errno, "Adjusting owner and mode for %s failed: %m", path);
@@ -804,7 +807,7 @@ static int path_set_acls(Item *item, const char *path) {
assert(item);
assert(path);
- fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC|O_PATH|O_NOATIME);
+ fd = open(path, O_NOFOLLOW|O_CLOEXEC|O_PATH);
if (fd < 0)
return log_error_errno(errno, "Adjusting ACL of %s failed: %m", path);
@@ -917,10 +920,7 @@ static int parse_attribute_from_arg(Item *item) {
v = attributes[i].value;
- if (mode == MODE_ADD || mode == MODE_SET)
- value |= v;
- else
- value &= ~v;
+ SET_FLAG(value, v, (mode == MODE_ADD || mode == MODE_SET));
mask |= v;
}
@@ -1220,7 +1220,6 @@ static int create_item(Item *i) {
case CREATE_SUBVOLUME:
case CREATE_SUBVOLUME_INHERIT_QUOTA:
case CREATE_SUBVOLUME_NEW_QUOTA:
-
RUN_WITH_UMASK(0000)
mkdir_parents_label(i->path, 0755);
@@ -1279,11 +1278,11 @@ static int create_item(Item *i) {
if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) {
r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA);
if (r == -ENOTTY)
- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path);
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (unsupported fs or dir not a subvolume): %m", i->path);
else if (r == -EROFS)
- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path);
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (fs is read-only).", i->path);
else if (r == -ENOPROTOOPT)
- log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path);
+ log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" (quota support is disabled).", i->path);
else if (r < 0)
q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path);
else if (r > 0)
@@ -1292,6 +1291,9 @@ static int create_item(Item *i) {
log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path);
}
+ /* fall through */
+
+ case EMPTY_DIRECTORY:
r = path_set_perms(i, i->path);
if (q < 0)
return q;
@@ -1301,7 +1303,6 @@ static int create_item(Item *i) {
break;
case CREATE_FIFO:
-
RUN_WITH_UMASK(0000) {
mac_selinux_create_file_prepare(i->path, S_IFIFO);
r = mkfifo(i->path, i->mode);
@@ -1538,47 +1539,20 @@ static int remove_item_instance(Item *i, const char *instance) {
}
static int remove_item(Item *i) {
- int r = 0;
-
assert(i);
log_debug("Running remove action for entry %c %s", (char) i->type, i->path);
switch (i->type) {
- case CREATE_FILE:
- case TRUNCATE_FILE:
- case CREATE_DIRECTORY:
- case CREATE_SUBVOLUME:
- case CREATE_SUBVOLUME_INHERIT_QUOTA:
- case CREATE_SUBVOLUME_NEW_QUOTA:
- case CREATE_FIFO:
- case CREATE_SYMLINK:
- case CREATE_CHAR_DEVICE:
- case CREATE_BLOCK_DEVICE:
- case IGNORE_PATH:
- case IGNORE_DIRECTORY_PATH:
- case ADJUST_MODE:
- case RELABEL_PATH:
- case RECURSIVE_RELABEL_PATH:
- case WRITE_FILE:
- case COPY_FILES:
- case SET_XATTR:
- case RECURSIVE_SET_XATTR:
- case SET_ACL:
- case RECURSIVE_SET_ACL:
- case SET_ATTRIBUTE:
- case RECURSIVE_SET_ATTRIBUTE:
- break;
-
case REMOVE_PATH:
case TRUNCATE_DIRECTORY:
case RECURSIVE_REMOVE_PATH:
- r = glob_item(i, remove_item_instance, false);
- break;
- }
+ return glob_item(i, remove_item_instance, false);
- return r;
+ default:
+ return 0;
+ }
}
static int clean_item_instance(Item *i, const char* instance) {
@@ -1633,8 +1607,6 @@ static int clean_item_instance(Item *i, const char* instance) {
}
static int clean_item(Item *i) {
- int r = 0;
-
assert(i);
log_debug("Running clean action for entry %c %s", (char) i->type, i->path);
@@ -1644,19 +1616,17 @@ static int clean_item(Item *i) {
case CREATE_SUBVOLUME:
case CREATE_SUBVOLUME_INHERIT_QUOTA:
case CREATE_SUBVOLUME_NEW_QUOTA:
+ case EMPTY_DIRECTORY:
case TRUNCATE_DIRECTORY:
case IGNORE_PATH:
case COPY_FILES:
clean_item_instance(i, i->path);
- break;
+ return 0;
case IGNORE_DIRECTORY_PATH:
- r = glob_item(i, clean_item_instance, false);
- break;
+ return glob_item(i, clean_item_instance, false);
default:
- break;
+ return 0;
}
-
- return r;
}
static int process_item_array(ItemArray *array);
@@ -1882,6 +1852,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
case CREATE_SUBVOLUME:
case CREATE_SUBVOLUME_INHERIT_QUOTA:
case CREATE_SUBVOLUME_NEW_QUOTA:
+ case EMPTY_DIRECTORY:
case TRUNCATE_DIRECTORY:
case CREATE_FIFO:
case IGNORE_PATH:
@@ -2201,7 +2172,8 @@ static int parse_argv(int argc, char *argv[]) {
}
static int read_config_file(const char *fn, bool ignore_enoent) {
- _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_fclose_ FILE *_f = NULL;
+ FILE *f;
char line[LINE_MAX];
Iterator iterator;
unsigned v = 0;
@@ -2210,16 +2182,23 @@ static int read_config_file(const char *fn, bool ignore_enoent) {
assert(fn);
- r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &f);
- if (r < 0) {
- if (ignore_enoent && r == -ENOENT) {
- log_debug_errno(r, "Failed to open \"%s\": %m", fn);
- return 0;
- }
+ if (streq(fn, "-")) {
+ log_debug("Reading config from stdin.");
+ fn = "<stdin>";
+ f = stdin;
+ } else {
+ r = search_and_fopen_nulstr(fn, "re", arg_root, conf_file_dirs, &_f);
+ if (r < 0) {
+ if (ignore_enoent && r == -ENOENT) {
+ log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
+ return 0;
+ }
- return log_error_errno(r, "Failed to open '%s', ignoring: %m", fn);
+ return log_error_errno(r, "Failed to open '%s': %m", fn);
+ }
+ log_debug("Reading config file \"%s\".", fn);
+ f = _f;
}
- log_debug("Reading config file \"%s\".", fn);
FOREACH_LINE(line, f, break) {
char *l;
@@ -2288,7 +2267,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- mac_selinux_init(NULL);
+ mac_selinux_init();
items = ordered_hashmap_new(&string_hash_ops);
globs = ordered_hashmap_new(&string_hash_ops);
diff --git a/src/systemd-tty-ask-password-agent/tty-ask-password-agent.c b/src/systemd-tty-ask-password-agent/tty-ask-password-agent.c
index 7b67831e54..ee879c7b89 100644
--- a/src/systemd-tty-ask-password-agent/tty-ask-password-agent.c
+++ b/src/systemd-tty-ask-password-agent/tty-ask-password-agent.c
@@ -65,8 +65,8 @@ static int ask_password_plymouth(
const char *flag_file,
char ***ret) {
+ static const union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_close_ int fd = -1, notify = -1;
- union sockaddr_union sa = PLYMOUTH_SOCKET;
_cleanup_free_ char *packet = NULL;
ssize_t k;
int r, n;
@@ -94,7 +94,7 @@ static int ask_password_plymouth(
if (fd < 0)
return -errno;
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1));
+ r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
return -errno;
@@ -269,8 +269,7 @@ static int send_passwords(const char *socket_name, char **passwords) {
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));
+ r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un));
if (r < 0)
r = log_debug_errno(errno, "sendto(): %m");
@@ -481,7 +480,7 @@ static int show_passwords(void) {
if (de->d_type != DT_REG)
continue;
- if (hidden_file(de->d_name))
+ if (hidden_or_backup_file(de->d_name))
continue;
if (!startswith(de->d_name, "ask."))
diff --git a/src/systemd-update-done/update-done.c b/src/systemd-update-done/update-done.c
index 931e583785..da306a4444 100644
--- a/src/systemd-update-done/update-done.c
+++ b/src/systemd-update-done/update-done.c
@@ -101,7 +101,7 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
- r = mac_selinux_init(NULL);
+ r = mac_selinux_init();
if (r < 0) {
log_error_errno(r, "SELinux setup failed: %m");
goto finish;
diff --git a/src/systemd-user-sessions/user-sessions.c b/src/systemd-user-sessions/user-sessions.c
index 8bf44e2100..9b29b5ba1d 100644
--- a/src/systemd-user-sessions/user-sessions.c
+++ b/src/systemd-user-sessions/user-sessions.c
@@ -40,7 +40,7 @@ int main(int argc, char*argv[]) {
umask(0022);
- mac_selinux_init(NULL);
+ mac_selinux_init();
if (streq(argv[1], "start")) {
int r = 0;
diff --git a/src/systemd-vconsole/vconsole-setup.c b/src/systemd-vconsole/vconsole-setup.c
index 8a1b824e65..1118118450 100644
--- a/src/systemd-vconsole/vconsole-setup.c
+++ b/src/systemd-vconsole/vconsole-setup.c
@@ -195,9 +195,15 @@ static void font_copy_to_all_vcs(int fd) {
unsigned char map8[E_TABSZ];
unsigned short map16[E_TABSZ];
struct unimapdesc unimapd;
- struct unipair unipairs[USHRT_MAX];
+ _cleanup_free_ struct unipair* unipairs = NULL;
int i, r;
+ unipairs = new(struct unipair, USHRT_MAX);
+ if (!unipairs) {
+ log_oom();
+ return;
+ }
+
/* get active, and 16 bit mask of used VT numbers */
r = ioctl(fd, VT_GETSTATE, &vcs);
if (r < 0) {
diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c
index 863c628323..4377f1b910 100644
--- a/src/sysusers/sysusers.c
+++ b/src/sysusers/sysusers.c
@@ -1820,7 +1820,7 @@ int main(int argc, char *argv[]) {
umask(0022);
- r = mac_selinux_init(NULL);
+ r = mac_selinux_init();
if (r < 0) {
log_error_errno(r, "SELinux setup failed: %m");
goto finish;
diff --git a/src/test/test-alloc-util.c b/src/test/test-alloc-util.c
new file mode 100644
index 0000000000..cc4821eaf5
--- /dev/null
+++ b/src/test/test-alloc-util.c
@@ -0,0 +1,55 @@
+/***
+ 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 "macro.h"
+#include "util.h"
+
+static void test_alloca(void) {
+ static const uint8_t zero[997] = { };
+ char *t;
+
+ t = alloca_align(17, 512);
+ assert_se(!((uintptr_t)t & 0xff));
+ memzero(t, 17);
+
+ t = alloca0_align(997, 1024);
+ assert_se(!((uintptr_t)t & 0x1ff));
+ assert_se(!memcmp(t, zero, 997));
+}
+
+static void test_memdup_multiply(void) {
+ int org[] = {1, 2, 3};
+ int *dup;
+
+ dup = (int*)memdup_multiply(org, sizeof(int), 3);
+
+ assert_se(dup);
+ assert_se(dup[0] == 1);
+ assert_se(dup[1] == 2);
+ assert_se(dup[2] == 3);
+ free(dup);
+}
+
+int main(int argc, char *argv[]) {
+ test_alloca();
+ test_memdup_multiply();
+
+ return 0;
+}
diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c
index d2add5880c..8e68d6510d 100644
--- a/src/test/test-boot-timestamps.c
+++ b/src/test/test-boot-timestamps.c
@@ -34,17 +34,18 @@ static int test_acpi_fpdt(void) {
r = acpi_get_boot_usec(&loader_start, &loader_exit);
if (r < 0) {
- if (r != -ENOENT)
- log_error_errno(r, "Failed to read ACPI FPDT: %m");
- return r;
+ bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES) || r == -ENODATA;
+
+ log_full_errno(ok ? LOG_DEBUG : LOG_ERR,
+ r, "Failed to read ACPI FPDT: %m");
+ return ok ? 0 : r;
}
log_info("ACPI FPDT: loader start=%s exit=%s duration=%s",
format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC),
format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC),
format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC));
-
- return 0;
+ return 1;
}
static int test_efi_loader(void) {
@@ -57,33 +58,34 @@ static int test_efi_loader(void) {
r = efi_loader_get_boot_usec(&loader_start, &loader_exit);
if (r < 0) {
- if (r != -ENOENT)
- log_error_errno(r, "Failed to read EFI loader data: %m");
- return r;
+ bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES);
+
+ log_full_errno(ok ? LOG_DEBUG : LOG_ERR,
+ r, "Failed to read EFI loader data: %m");
+ return ok ? 0 : r;
}
log_info("EFI Loader: start=%s exit=%s duration=%s",
format_timespan(ts_start, sizeof(ts_start), loader_start, USEC_PER_MSEC),
format_timespan(ts_exit, sizeof(ts_exit), loader_exit, USEC_PER_MSEC),
format_timespan(ts_span, sizeof(ts_span), loader_exit - loader_start, USEC_PER_MSEC));
-
- return 0;
+ return 1;
}
-int main(int argc, char* argv[]) {
+static int test_boot_timestamps(void) {
char s[MAX(FORMAT_TIMESPAN_MAX, FORMAT_TIMESTAMP_MAX)];
int r;
dual_timestamp fw, l, k;
- test_acpi_fpdt();
- test_efi_loader();
-
dual_timestamp_from_monotonic(&k, 0);
r = boot_timestamps(NULL, &fw, &l);
if (r < 0) {
- log_error_errno(r, "Failed to read variables: %m");
- return 1;
+ bool ok = r == -ENOENT || (getuid() != 0 && r == -EACCES);
+
+ log_full_errno(ok ? LOG_DEBUG : LOG_ERR,
+ r, "Failed to read variables: %m");
+ return ok ? 0 : r;
}
log_info("Firmware began %s before kernel.", format_timespan(s, sizeof(s), fw.monotonic, 0));
@@ -91,6 +93,21 @@ int main(int argc, char* argv[]) {
log_info("Firmware began %s.", format_timestamp(s, sizeof(s), fw.realtime));
log_info("Loader began %s.", format_timestamp(s, sizeof(s), l.realtime));
log_info("Kernel began %s.", format_timestamp(s, sizeof(s), k.realtime));
+ return 1;
+}
+
+int main(int argc, char* argv[]) {
+ int p, q, r;
+
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+
+ p = test_acpi_fpdt();
+ assert(p >= 0);
+ q = test_efi_loader();
+ assert(q >= 0);
+ r = test_boot_timestamps();
+ assert(r >= 0);
- return 0;
+ return (p > 0 || q > 0 || r >> 0) ? EXIT_SUCCESS : EXIT_TEST_SKIP;
}
diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c
index 8754cb3381..5a8c6cbfb6 100644
--- a/src/test/test-calendarspec.c
+++ b/src/test/test-calendarspec.c
@@ -137,6 +137,7 @@ int main(int argc, char* argv[]) {
test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000);
test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000);
test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000);
+ test_next("Sun 16:00:00", "CET", 1456041600123456, 1456066800000000);
assert_se(calendar_spec_from_string("test", &c) < 0);
assert_se(calendar_spec_from_string("", &c) < 0);
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index ad15075a5b..a027eb0fd2 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -21,7 +21,9 @@
#include "macro.h"
#include "manager.h"
+#include "rm-rf.h"
#include "test-helper.h"
+#include "tests.h"
#include "unit.h"
static int test_cgroup_mask(void) {
@@ -33,7 +35,7 @@ static int test_cgroup_mask(void) {
/* Prepare the manager. */
assert_se(set_unit_path(TEST_DIR) >= 0);
- r = manager_new(MANAGER_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, true, &m);
if (r == -EPERM || r == -EACCES) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
@@ -46,6 +48,7 @@ static int test_cgroup_mask(void) {
m->default_cpu_accounting =
m->default_memory_accounting =
m->default_blockio_accounting =
+ m->default_io_accounting =
m->default_tasks_accounting = false;
m->default_tasks_max = (uint64_t) -1;
@@ -74,7 +77,7 @@ static int test_cgroup_mask(void) {
assert_se(unit_get_own_mask(daughter) == 0);
assert_se(unit_get_own_mask(grandchild) == 0);
assert_se(unit_get_own_mask(parent_deep) == CGROUP_MASK_MEMORY);
- assert_se(unit_get_own_mask(parent) == CGROUP_MASK_BLKIO);
+ assert_se(unit_get_own_mask(parent) == (CGROUP_MASK_IO | CGROUP_MASK_BLKIO));
assert_se(unit_get_own_mask(root) == 0);
/* Verify aggregation of member masks */
@@ -83,23 +86,23 @@ static int test_cgroup_mask(void) {
assert_se(unit_get_members_mask(grandchild) == 0);
assert_se(unit_get_members_mask(parent_deep) == 0);
assert_se(unit_get_members_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
- assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+ assert_se(unit_get_members_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
/* Verify aggregation of sibling masks. */
assert_se(unit_get_siblings_mask(son) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
assert_se(unit_get_siblings_mask(daughter) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
assert_se(unit_get_siblings_mask(grandchild) == 0);
assert_se(unit_get_siblings_mask(parent_deep) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY));
- assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
- assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+ assert_se(unit_get_siblings_mask(parent) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
+ assert_se(unit_get_siblings_mask(root) == (CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY));
/* Verify aggregation of target masks. */
assert_se(unit_get_target_mask(son) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported));
assert_se(unit_get_target_mask(daughter) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported));
assert_se(unit_get_target_mask(grandchild) == 0);
assert_se(unit_get_target_mask(parent_deep) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_MEMORY) & m->cgroup_supported));
- assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
- assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
+ assert_se(unit_get_target_mask(parent) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
+ assert_se(unit_get_target_mask(root) == ((CGROUP_MASK_CPU | CGROUP_MASK_CPUACCT | CGROUP_MASK_IO | CGROUP_MASK_BLKIO | CGROUP_MASK_MEMORY) & m->cgroup_supported));
manager_free(m);
@@ -107,7 +110,11 @@ static int test_cgroup_mask(void) {
}
int main(int argc, char* argv[]) {
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int rc = 0;
+
+ assert_se(runtime_dir = setup_fake_runtime_dir());
TEST_REQ_RUNNING_SYSTEMD(rc = test_cgroup_mask());
+
return rc;
}
diff --git a/src/test/test-clock.c b/src/test/test-clock.c
new file mode 100644
index 0000000000..84f775e5bc
--- /dev/null
+++ b/src/test/test-clock.c
@@ -0,0 +1,96 @@
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2016 Canonical Ltd.
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "clock-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
+#include "macro.h"
+
+static void test_clock_is_localtime(void) {
+ char adjtime[] = "/tmp/test-adjtime.XXXXXX";
+ int fd = -1;
+ _cleanup_fclose_ FILE* f = NULL;
+
+ static const struct scenario {
+ const char* contents;
+ int expected_result;
+ } scenarios[] = {
+ /* adjtime configures UTC */
+ {"0.0 0 0\n0\nUTC\n", 0},
+ /* adjtime configures local time */
+ {"0.0 0 0\n0\nLOCAL\n", 1},
+ /* no final EOL */
+ {"0.0 0 0\n0\nUTC", 0},
+ {"0.0 0 0\n0\nLOCAL", 1},
+ /* empty value -> defaults to UTC */
+ {"0.0 0 0\n0\n", 0},
+ /* unknown value -> defaults to UTC */
+ {"0.0 0 0\n0\nFOO\n", 0},
+ /* no third line */
+ {"0.0 0 0", 0},
+ {"0.0 0 0\n", 0},
+ {"0.0 0 0\n0", 0},
+ };
+
+ /* without an adjtime file we default to UTC */
+ assert_se(clock_is_localtime("/nonexisting/adjtime") == 0);
+
+ fd = mkostemp_safe(adjtime, O_WRONLY|O_CLOEXEC);
+ assert_se(fd >= 0);
+ log_info("adjtime test file: %s", adjtime);
+ f = fdopen(fd, "w");
+ assert_se(f);
+
+ for (size_t i = 0; i < ELEMENTSOF(scenarios); ++i) {
+ log_info("scenario #%zu:, expected result %i", i, scenarios[i].expected_result);
+ log_info("%s", scenarios[i].contents);
+ rewind(f);
+ ftruncate(fd, 0);
+ assert_se(write_string_stream(f, scenarios[i].contents, false) == 0);
+ assert_se(clock_is_localtime(adjtime) == scenarios[i].expected_result);
+ }
+
+ unlink(adjtime);
+}
+
+/* Test with the real /etc/adjtime */
+static void test_clock_is_localtime_system(void) {
+ int r;
+ r = clock_is_localtime(NULL);
+
+ if (access("/etc/adjtime", F_OK) == 0) {
+ log_info("/etc/adjtime exists, clock_is_localtime() == %i", r);
+ /* if /etc/adjtime exists we expect some answer, no error or
+ * crash */
+ assert_se(r == 0 || r == 1);
+ } else
+ /* default is UTC if there is no /etc/adjtime */
+ assert_se(r == 0);
+}
+
+int main(int argc, char *argv[]) {
+ test_clock_is_localtime();
+ test_clock_is_localtime_system();
+
+ return 0;
+}
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index b3a4c40339..be5d2611f8 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -215,6 +215,14 @@ static void test_config_parse_nsec(void) {
test_config_parse_nsec_one("garbage", 0);
}
+static void test_config_parse_iec_uint64(void) {
+ uint64_t offset = 0;
+ assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0);
+ assert_se(offset == 4 * 1024 * 1024);
+
+ assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0);
+}
+
int main(int argc, char **argv) {
log_parse_environment();
log_open();
@@ -230,6 +238,7 @@ int main(int argc, char **argv) {
test_config_parse_mode();
test_config_parse_sec();
test_config_parse_nsec();
+ test_config_parse_iec_uint64();
return 0;
}
diff --git a/src/test/test-copy.c b/src/test/test-copy.c
index ad57cb0202..68154fc4e8 100644
--- a/src/test/test-copy.c
+++ b/src/test/test-copy.c
@@ -24,6 +24,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "log.h"
#include "macro.h"
#include "mkdir.h"
#include "path-util.h"
@@ -39,6 +40,8 @@ static void test_copy_file(void) {
size_t sz = 0;
int fd;
+ log_info("%s", __func__);
+
fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC);
assert_se(fd >= 0);
close(fd);
@@ -66,6 +69,8 @@ static void test_copy_file_fd(void) {
char text[] = "boohoo\nfoo\n\tbar\n";
char buf[64] = {0};
+ log_info("%s", __func__);
+
in_fd = mkostemp_safe(in_fn, O_RDWR);
assert_se(in_fd >= 0);
out_fd = mkostemp_safe(out_fn, O_RDWR);
@@ -90,31 +95,43 @@ static void test_copy_tree(void) {
char **links = STRV_MAKE("link", "file",
"link2", "dir1/file");
char **p, **link;
+ const char *unixsockp;
+ struct stat st;
+
+ log_info("%s", __func__);
(void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
STRV_FOREACH(p, files) {
- char *f = strjoina(original_dir, *p);
+ _cleanup_free_ char *f;
+
+ assert_se(f = strappend(original_dir, *p));
assert_se(mkdir_parents(f, 0755) >= 0);
assert_se(write_string_file(f, "file", WRITE_STRING_FILE_CREATE) == 0);
}
STRV_FOREACH_PAIR(link, p, links) {
- char *f = strjoina(original_dir, *p);
- char *l = strjoina(original_dir, *link);
+ _cleanup_free_ char *f, *l;
+
+ assert_se(f = strappend(original_dir, *p));
+ assert_se(l = strappend(original_dir, *link));
assert_se(mkdir_parents(l, 0755) >= 0);
assert_se(symlink(f, l) == 0);
}
+ unixsockp = strjoina(original_dir, "unixsock");
+ assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
+
assert_se(copy_tree(original_dir, copy_dir, true) == 0);
STRV_FOREACH(p, files) {
- _cleanup_free_ char *buf = NULL;
+ _cleanup_free_ char *buf = NULL, *f;
size_t sz = 0;
- char *f = strjoina(copy_dir, *p);
+
+ assert_se(f = strappend(copy_dir, *p));
assert_se(access(f, F_OK) == 0);
assert_se(read_full_file(f, &buf, &sz) == 0);
@@ -122,14 +139,19 @@ static void test_copy_tree(void) {
}
STRV_FOREACH_PAIR(link, p, links) {
- _cleanup_free_ char *target = NULL;
- char *f = strjoina(original_dir, *p);
- char *l = strjoina(copy_dir, *link);
+ _cleanup_free_ char *target = NULL, *f, *l;
+
+ assert_se(f = strjoin(original_dir, *p, NULL));
+ assert_se(l = strjoin(copy_dir, *link, NULL));
assert_se(readlink_and_canonicalize(l, &target) == 0);
assert_se(path_equal(f, target));
}
+ unixsockp = strjoina(copy_dir, "unixsock");
+ assert_se(stat(unixsockp, &st) >= 0);
+ assert_se(S_ISSOCK(st.st_mode));
+
assert_se(copy_tree(original_dir, copy_dir, false) < 0);
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
@@ -173,11 +195,65 @@ static void test_copy_bytes(void) {
assert_se(r == -EBADF);
}
+static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint64_t max_bytes) {
+ char fn2[] = "/tmp/test-copy-file-XXXXXX";
+ char fn3[] = "/tmp/test-copy-file-XXXXXX";
+ _cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1;
+ int r;
+ struct stat buf, buf2, buf3;
+
+ log_info("%s try_reflink=%s max_bytes=%" PRIu64, __func__, yes_no(try_reflink), max_bytes);
+
+ fd = open(src, O_RDONLY | O_CLOEXEC | O_NOCTTY);
+ assert_se(fd >= 0);
+
+ fd2 = mkostemp_safe(fn2, O_RDWR);
+ assert_se(fd2 >= 0);
+
+ fd3 = mkostemp_safe(fn3, O_WRONLY);
+ assert_se(fd3 >= 0);
+
+ r = copy_bytes(fd, fd2, max_bytes, try_reflink);
+ if (max_bytes == (uint64_t) -1)
+ assert_se(r == 0);
+ else
+ assert_se(IN_SET(r, 0, 1));
+
+ assert_se(lseek(fd2, 0, SEEK_SET) == 0);
+
+ r = copy_bytes(fd2, fd3, max_bytes, try_reflink);
+ if (max_bytes == (uint64_t) -1)
+ assert_se(r == 0);
+ else
+ /* We cannot distinguish between the input being exactly max_bytes
+ * or longer than max_bytes (without trying to read one more byte,
+ * or calling stat, or FION_READ, etc, and we don't want to do any
+ * of that). So we expect "truncation" since we know that file we
+ * are copying is exactly max_bytes bytes. */
+ assert_se(r == 1);
+
+ assert_se(fstat(fd, &buf) == 0);
+ assert_se(fstat(fd2, &buf2) == 0);
+ assert_se(fstat(fd3, &buf3) == 0);
+
+ assert_se((uint64_t) buf2.st_size == MIN((uint64_t) buf.st_size, max_bytes));
+ assert_se(buf3.st_size == buf2.st_size);
+
+ unlink(fn2);
+ unlink(fn3);
+}
+
int main(int argc, char *argv[]) {
test_copy_file();
test_copy_file_fd();
test_copy_tree();
test_copy_bytes();
+ test_copy_bytes_regular_file(argv[0], false, (uint64_t) -1);
+ test_copy_bytes_regular_file(argv[0], true, (uint64_t) -1);
+ test_copy_bytes_regular_file(argv[0], false, 1000); /* smaller than copy buffer size */
+ test_copy_bytes_regular_file(argv[0], true, 1000);
+ test_copy_bytes_regular_file(argv[0], false, 32000); /* larger than copy buffer size */
+ test_copy_bytes_regular_file(argv[0], true, 32000);
return 0;
}
diff --git a/src/test/test-cpu-set-util.c b/src/test/test-cpu-set-util.c
new file mode 100644
index 0000000000..8818d1ffb7
--- /dev/null
+++ b/src/test/test-cpu-set-util.c
@@ -0,0 +1,143 @@
+/***
+ 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 "cpu-set-util.h"
+#include "macro.h"
+
+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_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));
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
+ c = mfree(c);
+
+ /* A more interesting range */
+ 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);
+
+ /* Quoted strings */
+ 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++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Use commas as separators */
+ ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 4; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Commas with spaces (and trailing comma, space) */
+ ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 8; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Ranges */
+ ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 4; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Ranges with trailing comma, space */
+ ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
+ for (cpu = 0; cpu < 4; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 8; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Negative range (returns empty cpu_set) */
+ ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
+ c = mfree(c);
+
+ /* Overlapping ranges */
+ ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
+ for (cpu = 0; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Mix ranges and individual CPUs */
+ ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus >= 1024);
+ assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
+ assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
+ assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
+ for (cpu = 4; cpu < 12; cpu++)
+ assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
+ c = mfree(c);
+
+ /* Garbage */
+ ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus < 0);
+ assert_se(!c);
+
+ /* Range with garbage */
+ ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus < 0);
+ assert_se(!c);
+
+ /* Empty string */
+ c = NULL;
+ ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
+ assert_se(ncpus == 0); /* empty string returns 0 */
+ assert_se(!c);
+
+ /* Runnaway quoted string */
+ 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);
+}
+
+int main(int argc, char *argv[]) {
+ test_parse_cpu_set();
+
+ return 0;
+}
diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c
index d181bee214..b2cd3c7663 100644
--- a/src/test/test-daemon.c
+++ b/src/test/test-daemon.c
@@ -38,27 +38,27 @@ int main(int argc, char*argv[]) {
sd_notify(0,
"STATUS=Starting up");
- sleep(5);
+ sleep(1);
sd_notify(0,
"STATUS=Running\n"
"READY=1");
- sleep(5);
+ sleep(1);
sd_notify(0,
"STATUS=Reloading\n"
"RELOADING=1");
- sleep(5);
+ sleep(1);
sd_notify(0,
"STATUS=Running\n"
"READY=1");
- sleep(5);
+ sleep(1);
sd_notify(0,
"STATUS=Quitting\n"
"STOPPING=1");
- sleep(5);
+ sleep(1);
return EXIT_SUCCESS;
}
diff --git a/src/test/test-engine.c b/src/test/test-engine.c
index ca66f5b684..23da10fa1a 100644
--- a/src/test/test-engine.c
+++ b/src/test/test-engine.c
@@ -23,9 +23,12 @@
#include "bus-util.h"
#include "manager.h"
+#include "rm-rf.h"
#include "test-helper.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
Manager *m = NULL;
Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL;
@@ -34,9 +37,11 @@ int main(int argc, char *argv[]) {
Job *j;
int r;
+ assert_se(runtime_dir = setup_fake_runtime_dir());
+
/* prepare the test */
assert_se(set_unit_path(TEST_DIR) >= 0);
- r = manager_new(MANAGER_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, true, &m);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return EXIT_TEST_SKIP;
diff --git a/src/test/test-env-replace.c b/src/test/test-env-util.c
index 264acc6ea6..35bb62906e 100644
--- a/src/test/test-env-replace.c
+++ b/src/test/test-env-util.c
@@ -2,6 +2,7 @@
This file is part of systemd.
Copyright 2010 Lennart Poettering
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
@@ -177,10 +178,37 @@ static void test_env_name_is_valid(void) {
assert_se(!env_name_is_valid(NULL));
assert_se(!env_name_is_valid(""));
+ assert_se(!env_name_is_valid("xxx\a"));
+ assert_se(!env_name_is_valid("xxx\007b"));
+ assert_se(!env_name_is_valid("\007\009"));
assert_se(!env_name_is_valid("5_starting_with_a_number_is_wrong"));
assert_se(!env_name_is_valid("#¤%&?_only_numbers_letters_and_underscore_allowed"));
}
+static void test_env_value_is_valid(void) {
+ assert_se(env_value_is_valid(""));
+ assert_se(env_value_is_valid("głąb kapuściany"));
+ assert_se(env_value_is_valid("printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
+}
+
+static void test_env_assignment_is_valid(void) {
+ assert_se(env_assignment_is_valid("a="));
+ assert_se(env_assignment_is_valid("b=głąb kapuściany"));
+ assert_se(env_assignment_is_valid("c=\\007\\009\\011"));
+ assert_se(env_assignment_is_valid("e=printf \"\\x1b]0;<mock-chroot>\\x07<mock-chroot>\""));
+
+ assert_se(!env_assignment_is_valid("="));
+ assert_se(!env_assignment_is_valid("a b="));
+ assert_se(!env_assignment_is_valid("a ="));
+ assert_se(!env_assignment_is_valid(" b="));
+ /* no dots or dashes: http://tldp.org/LDP/abs/html/gotchas.html */
+ assert_se(!env_assignment_is_valid("a.b="));
+ assert_se(!env_assignment_is_valid("a-b="));
+ assert_se(!env_assignment_is_valid("\007=głąb kapuściany"));
+ assert_se(!env_assignment_is_valid("c\009=\007\009\011"));
+ assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\""));
+}
+
int main(int argc, char *argv[]) {
test_strv_env_delete();
test_strv_env_unset();
@@ -189,6 +217,8 @@ int main(int argc, char *argv[]) {
test_replace_env_arg();
test_env_clean();
test_env_name_is_valid();
+ test_env_value_is_valid();
+ test_env_assignment_is_valid();
return 0;
}
diff --git a/src/test/test-escape.c b/src/test/test-escape.c
new file mode 100644
index 0000000000..6cbb8443fe
--- /dev/null
+++ b/src/test/test-escape.c
@@ -0,0 +1,114 @@
+/***
+ 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 "macro.h"
+
+static void test_cescape(void) {
+ _cleanup_free_ char *escaped;
+
+ assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313"));
+ assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313"));
+}
+
+static void test_cunescape(void) {
+ _cleanup_free_ char *unescaped;
+
+ assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0);
+ assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00"));
+ unescaped = mfree(unescaped);
+
+ /* incomplete sequences */
+ assert_se(cunescape("\\x0", 0, &unescaped) < 0);
+ assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "\\x0"));
+ unescaped = mfree(unescaped);
+
+ assert_se(cunescape("\\x", 0, &unescaped) < 0);
+ assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "\\x"));
+ unescaped = mfree(unescaped);
+
+ assert_se(cunescape("\\", 0, &unescaped) < 0);
+ assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "\\"));
+ unescaped = mfree(unescaped);
+
+ assert_se(cunescape("\\11", 0, &unescaped) < 0);
+ assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "\\11"));
+ unescaped = mfree(unescaped);
+
+ assert_se(cunescape("\\1", 0, &unescaped) < 0);
+ assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "\\1"));
+ unescaped = mfree(unescaped);
+
+ assert_se(cunescape("\\u0000", 0, &unescaped) < 0);
+ assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, "ßßΠA"));
+ unescaped = mfree(unescaped);
+
+ assert_se(cunescape("\\073", 0, &unescaped) >= 0);
+ assert_se(streq_ptr(unescaped, ";"));
+}
+
+static void test_shell_escape_one(const char *s, const char *bad, const char *expected) {
+ _cleanup_free_ char *r;
+
+ assert_se(r = shell_escape(s, bad));
+ assert_se(streq_ptr(r, expected));
+}
+
+static void test_shell_escape(void) {
+ test_shell_escape_one("", "", "");
+ test_shell_escape_one("\\", "", "\\\\");
+ test_shell_escape_one("foobar", "", "foobar");
+ test_shell_escape_one("foobar", "o", "f\\o\\obar");
+ test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz");
+}
+
+static void test_shell_maybe_quote_one(const char *s, const char *expected) {
+ _cleanup_free_ char *r;
+
+ assert_se(r = shell_maybe_quote(s));
+ assert_se(streq(r, expected));
+}
+
+static void test_shell_maybe_quote(void) {
+
+ test_shell_maybe_quote_one("", "");
+ test_shell_maybe_quote_one("\\", "\"\\\\\"");
+ test_shell_maybe_quote_one("\"", "\"\\\"\"");
+ test_shell_maybe_quote_one("foobar", "foobar");
+ test_shell_maybe_quote_one("foo bar", "\"foo bar\"");
+ test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\"");
+ test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
+}
+
+int main(int argc, char *argv[]) {
+ test_cescape();
+ test_cunescape();
+ test_shell_escape();
+ test_shell_maybe_quote();
+
+ return 0;
+}
diff --git a/src/test/test-execute.c b/src/test/test-execute.c
index 92857cb5e2..77ef4e8b2a 100644
--- a/src/test/test-execute.c
+++ b/src/test/test-execute.c
@@ -91,7 +91,7 @@ static void test_exec_personality(Manager *m) {
#elif defined(__s390__)
test(m, "exec-personality-s390.service", 0, CLD_EXITED);
-#else
+#elif defined(__i386__)
test(m, "exec-personality-x86.service", 0, CLD_EXITED);
#endif
}
@@ -130,18 +130,33 @@ static void test_exec_systemcallerrornumber(Manager *m) {
#endif
}
+static void test_exec_systemcall_system_mode_with_user(Manager *m) {
+#ifdef HAVE_SECCOMP
+ if (getpwnam("nobody"))
+ test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
+ else if (getpwnam("nfsnobody"))
+ test(m, "exec-systemcallfilter-system-user-nfsnobody.service", 0, CLD_EXITED);
+ else
+ log_error_errno(errno, "Skipping test_exec_systemcall_system_mode_with_user, could not find nobody/nfsnobody user: %m");
+#endif
+}
+
static void test_exec_user(Manager *m) {
if (getpwnam("nobody"))
test(m, "exec-user.service", 0, CLD_EXITED);
+ else if (getpwnam("nfsnobody"))
+ test(m, "exec-user-nfsnobody.service", 0, CLD_EXITED);
else
- log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m");
+ log_error_errno(errno, "Skipping test_exec_user, could not find nobody/nfsnobody user: %m");
}
static void test_exec_group(Manager *m) {
if (getgrnam("nobody"))
test(m, "exec-group.service", 0, CLD_EXITED);
+ else if (getgrnam("nfsnobody"))
+ test(m, "exec-group-nfsnobody.service", 0, CLD_EXITED);
else
- log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m");
+ log_error_errno(errno, "Skipping test_exec_group, could not find nobody/nfsnobody group: %m");
}
static void test_exec_environment(Manager *m) {
@@ -204,8 +219,10 @@ static void test_exec_runtimedirectory(Manager *m) {
test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
if (getgrnam("nobody"))
test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+ else if (getgrnam("nfsnobody"))
+ test(m, "exec-runtimedirectory-owner-nfsnobody.service", 0, CLD_EXITED);
else
- log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m");
+ log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody/nfsnobody group: %m");
}
static void test_exec_capabilityboundingset(Manager *m) {
@@ -234,9 +251,16 @@ static void test_exec_capabilityambientset(Manager *m) {
* in the first place for the tests. */
r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
if (r >= 0 || errno != EINVAL) {
- test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
- test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
- }
+ if (getpwnam("nobody")) {
+ test(m, "exec-capabilityambientset.service", 0, CLD_EXITED);
+ test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED);
+ } else if (getpwnam("nfsnobody")) {
+ test(m, "exec-capabilityambientset-nfsnobody.service", 0, CLD_EXITED);
+ test(m, "exec-capabilityambientset-merge-nfsnobody.service", 0, CLD_EXITED);
+ } else
+ log_error_errno(errno, "Skipping test_exec_capabilityambientset, could not find nobody/nfsnobody user: %m");
+ } else
+ log_error_errno(errno, "Skipping test_exec_capabilityambientset, the kernel does not support ambient capabilities: %m");
}
static void test_exec_privatenetwork(Manager *m) {
@@ -263,8 +287,35 @@ static void test_exec_ioschedulingclass(Manager *m) {
test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
}
+static void test_exec_spec_interpolation(Manager *m) {
+ test(m, "exec-spec-interpolation.service", 0, CLD_EXITED);
+}
+
+static int run_tests(UnitFileScope scope, test_function_t *tests) {
+ test_function_t *test = NULL;
+ Manager *m = NULL;
+ int r;
+
+ assert_se(tests);
+
+ r = manager_new(scope, true, &m);
+ if (MANAGER_SKIP_TEST(r)) {
+ printf("Skipping test: manager_new: %s\n", strerror(-r));
+ return EXIT_TEST_SKIP;
+ }
+ assert_se(r >= 0);
+ assert_se(manager_startup(m, NULL, NULL) >= 0);
+
+ for (test = tests; test && *test; test++)
+ (*test)(m);
+
+ manager_free(m);
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
- test_function_t tests[] = {
+ test_function_t user_tests[] = {
test_exec_workingdirectory,
test_exec_personality,
test_exec_ignoresigpipe,
@@ -284,10 +335,13 @@ int main(int argc, char *argv[]) {
test_exec_capabilityambientset,
test_exec_oomscoreadjust,
test_exec_ioschedulingclass,
+ test_exec_spec_interpolation,
+ NULL,
+ };
+ test_function_t system_tests[] = {
+ test_exec_systemcall_system_mode_with_user,
NULL,
};
- test_function_t *test = NULL;
- Manager *m = NULL;
int r;
log_parse_environment();
@@ -312,18 +366,9 @@ int main(int argc, char *argv[]) {
assert_se(unsetenv("VAR2") == 0);
assert_se(unsetenv("VAR3") == 0);
- r = manager_new(MANAGER_USER, true, &m);
- if (MANAGER_SKIP_TEST(r)) {
- printf("Skipping test: manager_new: %s\n", strerror(-r));
- return EXIT_TEST_SKIP;
- }
- assert_se(r >= 0);
- assert_se(manager_startup(m, NULL, NULL) >= 0);
-
- for (test = tests; test && *test; test++)
- (*test)(m);
+ r = run_tests(UNIT_FILE_USER, user_tests);
+ if (r != 0)
+ return r;
- manager_free(m);
-
- return 0;
+ return run_tests(UNIT_FILE_SYSTEM, system_tests);
}
diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c
new file mode 100644
index 0000000000..421d3bdeb3
--- /dev/null
+++ b/src/test/test-fd-util.c
@@ -0,0 +1,103 @@
+/***
+ 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 <unistd.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "macro.h"
+
+static void test_close_many(void) {
+ int fds[3];
+ char name0[] = "/tmp/test-close-many.XXXXXX";
+ char name1[] = "/tmp/test-close-many.XXXXXX";
+ char name2[] = "/tmp/test-close-many.XXXXXX";
+
+ fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC);
+ fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC);
+ fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC);
+
+ close_many(fds, 2);
+
+ assert_se(fcntl(fds[0], F_GETFD) == -1);
+ assert_se(fcntl(fds[1], F_GETFD) == -1);
+ assert_se(fcntl(fds[2], F_GETFD) >= 0);
+
+ safe_close(fds[2]);
+
+ unlink(name0);
+ unlink(name1);
+ unlink(name2);
+}
+
+static void test_close_nointr(void) {
+ char name[] = "/tmp/test-test-close_nointr.XXXXXX";
+ int fd;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ assert_se(close_nointr(fd) >= 0);
+ assert_se(close_nointr(fd) < 0);
+
+ unlink(name);
+}
+
+static void test_same_fd(void) {
+ _cleanup_close_pair_ int p[2] = { -1, -1 };
+ _cleanup_close_ int a = -1, b = -1, c = -1;
+
+ assert_se(pipe2(p, O_CLOEXEC) >= 0);
+ assert_se((a = dup(p[0])) >= 0);
+ assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0);
+ assert_se((c = dup(a)) >= 0);
+
+ assert_se(same_fd(p[0], p[0]) > 0);
+ assert_se(same_fd(p[1], p[1]) > 0);
+ assert_se(same_fd(a, a) > 0);
+ assert_se(same_fd(b, b) > 0);
+
+ assert_se(same_fd(a, p[0]) > 0);
+ assert_se(same_fd(p[0], a) > 0);
+ assert_se(same_fd(c, p[0]) > 0);
+ assert_se(same_fd(p[0], c) > 0);
+ assert_se(same_fd(a, c) > 0);
+ assert_se(same_fd(c, a) > 0);
+
+ assert_se(same_fd(p[0], p[1]) == 0);
+ assert_se(same_fd(p[1], p[0]) == 0);
+ assert_se(same_fd(p[0], b) == 0);
+ assert_se(same_fd(b, p[0]) == 0);
+ assert_se(same_fd(p[1], a) == 0);
+ assert_se(same_fd(a, p[1]) == 0);
+ assert_se(same_fd(p[1], b) == 0);
+ assert_se(same_fd(b, p[1]) == 0);
+
+ assert_se(same_fd(a, b) == 0);
+ assert_se(same_fd(b, a) == 0);
+}
+
+int main(int argc, char *argv[]) {
+ test_close_many();
+ test_close_nointr();
+ test_same_fd();
+
+ return 0;
+}
diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c
index 5586a2d6c1..79609765e0 100644
--- a/src/test/test-fileio.c
+++ b/src/test/test-fileio.c
@@ -27,6 +27,7 @@
#include "env-util.h"
#include "fd-util.h"
#include "fileio.h"
+#include "io-util.h"
#include "parse-util.h"
#include "process-util.h"
#include "string-util.h"
@@ -288,7 +289,7 @@ static void test_capeff(void) {
assert_se(r == 0);
assert_se(*capeff);
- p = capeff[strspn(capeff, DIGITS "abcdefABCDEF")];
+ p = capeff[strspn(capeff, HEXDIGITS)];
assert_se(!p || isspace(p));
}
}
@@ -425,6 +426,134 @@ static void test_load_env_file_pairs(void) {
unlink(fn);
}
+static void test_search_and_fopen(void) {
+ const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
+ char name[] = "/tmp/test-search_and_fopen.XXXXXX";
+ int fd = -1;
+ int r;
+ FILE *f;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ close(fd);
+
+ r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
+ assert_se(r >= 0);
+ fclose(f);
+
+ r = search_and_fopen(name, "r", NULL, dirs, &f);
+ assert_se(r >= 0);
+ fclose(f);
+
+ r = search_and_fopen(basename(name), "r", "/", dirs, &f);
+ assert_se(r >= 0);
+ fclose(f);
+
+ r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
+ assert_se(r < 0);
+ r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
+ assert_se(r < 0);
+
+ r = unlink(name);
+ assert_se(r == 0);
+
+ r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
+ assert_se(r < 0);
+}
+
+
+static void test_search_and_fopen_nulstr(void) {
+ const char dirs[] = "/tmp/foo/bar\0/tmp\0";
+ char name[] = "/tmp/test-search_and_fopen.XXXXXX";
+ int fd = -1;
+ int r;
+ FILE *f;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ close(fd);
+
+ r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
+ assert_se(r >= 0);
+ fclose(f);
+
+ r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f);
+ assert_se(r >= 0);
+ fclose(f);
+
+ r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
+ assert_se(r < 0);
+ r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
+ assert_se(r < 0);
+
+ r = unlink(name);
+ assert_se(r == 0);
+
+ r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
+ assert_se(r < 0);
+}
+
+static void test_writing_tmpfile(void) {
+ char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
+ _cleanup_free_ char *contents = NULL;
+ size_t size;
+ int fd, r;
+ struct iovec iov[3];
+
+ IOVEC_SET_STRING(iov[0], "abc\n");
+ IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n");
+ IOVEC_SET_STRING(iov[2], "");
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ printf("tmpfile: %s", name);
+
+ r = writev(fd, iov, 3);
+ assert_se(r >= 0);
+
+ r = read_full_file(name, &contents, &size);
+ assert_se(r == 0);
+ printf("contents: %s", contents);
+ assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
+
+ unlink(name);
+}
+
+static void test_tempfn(void) {
+ char *ret = NULL, *p;
+
+ assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0);
+ assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX"));
+ free(ret);
+
+ assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0);
+ assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX"));
+ free(ret);
+
+ assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0);
+ assert_se(p = startswith(ret, "/foo/bar/.#waldo"));
+ assert_se(strlen(p) == 16);
+ assert_se(in_charset(p, "0123456789abcdef"));
+ free(ret);
+
+ assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0);
+ assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo"));
+ assert_se(strlen(p) == 16);
+ assert_se(in_charset(p, "0123456789abcdef"));
+ free(ret);
+
+ assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0);
+ assert_se(p = startswith(ret, "/foo/bar/waldo/.#"));
+ assert_se(strlen(p) == 16);
+ assert_se(in_charset(p, "0123456789abcdef"));
+ free(ret);
+
+ assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0);
+ assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]"));
+ assert_se(strlen(p) == 16);
+ assert_se(in_charset(p, "0123456789abcdef"));
+ free(ret);
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -439,6 +568,10 @@ int main(int argc, char *argv[]) {
test_write_string_file_no_create();
test_write_string_file_verify();
test_load_env_file_pairs();
+ test_search_and_fopen();
+ test_search_and_fopen_nulstr();
+ test_writing_tmpfile();
+ test_tempfn();
return 0;
}
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
new file mode 100644
index 0000000000..6db2c2b6f1
--- /dev/null
+++ b/src/test/test-fs-util.c
@@ -0,0 +1,91 @@
+/***
+ 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 <unistd.h>
+
+#include "alloc-util.h"
+#include "fileio.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "macro.h"
+#include "mkdir.h"
+#include "rm-rf.h"
+#include "string-util.h"
+#include "strv.h"
+#include "util.h"
+
+static void test_unlink_noerrno(void) {
+ char name[] = "/tmp/test-close_nointr.XXXXXX";
+ int fd;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ assert_se(close_nointr(fd) >= 0);
+
+ {
+ PROTECT_ERRNO;
+ errno = -42;
+ assert_se(unlink_noerrno(name) >= 0);
+ assert_se(errno == -42);
+ assert_se(unlink_noerrno(name) < 0);
+ assert_se(errno == -42);
+ }
+}
+
+static void test_readlink_and_make_absolute(void) {
+ char tempdir[] = "/tmp/test-readlink_and_make_absolute";
+ char name[] = "/tmp/test-readlink_and_make_absolute/original";
+ char name2[] = "test-readlink_and_make_absolute/original";
+ char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias";
+ char *r = NULL;
+
+ assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0);
+ assert_se(touch(name) >= 0);
+
+ assert_se(symlink(name, name_alias) >= 0);
+ assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
+ assert_se(streq(r, name));
+ free(r);
+ assert_se(unlink(name_alias) >= 0);
+
+ assert_se(chdir(tempdir) >= 0);
+ assert_se(symlink(name2, name_alias) >= 0);
+ assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
+ assert_se(streq(r, name));
+ free(r);
+ assert_se(unlink(name_alias) >= 0);
+
+ assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+}
+
+static void test_get_files_in_directory(void) {
+ _cleanup_strv_free_ char **l = NULL, **t = NULL;
+
+ assert_se(get_files_in_directory("/tmp", &l) >= 0);
+ assert_se(get_files_in_directory(".", &t) >= 0);
+ assert_se(get_files_in_directory(".", NULL) >= 0);
+}
+
+int main(int argc, char *argv[]) {
+ test_unlink_noerrno();
+ test_readlink_and_make_absolute();
+ test_get_files_in_directory();
+
+ return 0;
+}
diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c
index ea3d1a6909..63a4b8c243 100644
--- a/src/test/test-fstab-util.c
+++ b/src/test/test-fstab-util.c
@@ -131,8 +131,45 @@ static void test_fstab_yes_no_option(void) {
assert_se(fstab_test_yes_no_option("nofail,nofail=0,fail=0", "nofail\0fail\0") == false);
}
+static void test_fstab_node_to_udev_node(void) {
+ char *n;
+
+ n = fstab_node_to_udev_node("LABEL=applé/jack");
+ puts(n);
+ assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack"));
+ free(n);
+
+ n = fstab_node_to_udev_node("PARTLABEL=pinkié pie");
+ puts(n);
+ assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie"));
+ free(n);
+
+ n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535");
+ puts(n);
+ assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535"));
+ free(n);
+
+ n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535");
+ puts(n);
+ assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535"));
+ free(n);
+
+ n = fstab_node_to_udev_node("PONIES=awesome");
+ puts(n);
+ assert_se(streq(n, "PONIES=awesome"));
+ free(n);
+
+ n = fstab_node_to_udev_node("/dev/xda1");
+ puts(n);
+ assert_se(streq(n, "/dev/xda1"));
+ free(n);
+}
+
int main(void) {
test_fstab_filter_options();
test_fstab_find_pri();
test_fstab_yes_no_option();
+ test_fstab_node_to_udev_node();
+
+ return 0;
}
diff --git a/src/test/test-glob-util.c b/src/test/test-glob-util.c
new file mode 100644
index 0000000000..227d4290f0
--- /dev/null
+++ b/src/test/test-glob-util.c
@@ -0,0 +1,50 @@
+/***
+ 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 <unistd.h>
+
+#include "alloc-util.h"
+#include "fileio.h"
+#include "glob-util.h"
+#include "macro.h"
+
+static void test_glob_exists(void) {
+ char name[] = "/tmp/test-glob_exists.XXXXXX";
+ int fd = -1;
+ int r;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ close(fd);
+
+ r = glob_exists("/tmp/test-glob_exists*");
+ assert_se(r == 1);
+
+ r = unlink(name);
+ assert_se(r == 0);
+ r = glob_exists("/tmp/test-glob_exists*");
+ assert_se(r == 0);
+}
+
+int main(void) {
+ test_glob_exists();
+
+ return 0;
+}
diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c
index 6bf33306a9..1bd5c02f87 100644
--- a/src/test/test-hashmap-plain.c
+++ b/src/test/test-hashmap-plain.c
@@ -323,26 +323,29 @@ static void test_hashmap_remove_value(void) {
_cleanup_hashmap_free_ Hashmap *m = NULL;
char *r;
- r = hashmap_remove_value(NULL, "key 1", (void*) "val 1");
+ char val1[] = "val 1";
+ char val2[] = "val 2";
+
+ r = hashmap_remove_value(NULL, "key 1", val1);
assert_se(r == NULL);
m = hashmap_new(&string_hash_ops);
assert_se(m);
- r = hashmap_remove_value(m, "key 1", (void*) "val 1");
+ r = hashmap_remove_value(m, "key 1", val1);
assert_se(r == NULL);
- hashmap_put(m, "key 1", (void*) "val 1");
- hashmap_put(m, "key 2", (void*) "val 2");
+ hashmap_put(m, "key 1", val1);
+ hashmap_put(m, "key 2", val2);
- r = hashmap_remove_value(m, "key 1", (void*) "val 1");
+ r = hashmap_remove_value(m, "key 1", val1);
assert_se(streq(r, "val 1"));
r = hashmap_get(m, "key 2");
assert_se(streq(r, "val 2"));
assert_se(!hashmap_get(m, "key 1"));
- r = hashmap_remove_value(m, "key 2", (void*) "val 1");
+ r = hashmap_remove_value(m, "key 2", val1);
assert_se(r == NULL);
r = hashmap_get(m, "key 2");
diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c
new file mode 100644
index 0000000000..276f25d091
--- /dev/null
+++ b/src/test/test-hexdecoct.c
@@ -0,0 +1,387 @@
+/***
+ 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 "hexdecoct.h"
+#include "macro.h"
+#include "string-util.h"
+
+static void test_hexchar(void) {
+ assert_se(hexchar(0xa) == 'a');
+ assert_se(hexchar(0x0) == '0');
+}
+
+static void test_unhexchar(void) {
+ assert_se(unhexchar('a') == 0xA);
+ assert_se(unhexchar('A') == 0xA);
+ assert_se(unhexchar('0') == 0x0);
+}
+
+static void test_base32hexchar(void) {
+ assert_se(base32hexchar(0) == '0');
+ assert_se(base32hexchar(9) == '9');
+ assert_se(base32hexchar(10) == 'A');
+ assert_se(base32hexchar(31) == 'V');
+}
+
+static void test_unbase32hexchar(void) {
+ assert_se(unbase32hexchar('0') == 0);
+ assert_se(unbase32hexchar('9') == 9);
+ assert_se(unbase32hexchar('A') == 10);
+ assert_se(unbase32hexchar('V') == 31);
+ assert_se(unbase32hexchar('=') == -EINVAL);
+}
+
+static void test_base64char(void) {
+ assert_se(base64char(0) == 'A');
+ assert_se(base64char(26) == 'a');
+ assert_se(base64char(63) == '/');
+}
+
+static void test_unbase64char(void) {
+ assert_se(unbase64char('A') == 0);
+ assert_se(unbase64char('Z') == 25);
+ assert_se(unbase64char('a') == 26);
+ assert_se(unbase64char('z') == 51);
+ assert_se(unbase64char('0') == 52);
+ assert_se(unbase64char('9') == 61);
+ assert_se(unbase64char('+') == 62);
+ assert_se(unbase64char('/') == 63);
+ assert_se(unbase64char('=') == -EINVAL);
+}
+
+static void test_octchar(void) {
+ assert_se(octchar(00) == '0');
+ assert_se(octchar(07) == '7');
+}
+
+static void test_unoctchar(void) {
+ assert_se(unoctchar('0') == 00);
+ assert_se(unoctchar('7') == 07);
+}
+
+static void test_decchar(void) {
+ assert_se(decchar(0) == '0');
+ assert_se(decchar(9) == '9');
+}
+
+static void test_undecchar(void) {
+ assert_se(undecchar('0') == 0);
+ assert_se(undecchar('9') == 9);
+}
+
+static void test_unhexmem(void) {
+ const char *hex = "efa214921";
+ const char *hex_invalid = "efa214921o";
+ _cleanup_free_ char *hex2 = NULL;
+ _cleanup_free_ void *mem = NULL;
+ size_t len;
+
+ assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0);
+ assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL);
+ assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL);
+
+ assert_se((hex2 = hexmem(mem, len)));
+
+ free(mem);
+
+ assert_se(memcmp(hex, hex2, strlen(hex)) == 0);
+
+ free(hex2);
+
+ assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0);
+ assert_se((hex2 = hexmem(mem, len)));
+ assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0);
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-10 */
+static void test_base32hexmem(void) {
+ char *b32;
+
+ b32 = base32hexmem("", strlen(""), true);
+ assert_se(b32);
+ assert_se(streq(b32, ""));
+ free(b32);
+
+ b32 = base32hexmem("f", strlen("f"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CO======"));
+ free(b32);
+
+ b32 = base32hexmem("fo", strlen("fo"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNG===="));
+ free(b32);
+
+ b32 = base32hexmem("foo", strlen("foo"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMU==="));
+ free(b32);
+
+ b32 = base32hexmem("foob", strlen("foob"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOG="));
+ free(b32);
+
+ b32 = base32hexmem("fooba", strlen("fooba"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1"));
+ free(b32);
+
+ b32 = base32hexmem("foobar", strlen("foobar"), true);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1E8======"));
+ free(b32);
+
+ b32 = base32hexmem("", strlen(""), false);
+ assert_se(b32);
+ assert_se(streq(b32, ""));
+ free(b32);
+
+ b32 = base32hexmem("f", strlen("f"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CO"));
+ free(b32);
+
+ b32 = base32hexmem("fo", strlen("fo"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNG"));
+ free(b32);
+
+ b32 = base32hexmem("foo", strlen("foo"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMU"));
+ free(b32);
+
+ b32 = base32hexmem("foob", strlen("foob"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOG"));
+ free(b32);
+
+ b32 = base32hexmem("fooba", strlen("fooba"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1"));
+ free(b32);
+
+ b32 = base32hexmem("foobar", strlen("foobar"), false);
+ assert_se(b32);
+ assert_se(streq(b32, "CPNMUOJ1E8"));
+ free(b32);
+}
+
+static void test_unbase32hexmem(void) {
+ void *mem;
+ size_t len;
+
+ assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), ""));
+ free(mem);
+
+ assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "f"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foob"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fooba"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foobar"));
+ free(mem);
+
+ assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL);
+
+ assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
+
+ assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), ""));
+ free(mem);
+
+ assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "f"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foo"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foob"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fooba"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foobar"));
+ free(mem);
+
+ assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL);
+ assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL);
+}
+
+/* https://tools.ietf.org/html/rfc4648#section-10 */
+static void test_base64mem(void) {
+ char *b64;
+
+ assert_se(base64mem("", strlen(""), &b64) == 0);
+ assert_se(streq(b64, ""));
+ free(b64);
+
+ assert_se(base64mem("f", strlen("f"), &b64) == 4);
+ assert_se(streq(b64, "Zg=="));
+ free(b64);
+
+ assert_se(base64mem("fo", strlen("fo"), &b64) == 4);
+ assert_se(streq(b64, "Zm8="));
+ free(b64);
+
+ assert_se(base64mem("foo", strlen("foo"), &b64) == 4);
+ assert_se(streq(b64, "Zm9v"));
+ free(b64);
+
+ assert_se(base64mem("foob", strlen("foob"), &b64) == 8);
+ assert_se(streq(b64, "Zm9vYg=="));
+ free(b64);
+
+ assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8);
+ assert_se(streq(b64, "Zm9vYmE="));
+ free(b64);
+
+ assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8);
+ assert_se(streq(b64, "Zm9vYmFy"));
+ free(b64);
+}
+
+static void test_unbase64mem(void) {
+ void *mem;
+ size_t len;
+
+ assert_se(unbase64mem("", strlen(""), &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), ""));
+ free(mem);
+
+ assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "f"));
+ free(mem);
+
+ assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fo"));
+ free(mem);
+
+ assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foo"));
+ free(mem);
+
+ assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foob"));
+ free(mem);
+
+ assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "fooba"));
+ free(mem);
+
+ assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0);
+ assert_se(streq(strndupa(mem, len), "foobar"));
+ free(mem);
+
+ assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL);
+ assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL);
+ assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL);
+ assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL);
+}
+
+static void test_hexdump(void) {
+ uint8_t data[146];
+ unsigned i;
+
+ hexdump(stdout, NULL, 0);
+ hexdump(stdout, "", 0);
+ hexdump(stdout, "", 1);
+ hexdump(stdout, "x", 1);
+ hexdump(stdout, "x", 2);
+ hexdump(stdout, "foobar", 7);
+ hexdump(stdout, "f\nobar", 7);
+ hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23);
+
+ for (i = 0; i < ELEMENTSOF(data); i++)
+ data[i] = i*2;
+
+ hexdump(stdout, data, sizeof(data));
+}
+
+int main(int argc, char *argv[]) {
+ test_hexchar();
+ test_unhexchar();
+ test_base32hexchar();
+ test_unbase32hexchar();
+ test_base64char();
+ test_unbase64char();
+ test_octchar();
+ test_unoctchar();
+ test_decchar();
+ test_undecchar();
+ test_unhexmem();
+ test_base32hexmem();
+ test_unbase32hexmem();
+ test_base64mem();
+ test_unbase64mem();
+ test_hexdump();
+
+ return 0;
+}
diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c
index cd250ca7b8..4b9a74fca4 100644
--- a/src/test/test-install-root.c
+++ b/src/test/test-install-root.c
@@ -30,6 +30,8 @@ static void test_basic_mask_and_enable(const char *root) {
UnitFileChange *changes = NULL;
unsigned n_changes = 0;
+ log_set_max_level(LOG_DEBUG);
+
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT);
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT);
@@ -78,7 +80,7 @@ static void test_basic_mask_and_enable(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED);
/* Enabling a masked unit should fail! */
- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN);
+ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ERFKILL);
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
@@ -105,7 +107,7 @@ static void test_basic_mask_and_enable(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
/* Enabling it again should succeed but be a NOP */
- assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1);
+ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0);
assert_se(n_changes == 0);
unit_file_changes_free(changes, n_changes);
changes = NULL; n_changes = 0;
@@ -604,7 +606,7 @@ static void test_preset_and_list(const char *root) {
assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
assert_se(h = hashmap_new(&string_hash_ops));
- assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h) >= 0);
+ assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h, NULL, NULL) >= 0);
p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service");
q = strjoina(root, "/usr/lib/systemd/system/preset-no.service");
@@ -628,6 +630,104 @@ static void test_preset_and_list(const char *root) {
assert_se(got_yes && got_no);
}
+static void test_revert(const char *root) {
+ const char *p;
+ UnitFileState state;
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+
+ assert(root);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) == -ENOENT);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "yy.service", NULL) == -ENOENT);
+
+ p = strjoina(root, "/usr/lib/systemd/system/xx.service");
+ assert_se(write_string_file(p, "# Empty\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", NULL) >= 0);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "xx.service", &state) >= 0 && state == UNIT_FILE_STATIC);
+
+ /* Initially there's nothing to revert */
+ assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
+ assert_se(n_changes == 0);
+ unit_file_changes_free(changes, n_changes);
+ changes = NULL; n_changes = 0;
+
+ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service");
+ assert_se(write_string_file(p, "# Empty override\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ /* Revert the override file */
+ assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
+ assert_se(n_changes == 1);
+ assert_se(changes[0].type == UNIT_FILE_UNLINK);
+ assert_se(streq(changes[0].path, p));
+ unit_file_changes_free(changes, n_changes);
+ changes = NULL; n_changes = 0;
+
+ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d/dropin.conf");
+ assert_se(mkdir_parents(p, 0755) >= 0);
+ assert_se(write_string_file(p, "# Empty dropin\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ /* Revert the dropin file */
+ assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0);
+ assert_se(n_changes == 2);
+ assert_se(changes[0].type == UNIT_FILE_UNLINK);
+ assert_se(streq(changes[0].path, p));
+
+ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/xx.service.d");
+ assert_se(changes[1].type == UNIT_FILE_UNLINK);
+ assert_se(streq(changes[1].path, p));
+ unit_file_changes_free(changes, n_changes);
+ changes = NULL; n_changes = 0;
+}
+
+static void test_preset_order(const char *root) {
+ UnitFileChange *changes = NULL;
+ unsigned n_changes = 0;
+ const char *p;
+ UnitFileState state;
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) == -ENOENT);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) == -ENOENT);
+
+ p = strjoina(root, "/usr/lib/systemd/system/prefix-1.service");
+ assert_se(write_string_file(p,
+ "[Install]\n"
+ "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ p = strjoina(root, "/usr/lib/systemd/system/prefix-2.service");
+ assert_se(write_string_file(p,
+ "[Install]\n"
+ "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset");
+ assert_se(write_string_file(p,
+ "enable prefix-1.service\n"
+ "disable prefix-*.service\n"
+ "enable prefix-2.service\n", WRITE_STRING_FILE_CREATE) >= 0);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
+ assert_se(n_changes == 1);
+ assert_se(changes[0].type == UNIT_FILE_SYMLINK);
+ assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service"));
+ p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/prefix-1.service");
+ assert_se(streq(changes[0].path, p));
+ unit_file_changes_free(changes, n_changes);
+ changes = NULL; n_changes = 0;
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+
+ assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("prefix-2.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0);
+ assert_se(n_changes == 0);
+
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-1.service", &state) >= 0 && state == UNIT_FILE_ENABLED);
+ assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "prefix-2.service", &state) >= 0 && state == UNIT_FILE_DISABLED);
+}
+
int main(int argc, char *argv[]) {
char root[] = "/tmp/rootXXXXXX";
const char *p;
@@ -656,6 +756,8 @@ int main(int argc, char *argv[]) {
test_template_enable(root);
test_indirect(root);
test_preset_and_list(root);
+ test_preset_order(root);
+ test_revert(root);
assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
diff --git a/src/test/test-install.c b/src/test/test-install.c
index 874d617621..0ac85f040a 100644
--- a/src/test/test-install.c
+++ b/src/test/test-install.c
@@ -46,8 +46,11 @@ int main(int argc, char* argv[]) {
unsigned n_changes = 0;
UnitFileState state = 0;
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+
h = hashmap_new(&string_hash_ops);
- r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
+ r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
assert_se(r == 0);
HASHMAP_FOREACH(p, h, i) {
@@ -65,12 +68,12 @@ int main(int argc, char* argv[]) {
unit_file_list_free(h);
- log_error("enable");
+ log_info("/*** enable **/");
r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
- log_error("enable2");
+ log_info("/*** enable2 **/");
r = unit_file_enable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
@@ -82,8 +85,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
- log_error("disable");
-
+ log_info("/*** disable ***/");
changes = NULL;
n_changes = 0;
@@ -97,13 +99,13 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
- log_error("mask");
+ log_info("/*** mask ***/");
changes = NULL;
n_changes = 0;
r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
- log_error("mask2");
+ log_info("/*** mask2 ***/");
r = unit_file_mask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, false, &changes, &n_changes);
assert_se(r >= 0);
@@ -114,13 +116,13 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
- log_error("unmask");
+ log_info("/*** unmask ***/");
changes = NULL;
n_changes = 0;
r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
- log_error("unmask2");
+ log_info("/*** unmask2 ***/");
r = unit_file_unmask(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
@@ -131,7 +133,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
- log_error("mask");
+ log_info("/*** mask ***/");
changes = NULL;
n_changes = 0;
@@ -145,13 +147,13 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
- log_error("disable");
+ log_info("/*** disable ***/");
changes = NULL;
n_changes = 0;
r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
- log_error("disable2");
+ log_info("/*** disable2 ***/");
r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files, &changes, &n_changes);
assert_se(r >= 0);
@@ -162,7 +164,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_MASKED);
- log_error("umask");
+ log_info("/*** umask ***/");
changes = NULL;
n_changes = 0;
@@ -176,7 +178,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_DISABLED);
- log_error("enable files2");
+ log_info("/*** enable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -190,7 +192,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
- log_error("disable files2");
+ log_info("/*** disable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -203,7 +205,7 @@ int main(int argc, char* argv[]) {
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
- log_error("link files2");
+ log_info("/*** link files2 ***/");
changes = NULL;
n_changes = 0;
@@ -217,7 +219,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_LINKED);
- log_error("disable files2");
+ log_info("/*** disable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -230,7 +232,7 @@ int main(int argc, char* argv[]) {
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
- log_error("link files2");
+ log_info("/*** link files2 ***/");
changes = NULL;
n_changes = 0;
@@ -244,7 +246,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_LINKED);
- log_error("reenable files2");
+ log_info("/*** reenable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -258,7 +260,7 @@ int main(int argc, char* argv[]) {
assert_se(r >= 0);
assert_se(state == UNIT_FILE_ENABLED);
- log_error("disable files2");
+ log_info("/*** disable files2 ***/");
changes = NULL;
n_changes = 0;
@@ -270,7 +272,7 @@ int main(int argc, char* argv[]) {
r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state);
assert_se(r < 0);
- log_error("preset files");
+ log_info("/*** preset files ***/");
changes = NULL;
n_changes = 0;
diff --git a/src/test/test-io-util.c b/src/test/test-io-util.c
new file mode 100644
index 0000000000..10bd3833bc
--- /dev/null
+++ b/src/test/test-io-util.c
@@ -0,0 +1,69 @@
+/***
+ 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 <stdlib.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "macro.h"
+
+static void test_sparse_write_one(int fd, const char *buffer, size_t n) {
+ char check[n];
+
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(ftruncate(fd, 0) >= 0);
+ assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n);
+
+ assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n);
+ assert_se(ftruncate(fd, n) >= 0);
+
+ assert_se(lseek(fd, 0, SEEK_SET) == 0);
+ assert_se(read(fd, check, n) == (ssize_t) n);
+
+ assert_se(memcmp(buffer, check, n) == 0);
+}
+
+static void test_sparse_write(void) {
+ const char test_a[] = "test";
+ const char test_b[] = "\0\0\0\0test\0\0\0\0";
+ const char test_c[] = "\0\0test\0\0\0\0";
+ const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0";
+ const char test_e[] = "test\0\0\0\0test";
+ _cleanup_close_ int fd = -1;
+ char fn[] = "/tmp/sparseXXXXXX";
+
+ fd = mkostemp(fn, O_CLOEXEC);
+ assert_se(fd >= 0);
+ unlink(fn);
+
+ test_sparse_write_one(fd, test_a, sizeof(test_a));
+ test_sparse_write_one(fd, test_b, sizeof(test_b));
+ test_sparse_write_one(fd, test_c, sizeof(test_c));
+ test_sparse_write_one(fd, test_d, sizeof(test_d));
+ test_sparse_write_one(fd, test_e, sizeof(test_e));
+}
+
+int main(void) {
+ test_sparse_write();
+
+ return 0;
+}
diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c
index 2464d32458..c5bcaf47bb 100644
--- a/src/test/test-ipcrm.c
+++ b/src/test/test-ipcrm.c
@@ -23,9 +23,14 @@
int main(int argc, char *argv[]) {
uid_t uid;
-
- assert_se(argc == 2);
- assert_se(parse_uid(argv[1], &uid) >= 0);
+ int r;
+ const char* name = argv[1] ?: "nfsnobody";
+
+ r = get_user_creds(&name, &uid, NULL, NULL, NULL);
+ if (r < 0) {
+ log_error_errno(r, "Failed to resolve \"%s\": %m", name);
+ return EXIT_FAILURE;
+ }
return clean_ipc(uid) < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/test/test-json.c b/src/test/test-json.c
deleted file mode 100644
index 3fe2f58d04..0000000000
--- a/src/test/test-json.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <math.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;
- va_list ap;
-
- va_start(ap, data);
-
- for (;;) {
- _cleanup_free_ char *str = NULL;
- union json_value v = {};
- int t, tt;
-
- t = json_tokenize(&data, &str, &v, &state, NULL);
- tt = va_arg(ap, int);
-
- assert_se(t == tt);
-
- if (t == JSON_END || t < 0)
- break;
-
- else if (t == JSON_STRING) {
- const char *nn;
-
- nn = va_arg(ap, const char *);
- assert_se(streq_ptr(nn, str));
-
- } else if (t == JSON_REAL) {
- double d;
-
- d = va_arg(ap, double);
- assert_se(fabs(d - v.real) < 0.001);
-
- } else if (t == JSON_INTEGER) {
- intmax_t i;
-
- i = va_arg(ap, intmax_t);
- assert_se(i == v.integer);
-
- } else if (t == JSON_BOOLEAN) {
- bool b;
-
- b = va_arg(ap, int);
- assert_se(b == v.boolean);
- }
- }
-
- va_end(ap);
-}
-
-typedef void (*Test)(JsonVariant *);
-
-static void test_file(const char *data, Test test) {
- _cleanup_json_variant_unref_ JsonVariant *v = NULL;
- int r;
-
- r = json_parse(data, &v);
- assert_se(r == 0);
- assert_se(v != NULL);
- assert_se(v->type == JSON_VARIANT_OBJECT);
-
- if (test)
- test(v);
-}
-
-static void test_1(JsonVariant *v) {
- JsonVariant *p, *q;
- unsigned i;
-
- /* 3 keys + 3 values */
- assert_se(v->size == 6);
-
- /* has k */
- p = json_variant_value(v, "k");
- assert_se(p && p->type == JSON_VARIANT_STRING);
-
- /* k equals v */
- assert_se(streq(json_variant_string(p), "v"));
-
- /* has foo */
- p = json_variant_value(v, "foo");
- assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 3);
-
- /* check foo[0] = 1, foo[1] = 2, foo[2] = 3 */
- for (i = 0; i < 3; ++i) {
- q = json_variant_element(p, i);
- assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == (i+1));
- }
-
- /* has bar */
- p = json_variant_value(v, "bar");
- assert_se(p && p->type == JSON_VARIANT_OBJECT && p->size == 2);
-
- /* zap is null */
- q = json_variant_value(p, "zap");
- assert_se(q && q->type == JSON_VARIANT_NULL);
-}
-
-static void test_2(JsonVariant *v) {
- JsonVariant *p, *q;
-
- /* 2 keys + 2 values */
- assert_se(v->size == 4);
-
- /* has mutant */
- p = json_variant_value(v, "mutant");
- assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 4);
-
- /* mutant[0] == 1 */
- q = json_variant_element(p, 0);
- assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1);
-
- /* mutant[1] == null */
- q = json_variant_element(p, 1);
- assert_se(q && q->type == JSON_VARIANT_NULL);
-
- /* mutant[2] == "1" */
- q = json_variant_element(p, 2);
- assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1"));
-
- /* mutant[3] == JSON_VARIANT_OBJECT */
- q = json_variant_element(p, 3);
- assert_se(q && q->type == JSON_VARIANT_OBJECT && q->size == 2);
-
- /* has 1 */
- p = json_variant_value(q, "1");
- assert_se(p && p->type == JSON_VARIANT_ARRAY && p->size == 2);
-
- /* "1"[0] == 1 */
- q = json_variant_element(p, 0);
- assert_se(q && q->type == JSON_VARIANT_INTEGER && json_variant_integer(q) == 1);
-
- /* "1"[1] == "1" */
- q = json_variant_element(p, 1);
- assert_se(q && q->type == JSON_VARIANT_STRING && streq(json_variant_string(q), "1"));
-
- /* has blah */
- p = json_variant_value(v, "blah");
- assert_se(p && p->type == JSON_VARIANT_REAL && fabs(json_variant_real(p) - 1.27) < 0.001);
-}
-
-int main(int argc, char *argv[]) {
-
- test_one("x", -EINVAL);
- test_one("", JSON_END);
- test_one(" ", JSON_END);
- test_one("0", JSON_INTEGER, (intmax_t) 0, JSON_END);
- test_one("1234", JSON_INTEGER, (intmax_t) 1234, JSON_END);
- test_one("3.141", JSON_REAL, 3.141, JSON_END);
- test_one("0.0", JSON_REAL, 0.0, JSON_END);
- test_one("7e3", JSON_REAL, 7e3, JSON_END);
- test_one("-7e-3", JSON_REAL, -7e-3, JSON_END);
- test_one("true", JSON_BOOLEAN, true, JSON_END);
- test_one("false", JSON_BOOLEAN, false, JSON_END);
- test_one("null", JSON_NULL, JSON_END);
- test_one("{}", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END);
- test_one("\t {\n} \n", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END);
- test_one("[]", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END);
- test_one("\t [] \n\n", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END);
- test_one("\"\"", JSON_STRING, "", JSON_END);
- test_one("\"foo\"", JSON_STRING, "foo", JSON_END);
- test_one("\"foo\\nfoo\"", JSON_STRING, "foo\nfoo", JSON_END);
- test_one("{\"foo\" : \"bar\"}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_STRING, "bar", JSON_OBJECT_CLOSE, JSON_END);
- test_one("{\"foo\" : [true, false]}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_ARRAY_OPEN, JSON_BOOLEAN, true, JSON_COMMA, JSON_BOOLEAN, false, JSON_ARRAY_CLOSE, JSON_OBJECT_CLOSE, JSON_END);
- test_one("\"\xef\xbf\xbd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END);
- test_one("\"\\ufffd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END);
- test_one("\"\\uf\"", -EINVAL);
- test_one("\"\\ud800a\"", -EINVAL);
- test_one("\"\\udc00\\udc00\"", -EINVAL);
- test_one("\"\\ud801\\udc37\"", JSON_STRING, "\xf0\x90\x90\xb7", JSON_END);
-
- test_one("[1, 2]", JSON_ARRAY_OPEN, JSON_INTEGER, (intmax_t) 1, JSON_COMMA, JSON_INTEGER, (intmax_t) 2, JSON_ARRAY_CLOSE, JSON_END);
-
- test_file("{\"k\": \"v\", \"foo\": [1, 2, 3], \"bar\": {\"zap\": null}}", test_1);
- test_file("{\"mutant\": [1, null, \"1\", {\"1\": [1, \"1\"]}], \"blah\": 1.27}", test_2);
-
- return 0;
-}
diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c
index a7eb60e8cf..e28de9b37b 100644
--- a/src/test/test-libudev.c
+++ b/src/test/test-libudev.c
@@ -24,170 +24,140 @@
#include "libudev.h"
+#include "fd-util.h"
+#include "log.h"
#include "stdio-util.h"
#include "string-util.h"
#include "udev-util.h"
#include "util.h"
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-
static void print_device(struct udev_device *device) {
const char *str;
dev_t devnum;
int count;
struct udev_list_entry *list_entry;
- printf("*** device: %p ***\n", device);
+ log_info("*** device: %p ***", device);
str = udev_device_get_action(device);
if (str != NULL)
- printf("action: '%s'\n", str);
+ log_info("action: '%s'", str);
str = udev_device_get_syspath(device);
- printf("syspath: '%s'\n", str);
+ log_info("syspath: '%s'", str);
str = udev_device_get_sysname(device);
- printf("sysname: '%s'\n", str);
+ log_info("sysname: '%s'", str);
str = udev_device_get_sysnum(device);
if (str != NULL)
- printf("sysnum: '%s'\n", str);
+ log_info("sysnum: '%s'", str);
str = udev_device_get_devpath(device);
- printf("devpath: '%s'\n", str);
+ log_info("devpath: '%s'", str);
str = udev_device_get_subsystem(device);
if (str != NULL)
- printf("subsystem: '%s'\n", str);
+ log_info("subsystem: '%s'", str);
str = udev_device_get_devtype(device);
if (str != NULL)
- printf("devtype: '%s'\n", str);
+ log_info("devtype: '%s'", str);
str = udev_device_get_driver(device);
if (str != NULL)
- printf("driver: '%s'\n", str);
+ log_info("driver: '%s'", str);
str = udev_device_get_devnode(device);
if (str != NULL)
- printf("devname: '%s'\n", str);
+ log_info("devname: '%s'", str);
devnum = udev_device_get_devnum(device);
if (major(devnum) > 0)
- printf("devnum: %u:%u\n", major(devnum), minor(devnum));
+ log_info("devnum: %u:%u", major(devnum), minor(devnum));
count = 0;
udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
- printf("link: '%s'\n", udev_list_entry_get_name(list_entry));
+ log_info("link: '%s'", udev_list_entry_get_name(list_entry));
count++;
}
if (count > 0)
- printf("found %i links\n", count);
+ log_info("found %i links", count);
count = 0;
udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) {
- printf("property: '%s=%s'\n",
+ log_info("property: '%s=%s'",
udev_list_entry_get_name(list_entry),
udev_list_entry_get_value(list_entry));
count++;
}
if (count > 0)
- printf("found %i properties\n", count);
+ log_info("found %i properties", count);
str = udev_device_get_property_value(device, "MAJOR");
if (str != NULL)
- printf("MAJOR: '%s'\n", str);
+ log_info("MAJOR: '%s'", str);
str = udev_device_get_sysattr_value(device, "dev");
if (str != NULL)
- printf("attr{dev}: '%s'\n", str);
-
- printf("\n");
+ log_info("attr{dev}: '%s'", str);
}
-static int test_device(struct udev *udev, const char *syspath) {
+static void test_device(struct udev *udev, const char *syspath) {
_cleanup_udev_device_unref_ struct udev_device *device;
- printf("looking at device: %s\n", syspath);
+ log_info("looking at device: %s", syspath);
device = udev_device_new_from_syspath(udev, syspath);
- if (device == NULL) {
- printf("no device found\n");
- return -1;
- }
- print_device(device);
-
- return 0;
+ if (device == NULL)
+ log_warning_errno(errno, "udev_device_new_from_syspath: %m");
+ else
+ print_device(device);
}
-static int test_device_parents(struct udev *udev, const char *syspath) {
+static void test_device_parents(struct udev *udev, const char *syspath) {
_cleanup_udev_device_unref_ struct udev_device *device;
struct udev_device *device_parent;
- printf("looking at device: %s\n", syspath);
+ log_info("looking at device: %s", syspath);
device = udev_device_new_from_syspath(udev, syspath);
if (device == NULL)
- return -1;
+ return;
- printf("looking at parents\n");
+ log_info("looking at parents");
device_parent = device;
do {
print_device(device_parent);
device_parent = udev_device_get_parent(device_parent);
} while (device_parent != NULL);
- printf("looking at parents again\n");
+ log_info("looking at parents again");
device_parent = device;
do {
print_device(device_parent);
device_parent = udev_device_get_parent(device_parent);
} while (device_parent != NULL);
-
- return 0;
}
-static int test_device_devnum(struct udev *udev) {
+static void test_device_devnum(struct udev *udev) {
dev_t devnum = makedev(1, 3);
- struct udev_device *device;
+ _cleanup_udev_device_unref_ struct udev_device *device;
- printf("looking up device: %u:%u\n", major(devnum), minor(devnum));
+ log_info("looking up device: %u:%u", major(devnum), minor(devnum));
device = udev_device_new_from_devnum(udev, 'c', devnum);
if (device == NULL)
- return -1;
- print_device(device);
- udev_device_unref(device);
- return 0;
+ log_warning_errno(errno, "udev_device_new_from_devnum: %m");
+ else
+ print_device(device);
}
-static int test_device_subsys_name(struct udev *udev) {
- struct udev_device *device;
-
- printf("looking up device: 'block':'sda'\n");
- device = udev_device_new_from_subsystem_sysname(udev, "block", "sda");
- if (device == NULL)
- return -1;
- print_device(device);
- udev_device_unref(device);
-
- printf("looking up device: 'subsystem':'pci'\n");
- device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
- if (device == NULL)
- return -1;
- print_device(device);
- udev_device_unref(device);
-
- printf("looking up device: 'drivers':'scsi:sd'\n");
- device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd");
- if (device == NULL)
- return -1;
- print_device(device);
- udev_device_unref(device);
+static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) {
+ _cleanup_udev_device_unref_ struct udev_device *device;
- printf("looking up device: 'module':'printk'\n");
- device = udev_device_new_from_subsystem_sysname(udev, "module", "printk");
+ log_info("looking up device: '%s:%s'", subsys, dev);
+ device = udev_device_new_from_subsystem_sysname(udev, subsys, dev);
if (device == NULL)
- return -1;
- print_device(device);
- udev_device_unref(device);
- return 0;
+ log_warning_errno(errno, "udev_device_new_from_subsystem_sysname: %m");
+ else
+ print_device(device);
}
static int test_enumerate_print_list(struct udev_enumerate *enumerate) {
@@ -200,63 +170,45 @@ static int test_enumerate_print_list(struct udev_enumerate *enumerate) {
device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate),
udev_list_entry_get_name(list_entry));
if (device != NULL) {
- printf("device: '%s' (%s)\n",
- udev_device_get_syspath(device),
- udev_device_get_subsystem(device));
+ log_info("device: '%s' (%s)",
+ udev_device_get_syspath(device),
+ udev_device_get_subsystem(device));
udev_device_unref(device);
count++;
}
}
- printf("found %i devices\n\n", count);
+ log_info("found %i devices", count);
return count;
}
-static int test_monitor(struct udev *udev) {
- struct udev_monitor *udev_monitor = NULL;
- int fd_ep;
- int fd_udev = -1;
- struct epoll_event ep_udev, ep_stdin;
+static void test_monitor(struct udev *udev) {
+ _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor;
+ _cleanup_close_ int fd_ep;
+ int fd_udev;
+ struct epoll_event ep_udev = {
+ .events = EPOLLIN,
+ }, ep_stdin = {
+ .events = EPOLLIN,
+ .data.fd = STDIN_FILENO,
+ };
fd_ep = epoll_create1(EPOLL_CLOEXEC);
- if (fd_ep < 0) {
- printf("error creating epoll fd: %m\n");
- goto out;
- }
+ assert_se(fd_ep >= 0);
udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
- if (udev_monitor == NULL) {
- printf("no socket\n");
- goto out;
- }
+ assert_se(udev_monitor != NULL);
+
fd_udev = udev_monitor_get_fd(udev_monitor);
+ ep_udev.data.fd = fd_udev;
- if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 ||
- udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 ||
- udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) {
- printf("filter failed\n");
- goto out;
- }
+ assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) >= 0);
+ assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) >= 0);
+ assert_se(udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") >= 0);
- if (udev_monitor_enable_receiving(udev_monitor) < 0) {
- printf("bind failed\n");
- goto out;
- }
+ assert_se(udev_monitor_enable_receiving(udev_monitor) >= 0);
- memzero(&ep_udev, sizeof(struct epoll_event));
- ep_udev.events = EPOLLIN;
- ep_udev.data.fd = fd_udev;
- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
- printf("fail to add fd to epoll: %m\n");
- goto out;
- }
-
- memzero(&ep_stdin, sizeof(struct epoll_event));
- ep_stdin.events = EPOLLIN;
- ep_stdin.data.fd = STDIN_FILENO;
- if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) {
- printf("fail to add fd to epoll: %m\n");
- goto out;
- }
+ assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) >= 0);
+ assert_se(epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) >= 0);
for (;;) {
int fdcount;
@@ -265,7 +217,7 @@ static int test_monitor(struct udev *udev) {
int i;
printf("waiting for events from udev, press ENTER to exit\n");
- fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1);
+ fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
printf("epoll fd count: %i\n", fdcount);
for (i = 0; i < fdcount; i++) {
@@ -279,36 +231,29 @@ static int test_monitor(struct udev *udev) {
udev_device_unref(device);
} else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) {
printf("exiting loop\n");
- goto out;
+ return;
}
}
}
-out:
- if (fd_ep >= 0)
- close(fd_ep);
- udev_monitor_unref(udev_monitor);
- return 0;
}
-static int test_queue(struct udev *udev) {
+static void test_queue(struct udev *udev) {
struct udev_queue *udev_queue;
+ bool empty;
udev_queue = udev_queue_new(udev);
- if (udev_queue == NULL)
- return -1;
-
- if (udev_queue_get_queue_is_empty(udev_queue))
- printf("queue is empty\n");
+ assert_se(udev_queue);
+ empty = udev_queue_get_queue_is_empty(udev_queue);
+ log_info("queue is %s", empty ? "empty" : "not empty");
udev_queue_unref(udev_queue);
- return 0;
}
static int test_enumerate(struct udev *udev, const char *subsystem) {
struct udev_enumerate *udev_enumerate;
int r;
- printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem);
+ log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem);
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
@@ -317,7 +262,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
test_enumerate_print_list(udev_enumerate);
udev_enumerate_unref(udev_enumerate);
- printf("enumerate 'net' + duplicated scan + null + zero\n");
+ log_info("enumerate 'net' + duplicated scan + null + zero");
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
@@ -337,7 +282,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
test_enumerate_print_list(udev_enumerate);
udev_enumerate_unref(udev_enumerate);
- printf("enumerate 'block'\n");
+ log_info("enumerate 'block'");
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
@@ -351,7 +296,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
test_enumerate_print_list(udev_enumerate);
udev_enumerate_unref(udev_enumerate);
- printf("enumerate 'not block'\n");
+ log_info("enumerate 'not block'");
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
@@ -360,7 +305,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
test_enumerate_print_list(udev_enumerate);
udev_enumerate_unref(udev_enumerate);
- printf("enumerate 'pci, mem, vc'\n");
+ log_info("enumerate 'pci, mem, vc'");
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
@@ -371,7 +316,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
test_enumerate_print_list(udev_enumerate);
udev_enumerate_unref(udev_enumerate);
- printf("enumerate 'subsystem'\n");
+ log_info("enumerate 'subsystem'");
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
@@ -379,7 +324,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
test_enumerate_print_list(udev_enumerate);
udev_enumerate_unref(udev_enumerate);
- printf("enumerate 'property IF_FS_*=filesystem'\n");
+ log_info("enumerate 'property IF_FS_*=filesystem'");
udev_enumerate = udev_enumerate_new(udev);
if (udev_enumerate == NULL)
return -1;
@@ -397,32 +342,32 @@ static void test_hwdb(struct udev *udev, const char *modalias) {
hwdb = udev_hwdb_new(udev);
udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
- printf("'%s'='%s'\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
- printf("\n");
+ log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
hwdb = udev_hwdb_unref(hwdb);
assert_se(hwdb == NULL);
}
int main(int argc, char *argv[]) {
- struct udev *udev = NULL;
+ _cleanup_udev_unref_ struct udev *udev = NULL;
+ bool arg_monitor = false;
static const struct option options[] = {
- { "syspath", required_argument, NULL, 'p' },
+ { "syspath", required_argument, NULL, 'p' },
{ "subsystem", required_argument, NULL, 's' },
- { "debug", no_argument, NULL, 'd' },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, 'V' },
+ { "debug", no_argument, NULL, 'd' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, 'V' },
+ { "monitor", no_argument, NULL, 'm' },
{}
};
const char *syspath = "/devices/virtual/mem/null";
const char *subsystem = NULL;
- char path[1024];
int c;
udev = udev_new();
- printf("context: %p\n", udev);
+ log_info("context: %p", udev);
if (udev == NULL) {
- printf("no context\n");
+ log_info("no context");
return 1;
}
@@ -444,14 +389,18 @@ int main(int argc, char *argv[]) {
case 'h':
printf("--debug --syspath= --subsystem= --help\n");
- goto out;
+ return EXIT_SUCCESS;
case 'V':
printf("%s\n", VERSION);
- goto out;
+ return EXIT_SUCCESS;
+
+ case 'm':
+ arg_monitor = true;
+ break;
case '?':
- goto out;
+ return EXIT_FAILURE;
default:
assert_not_reached("Unhandled option code.");
@@ -459,14 +408,16 @@ int main(int argc, char *argv[]) {
/* add sys path if needed */
- if (!startswith(syspath, "/sys")) {
- xsprintf(path, "/sys/%s", syspath);
- syspath = path;
- }
+ if (!startswith(syspath, "/sys"))
+ syspath = strjoina("/sys/", syspath);
test_device(udev, syspath);
test_device_devnum(udev);
- test_device_subsys_name(udev);
+ test_device_subsys_name(udev, "block", "sda");
+ test_device_subsys_name(udev, "subsystem", "pci");
+ test_device_subsys_name(udev, "drivers", "scsi:sd");
+ test_device_subsys_name(udev, "module", "printk");
+
test_device_parents(udev, syspath);
test_enumerate(udev, subsystem);
@@ -475,8 +426,8 @@ int main(int argc, char *argv[]) {
test_hwdb(udev, "usb:v0D50p0011*");
- test_monitor(udev);
-out:
- udev_unref(udev);
- return 0;
+ if (arg_monitor)
+ test_monitor(udev);
+
+ return EXIT_SUCCESS;
}
diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c
index 2748395ade..7b67337331 100644
--- a/src/test/test-loopback.c
+++ b/src/test/test-loopback.c
@@ -31,7 +31,7 @@ int main(int argc, char* argv[]) {
r = loopback_setup();
if (r < 0)
- fprintf(stderr, "loopback: %s\n", strerror(-r));
+ log_error("loopback: %m");
- return 0;
+ return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c
index 0b2f9e9173..ff9f35cecd 100644
--- a/src/test/test-namespace.c
+++ b/src/test/test-namespace.c
@@ -69,8 +69,10 @@ static void test_netns(void) {
int r, n = 0;
siginfo_t si;
- if (geteuid() > 0)
- return;
+ if (geteuid() > 0) {
+ log_info("Skipping test: not root");
+ exit(EXIT_TEST_SKIP);
+ }
assert_se(socketpair(AF_UNIX, SOCK_DGRAM, 0, s) >= 0);
@@ -124,6 +126,9 @@ int main(int argc, char *argv[]) {
char boot_id[SD_ID128_STRING_MAX];
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *zz = NULL;
+ log_parse_environment();
+ log_open();
+
assert_se(sd_id128_get_boot(&bid) >= 0);
sd_id128_to_string(bid, boot_id);
diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c
index fe15a56aba..57e244eb79 100644
--- a/src/test/test-netlink-manual.c
+++ b/src/test/test-netlink-manual.c
@@ -68,10 +68,10 @@ static int test_tunnel_configure(sd_netlink *rtnl) {
/* skip test if module cannot be loaded */
r = load_module("ipip");
- if(r < 0)
+ if (r < 0)
return EXIT_TEST_SKIP;
- if(getuid() != 0)
+ if (getuid() != 0)
return EXIT_TEST_SKIP;
/* IPIP tunnel */
@@ -99,7 +99,7 @@ static int test_tunnel_configure(sd_netlink *rtnl) {
assert_se((m = sd_netlink_message_unref(m)) == NULL);
r = load_module("sit");
- if(r < 0)
+ if (r < 0)
return EXIT_TEST_SKIP;
/* sit */
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index cf627be6c5..9248f2987c 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -68,7 +68,6 @@ int main(int argc, char *argv[]) {
(char **) inaccessible,
tmp_dir,
var_tmp_dir,
- NULL,
true,
PROTECT_HOME_NO,
PROTECT_SYSTEM_NO,
diff --git a/src/test/test-nss.c b/src/test/test-nss.c
new file mode 100644
index 0000000000..55af592287
--- /dev/null
+++ b/src/test/test-nss.c
@@ -0,0 +1,454 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <net/if.h>
+
+#include "log.h"
+#include "nss-util.h"
+#include "path-util.h"
+#include "string-util.h"
+#include "alloc-util.h"
+#include "in-addr-util.h"
+#include "hexdecoct.h"
+#include "af-list.h"
+#include "stdio-util.h"
+#include "strv.h"
+#include "errno-list.h"
+#include "hostname-util.h"
+#include "local-addresses.h"
+
+static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) {
+ switch (status) {
+ case NSS_STATUS_TRYAGAIN:
+ return "NSS_STATUS_TRYAGAIN";
+ case NSS_STATUS_UNAVAIL:
+ return "NSS_STATUS_UNAVAIL";
+ case NSS_STATUS_NOTFOUND:
+ return "NSS_STATUS_NOTFOUND";
+ case NSS_STATUS_SUCCESS:
+ return "NSS_STATUS_SUCCESS";
+ case NSS_STATUS_RETURN:
+ return "NSS_STATUS_RETURN";
+ default:
+ snprintf(buf, buf_len, "%i", status);
+ return buf;
+ }
+};
+
+static const char* af_to_string(int family, char *buf, size_t buf_len) {
+ const char *name;
+
+ if (family == AF_UNSPEC)
+ return "*";
+
+ name = af_to_name(family);
+ if (name)
+ return name;
+
+ snprintf(buf, buf_len, "%i", family);
+ return buf;
+}
+
+static void* open_handle(const char* dir, const char* module, int flags) {
+ const char *path;
+ void *handle;
+
+ if (dir)
+ path = strjoina(dir, "/.libs/libnss_", module, ".so.2");
+ else
+ path = strjoina("libnss_", module, ".so.2");
+
+ handle = dlopen(path, flags);
+ assert_se(handle);
+ return handle;
+}
+
+static int print_gaih_addrtuples(const struct gaih_addrtuple *tuples) {
+ const struct gaih_addrtuple *it;
+ int n = 0;
+
+ for (it = tuples; it; it = it->next) {
+ _cleanup_free_ char *a = NULL;
+ union in_addr_union u;
+ int r;
+ char family_name[DECIMAL_STR_MAX(int)];
+ char ifname[IF_NAMESIZE];
+
+ memcpy(&u, it->addr, 16);
+ r = in_addr_to_string(it->family, &u, &a);
+ assert_se(r == 0 || r == -EAFNOSUPPORT);
+ if (r == -EAFNOSUPPORT)
+ assert_se((a = hexmem(it->addr, 16)));
+
+ if (it->scopeid == 0)
+ goto numerical_index;
+
+ if (if_indextoname(it->scopeid, ifname) == NULL) {
+ log_warning("if_indextoname(%d) failed: %m", it->scopeid);
+ numerical_index:
+ xsprintf(ifname, "%i", it->scopeid);
+ };
+
+ log_info(" \"%s\" %s %s %%%s",
+ it->name,
+ af_to_string(it->family, family_name, sizeof family_name),
+ a,
+ ifname);
+ n ++;
+ }
+ return n;
+}
+
+static void print_struct_hostent(struct hostent *host, const char *canon) {
+ char **s;
+
+ log_info(" \"%s\"", host->h_name);
+ STRV_FOREACH(s, host->h_aliases)
+ log_info(" alias \"%s\"", *s);
+ STRV_FOREACH(s, host->h_addr_list) {
+ union in_addr_union u;
+ _cleanup_free_ char *a = NULL;
+ char family_name[DECIMAL_STR_MAX(int)];
+ int r;
+
+ assert_se((unsigned) host->h_length == FAMILY_ADDRESS_SIZE(host->h_addrtype));
+ memcpy(&u, *s, host->h_length);
+ r = in_addr_to_string(host->h_addrtype, &u, &a);
+ assert_se(r == 0);
+ log_info(" %s %s",
+ af_to_string(host->h_addrtype, family_name, sizeof family_name),
+ a);
+ }
+ if (canon)
+ log_info(" canonical: \"%s\"", canon);
+}
+
+static void test_gethostbyname4_r(void *handle, const char *module, const char *name) {
+ const char *fname;
+ _nss_gethostbyname4_r_t f;
+ char buffer[2000];
+ struct gaih_addrtuple *pat = NULL;
+ int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+ int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
+ and will access this variable through *ttlp,
+ so we need to set it to something.
+ I'm not sure if this is a bug in nss-dns
+ or not. */
+ enum nss_status status;
+ char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+ int n;
+
+ fname = strjoina("_nss_", module, "_gethostbyname4_r");
+ f = dlsym(handle, fname);
+ log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+ assert_se(f);
+
+ status = f(name, &pat, buffer, sizeof buffer, &errno1, &errno2, &ttl);
+ if (status == NSS_STATUS_SUCCESS) {
+ log_info("%s(\"%s\") → status=%s%-20spat=buffer+0x%tx errno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
+ fname, name,
+ nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+ pat ? (char*) pat - buffer : 0,
+ errno1, errno_to_name(errno1) ?: "---",
+ errno2, hstrerror(errno2),
+ ttl);
+ n = print_gaih_addrtuples(pat);
+ } else {
+ log_info("%s(\"%s\") → status=%s%-20spat=0x%p errno=%d/%s h_errno=%d/%s",
+ fname, name,
+ nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+ pat,
+ errno1, errno_to_name(errno1) ?: "---",
+ errno2, hstrerror(errno2));
+ n = 0;
+ }
+
+ if (STR_IN_SET(module, "resolve", "mymachines") && status == NSS_STATUS_UNAVAIL)
+ return;
+
+ if (STR_IN_SET(module, "myhostname", "resolve") && streq(name, "localhost")) {
+ assert_se(status == NSS_STATUS_SUCCESS);
+ assert_se(n == 2);
+ }
+}
+
+
+static void test_gethostbyname3_r(void *handle, const char *module, const char *name, int af) {
+ const char *fname;
+ _nss_gethostbyname3_r_t f;
+ char buffer[2000];
+ int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+ int32_t ttl = INT32_MAX; /* nss-dns wants to return the lowest ttl,
+ and will access this variable through *ttlp,
+ so we need to set it to something.
+ I'm not sure if this is a bug in nss-dns
+ or not. */
+ enum nss_status status;
+ char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+ struct hostent host;
+ char *canon;
+ char family_name[DECIMAL_STR_MAX(int)];
+
+ fname = strjoina("_nss_", module, "_gethostbyname3_r");
+ f = dlsym(handle, fname);
+ log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+ assert_se(f);
+
+ status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl, &canon);
+ log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
+ fname, name, af_to_string(af, family_name, sizeof family_name),
+ nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+ errno1, errno_to_name(errno1) ?: "---",
+ errno2, hstrerror(errno2),
+ ttl);
+ if (status == NSS_STATUS_SUCCESS)
+ print_struct_hostent(&host, canon);
+}
+
+static void test_gethostbyname2_r(void *handle, const char *module, const char *name, int af) {
+ const char *fname;
+ _nss_gethostbyname2_r_t f;
+ char buffer[2000];
+ int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+ enum nss_status status;
+ char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+ struct hostent host;
+ char family_name[DECIMAL_STR_MAX(int)];
+
+ fname = strjoina("_nss_", module, "_gethostbyname2_r");
+ f = dlsym(handle, fname);
+ log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+ assert_se(f);
+
+ status = f(name, af, &host, buffer, sizeof buffer, &errno1, &errno2);
+ log_info("%s(\"%s\", %s) → status=%s%-20serrno=%d/%s h_errno=%d/%s",
+ fname, name, af_to_string(af, family_name, sizeof family_name),
+ nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+ errno1, errno_to_name(errno1) ?: "---",
+ errno2, hstrerror(errno2));
+ if (status == NSS_STATUS_SUCCESS)
+ print_struct_hostent(&host, NULL);
+}
+
+static void test_gethostbyname_r(void *handle, const char *module, const char *name) {
+ const char *fname;
+ _nss_gethostbyname_r_t f;
+ char buffer[2000];
+ int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+ enum nss_status status;
+ char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+ struct hostent host;
+
+ fname = strjoina("_nss_", module, "_gethostbyname_r");
+ f = dlsym(handle, fname);
+ log_debug("dlsym(0x%p, %s) → 0x%p", handle, fname, f);
+ assert_se(f);
+
+ status = f(name, &host, buffer, sizeof buffer, &errno1, &errno2);
+ log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
+ fname, name,
+ nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+ errno1, errno_to_name(errno1) ?: "---",
+ errno2, hstrerror(errno2));
+ if (status == NSS_STATUS_SUCCESS)
+ print_struct_hostent(&host, NULL);
+}
+
+static void test_gethostbyaddr2_r(void *handle,
+ const char *module,
+ const void* addr, socklen_t len,
+ int af) {
+
+ const char *fname;
+ _nss_gethostbyaddr2_r_t f;
+ char buffer[2000];
+ int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+ enum nss_status status;
+ char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+ struct hostent host;
+ int32_t ttl = INT32_MAX;
+ _cleanup_free_ char *addr_pretty = NULL;
+
+ fname = strjoina("_nss_", module, "_gethostbyaddr2_r");
+ f = dlsym(handle, fname);
+
+ log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno,
+ "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
+ if (!f)
+ return;
+
+ assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
+
+ status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2, &ttl);
+ log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s ttl=%"PRIi32,
+ fname, addr_pretty,
+ nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+ errno1, errno_to_name(errno1) ?: "---",
+ errno2, hstrerror(errno2),
+ ttl);
+ if (status == NSS_STATUS_SUCCESS)
+ print_struct_hostent(&host, NULL);
+}
+
+static void test_gethostbyaddr_r(void *handle,
+ const char *module,
+ const void* addr, socklen_t len,
+ int af) {
+
+ const char *fname;
+ _nss_gethostbyaddr_r_t f;
+ char buffer[2000];
+ int errno1 = 999, errno2 = 999; /* nss-dns doesn't set those */
+ enum nss_status status;
+ char pretty_status[DECIMAL_STR_MAX(enum nss_status)];
+ struct hostent host;
+ _cleanup_free_ char *addr_pretty = NULL;
+
+ fname = strjoina("_nss_", module, "_gethostbyaddr_r");
+ f = dlsym(handle, fname);
+
+ log_full_errno(f ? LOG_DEBUG : LOG_INFO, errno,
+ "dlsym(0x%p, %s) → 0x%p: %m", handle, fname, f);
+ if (!f)
+ return;
+
+ assert_se(in_addr_to_string(af, addr, &addr_pretty) >= 0);
+
+ status = f(addr, len, af, &host, buffer, sizeof buffer, &errno1, &errno2);
+ log_info("%s(\"%s\") → status=%s%-20serrno=%d/%s h_errno=%d/%s",
+ fname, addr_pretty,
+ nss_status_to_string(status, pretty_status, sizeof pretty_status), "\n",
+ errno1, errno_to_name(errno1) ?: "---",
+ errno2, hstrerror(errno2));
+ if (status == NSS_STATUS_SUCCESS)
+ print_struct_hostent(&host, NULL);
+}
+
+static void test_byname(void *handle, const char *module, const char *name) {
+ test_gethostbyname4_r(handle, module, name);
+ puts("");
+
+ test_gethostbyname3_r(handle, module, name, AF_INET);
+ puts("");
+ test_gethostbyname3_r(handle, module, name, AF_INET6);
+ puts("");
+ test_gethostbyname3_r(handle, module, name, AF_UNSPEC);
+ puts("");
+ test_gethostbyname3_r(handle, module, name, AF_LOCAL);
+ puts("");
+
+ test_gethostbyname2_r(handle, module, name, AF_INET);
+ puts("");
+ test_gethostbyname2_r(handle, module, name, AF_INET6);
+ puts("");
+ test_gethostbyname2_r(handle, module, name, AF_UNSPEC);
+ puts("");
+ test_gethostbyname2_r(handle, module, name, AF_LOCAL);
+ puts("");
+
+ test_gethostbyname_r(handle, module, name);
+ puts("");
+}
+
+static void test_byaddr(void *handle,
+ const char *module,
+ const void* addr, socklen_t len,
+ int af) {
+ test_gethostbyaddr2_r(handle, module, addr, len, af);
+ puts("");
+
+ test_gethostbyaddr_r(handle, module, addr, len, af);
+ puts("");
+}
+
+#ifdef HAVE_MYHOSTNAME
+# define MODULE1 "myhostname\0"
+#else
+# define MODULE1
+#endif
+#ifdef HAVE_RESOLVED
+# define MODULE2 "resolve\0"
+#else
+# define MODULE2
+#endif
+#ifdef HAVE_MACHINED
+# define MODULE3 "mymachines\0"
+#else
+# define MODULE3
+#endif
+#define MODULE4 "dns\0"
+
+int main(int argc, char **argv) {
+ _cleanup_free_ char *dir = NULL, *hostname = NULL;
+ const char *module;
+
+ const uint32_t local_address_ipv4 = htonl(0x7F000001);
+ const uint32_t local_address_ipv4_2 = htonl(0x7F000002);
+ _cleanup_free_ struct local_address *addresses = NULL;
+ int n_addresses;
+
+ log_set_max_level(LOG_INFO);
+ log_parse_environment();
+
+ dir = dirname_malloc(argv[0]);
+ assert_se(dir);
+
+ hostname = gethostname_malloc();
+ assert_se(hostname);
+
+ n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
+ if (n_addresses < 0) {
+ log_info_errno(n_addresses, "Failed to query local addresses: %m");
+ n_addresses = 0;
+ }
+
+ NULSTR_FOREACH(module, MODULE1 MODULE2 MODULE3 MODULE4) {
+ void *handle;
+ const char *name;
+ int i;
+
+ log_info("======== %s ========", module);
+
+ handle = open_handle(streq(module, "dns") ? NULL : dir,
+ module,
+ RTLD_LAZY|RTLD_NODELETE);
+ NULSTR_FOREACH(name, "localhost\0" "gateway\0" "foo_no_such_host\0")
+ test_byname(handle, module, name);
+
+ test_byname(handle, module, hostname);
+
+ test_byaddr(handle, module, &local_address_ipv4, sizeof local_address_ipv4, AF_INET);
+ test_byaddr(handle, module, &local_address_ipv4_2, sizeof local_address_ipv4_2, AF_INET);
+ test_byaddr(handle, module, &in6addr_loopback, sizeof in6addr_loopback, AF_INET6);
+
+ for (i = 0; i < n_addresses; i++)
+ test_byaddr(handle, module,
+ &addresses[i].address,
+ FAMILY_ADDRESS_SIZE(addresses[i].family),
+ addresses[i].family);
+
+ dlclose(handle);
+
+ log_info(" ");
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c
index 268da002a9..096326d176 100644
--- a/src/test/test-path-lookup.c
+++ b/src/test/test-path-lookup.c
@@ -26,41 +26,38 @@
#include "string-util.h"
#include "strv.h"
-static void test_paths(ManagerRunningAs running_as, bool personal) {
+static void test_paths(UnitFileScope scope) {
char template[] = "/tmp/test-path-lookup.XXXXXXX";
_cleanup_lookup_paths_free_ LookupPaths lp_without_env = {};
_cleanup_lookup_paths_free_ LookupPaths lp_with_env = {};
- char *exists, *not, *systemd_unit_path;
+ char *systemd_unit_path;
assert_se(mkdtemp(template));
- exists = strjoina(template, "/exists");
- assert_se(mkdir(exists, 0755) == 0);
- not = strjoina(template, "/not");
assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0);
- assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0);
-
- assert_se(!strv_isempty(lp_without_env.unit_path));
- assert_se(strv_contains(lp_without_env.unit_path, exists));
- assert_se(strv_contains(lp_without_env.unit_path, not));
+ assert_se(lookup_paths_init(&lp_without_env, scope, 0, NULL) >= 0);
+ assert_se(!strv_isempty(lp_without_env.search_path));
+ assert_se(lookup_paths_reduce(&lp_without_env) >= 0);
systemd_unit_path = strjoina(template, "/systemd-unit-path");
assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0);
- assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0);
- assert_se(strv_length(lp_with_env.unit_path) == 1);
- assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path));
+ assert_se(lookup_paths_init(&lp_with_env, scope, 0, NULL) == 0);
+ assert_se(strv_length(lp_with_env.search_path) == 1);
+ assert_se(streq(lp_with_env.search_path[0], systemd_unit_path));
+ assert_se(lookup_paths_reduce(&lp_with_env) >= 0);
+ assert_se(strv_length(lp_with_env.search_path) == 0);
assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
}
-static void print_generator_paths(ManagerRunningAs running_as) {
+static void print_generator_binary_paths(UnitFileScope scope) {
_cleanup_strv_free_ char **paths;
char **dir;
- log_info("Generators dirs (%s):", running_as == MANAGER_SYSTEM ? "system" : "user");
+ log_info("Generators dirs (%s):", scope == UNIT_FILE_SYSTEM ? "system" : "user");
- paths = generator_paths(running_as);
+ paths = generator_binary_paths(scope);
STRV_FOREACH(dir, paths)
log_info(" %s", *dir);
}
@@ -70,13 +67,12 @@ int main(int argc, char **argv) {
log_parse_environment();
log_open();
- test_paths(MANAGER_SYSTEM, false);
- test_paths(MANAGER_SYSTEM, true);
- test_paths(MANAGER_USER, false);
- test_paths(MANAGER_USER, true);
+ test_paths(UNIT_FILE_SYSTEM);
+ test_paths(UNIT_FILE_USER);
+ test_paths(UNIT_FILE_GLOBAL);
- print_generator_paths(MANAGER_SYSTEM);
- print_generator_paths(MANAGER_USER);
+ print_generator_binary_paths(UNIT_FILE_SYSTEM);
+ print_generator_binary_paths(UNIT_FILE_USER);
return EXIT_SUCCESS;
}
diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c
index 53a585290a..b53324b5e6 100644
--- a/src/test/test-path-util.c
+++ b/src/test/test-path-util.c
@@ -90,6 +90,18 @@ static void test_path(void) {
assert_se(path_equal(path_kill_slashes(p2), "/aaa/./ccc"));
assert_se(path_equal(path_kill_slashes(p3), "/./"));
}
+
+ assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
+ assert_se(PATH_IN_SET("/bin", "/bin"));
+ assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin"));
+ assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar"));
+ assert_se(!PATH_IN_SET("/", "/abc", "/def"));
+
+ assert_se(path_equal_ptr(NULL, NULL));
+ assert_se(path_equal_ptr("/a", "/a"));
+ assert_se(!path_equal_ptr("/a", "/b"));
+ assert_se(!path_equal_ptr("/a", NULL));
+ assert_se(!path_equal_ptr(NULL, "/a"));
}
static void test_find_binary(const char *self) {
@@ -433,6 +445,71 @@ static void test_path_is_mount_point(void) {
assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
}
+static void test_file_in_same_dir(void) {
+ char *t;
+
+ t = file_in_same_dir("/", "a");
+ assert_se(streq(t, "/a"));
+ free(t);
+
+ t = file_in_same_dir("/", "/a");
+ assert_se(streq(t, "/a"));
+ free(t);
+
+ t = file_in_same_dir("", "a");
+ assert_se(streq(t, "a"));
+ free(t);
+
+ t = file_in_same_dir("a/", "a");
+ assert_se(streq(t, "a/a"));
+ free(t);
+
+ t = file_in_same_dir("bar/foo", "bar");
+ assert_se(streq(t, "bar/bar"));
+ free(t);
+}
+
+static void test_filename_is_valid(void) {
+ char foo[FILENAME_MAX+2];
+ int i;
+
+ assert_se(!filename_is_valid(""));
+ assert_se(!filename_is_valid("/bar/foo"));
+ assert_se(!filename_is_valid("/"));
+ assert_se(!filename_is_valid("."));
+ assert_se(!filename_is_valid(".."));
+
+ for (i=0; i<FILENAME_MAX+1; i++)
+ foo[i] = 'a';
+ foo[FILENAME_MAX+1] = '\0';
+
+ assert_se(!filename_is_valid(foo));
+
+ assert_se(filename_is_valid("foo_bar-333"));
+ assert_se(filename_is_valid("o.o"));
+}
+
+static void test_hidden_or_backup_file(void) {
+ assert_se(hidden_or_backup_file(".hidden"));
+ assert_se(hidden_or_backup_file("..hidden"));
+ assert_se(!hidden_or_backup_file("hidden."));
+
+ assert_se(hidden_or_backup_file("backup~"));
+ assert_se(hidden_or_backup_file(".backup~"));
+
+ assert_se(hidden_or_backup_file("lost+found"));
+ assert_se(hidden_or_backup_file("aquota.user"));
+ assert_se(hidden_or_backup_file("aquota.group"));
+
+ assert_se(hidden_or_backup_file("test.rpmnew"));
+ assert_se(hidden_or_backup_file("test.dpkg-old"));
+ assert_se(hidden_or_backup_file("test.dpkg-remove"));
+ assert_se(hidden_or_backup_file("test.swp"));
+
+ assert_se(!hidden_or_backup_file("test.rpmnew."));
+ assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
+}
+
int main(int argc, char **argv) {
test_path();
test_find_binary(argv[0]);
@@ -444,6 +521,9 @@ int main(int argc, char **argv) {
test_path_startswith();
test_prefix_root();
test_path_is_mount_point();
+ test_file_in_same_dir();
+ test_filename_is_valid();
+ test_hidden_or_backup_file();
return 0;
}
diff --git a/src/test/test-path.c b/src/test/test-path.c
index 7a3b145414..62181e22a0 100644
--- a/src/test/test-path.c
+++ b/src/test/test-path.c
@@ -30,6 +30,7 @@
#include "string-util.h"
#include "strv.h"
#include "test-helper.h"
+#include "tests.h"
#include "unit.h"
#include "util.h"
@@ -44,7 +45,7 @@ static int setup_test(Manager **m) {
assert_se(m);
- r = manager_new(MANAGER_USER, true, &tmp);
+ r = manager_new(UNIT_FILE_USER, true, &tmp);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return -EXIT_TEST_SKIP;
@@ -93,7 +94,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con
ts = now(CLOCK_MONOTONIC);
/* We process events until the service related to the path has been successfully started */
- while(service->result != SERVICE_SUCCESS || service->state != SERVICE_START) {
+ while (service->result != SERVICE_SUCCESS || service->state != SERVICE_START) {
usec_t n;
int r;
@@ -243,7 +244,7 @@ static void test_path_makedirectory_directorymode(Manager *m) {
}
int main(int argc, char *argv[]) {
- test_function_t tests[] = {
+ static const test_function_t tests[] = {
test_path_exists,
test_path_existsglob,
test_path_changed,
@@ -253,12 +254,15 @@ int main(int argc, char *argv[]) {
test_path_makedirectory_directorymode,
NULL,
};
- test_function_t *test = NULL;
+
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
+ const test_function_t *test = NULL;
Manager *m = NULL;
log_parse_environment();
log_open();
+ assert_se(runtime_dir = setup_fake_runtime_dir());
assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0);
for (test = tests; test && *test; test++) {
diff --git a/src/test/test-proc-cmdline.c b/src/test/test-proc-cmdline.c
new file mode 100644
index 0000000000..a7a8f621a2
--- /dev/null
+++ b/src/test/test-proc-cmdline.c
@@ -0,0 +1,52 @@
+/***
+ 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 "log.h"
+#include "macro.h"
+#include "proc-cmdline.h"
+#include "special.h"
+#include "string-util.h"
+
+static int parse_item(const char *key, const char *value) {
+ assert_se(key);
+
+ log_info("kernel cmdline option <%s> = <%s>", key, strna(value));
+ return 0;
+}
+
+static void test_parse_proc_cmdline(void) {
+ assert_se(parse_proc_cmdline(parse_item) >= 0);
+}
+
+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(void) {
+ log_parse_environment();
+ log_open();
+
+ test_parse_proc_cmdline();
+ test_runlevel_to_target();
+
+ return 0;
+}
diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c
index 48be5a3a87..4616314200 100644
--- a/src/test/test-process-util.c
+++ b/src/test/test-process-util.c
@@ -18,12 +18,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <sys/personality.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "alloc-util.h"
+#include "architecture.h"
#include "log.h"
#include "macro.h"
#include "process-util.h"
@@ -128,6 +130,29 @@ static void test_pid_is_alive(void) {
assert_se(!pid_is_alive(-1));
}
+static void test_personality(void) {
+
+ assert_se(personality_to_string(PER_LINUX));
+ assert_se(!personality_to_string(PERSONALITY_INVALID));
+
+ assert_se(streq(personality_to_string(PER_LINUX), architecture_to_string(native_architecture())));
+
+ assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX);
+ assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX);
+
+#ifdef __x86_64__
+ assert_se(streq_ptr(personality_to_string(PER_LINUX), "x86-64"));
+ assert_se(streq_ptr(personality_to_string(PER_LINUX32), "x86"));
+
+ assert_se(personality_from_string("x86-64") == PER_LINUX);
+ assert_se(personality_from_string("x86") == PER_LINUX32);
+ assert_se(personality_from_string("ia64") == PERSONALITY_INVALID);
+ assert_se(personality_from_string(NULL) == PERSONALITY_INVALID);
+
+ assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32);
+#endif
+}
+
int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
@@ -135,6 +160,7 @@ int main(int argc, char *argv[]) {
test_get_process_comm();
test_pid_is_unwaited();
test_pid_is_alive();
+ test_personality();
return 0;
}
diff --git a/src/test/test-rbtree.c b/src/test/test-rbtree.c
deleted file mode 100644
index 8ae416c557..0000000000
--- a/src/test/test-rbtree.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/***
- This file is part of systemd. See COPYING for details.
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-/*
- * Tests for RB-Tree
- */
-
-#undef NDEBUG
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include "c-rbtree.h"
-
-/* verify that all API calls are exported */
-static void test_api(void) {
- CRBTree t = {};
- CRBNode n = C_RBNODE_INIT(n);
-
- assert(!c_rbnode_is_linked(&n));
-
- /* init, is_linked, add, remove, remove_init */
-
- c_rbtree_add(&t, NULL, &t.root, &n);
- assert(c_rbnode_is_linked(&n));
-
- c_rbtree_remove_init(&t, &n);
- assert(!c_rbnode_is_linked(&n));
-
- c_rbtree_add(&t, NULL, &t.root, &n);
- assert(c_rbnode_is_linked(&n));
-
- c_rbtree_remove(&t, &n);
- assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */
-
- c_rbnode_init(&n);
- assert(!c_rbnode_is_linked(&n));
-
- /* first, last, leftmost, rightmost, next, prev */
-
- assert(!c_rbtree_first(&t));
- assert(!c_rbtree_last(&t));
- assert(&n == c_rbnode_leftmost(&n));
- assert(&n == c_rbnode_rightmost(&n));
- assert(!c_rbnode_next(&n));
- assert(!c_rbnode_prev(&n));
-}
-
-/* copied from c-rbtree.c, relies on internal representation */
-static inline _Bool c_rbnode_is_red(CRBNode *n) {
- return !((unsigned long)n->__parent_and_color & 1UL);
-}
-
-/* copied from c-rbtree.c, relies on internal representation */
-static inline _Bool c_rbnode_is_black(CRBNode *n) {
- return !!((unsigned long)n->__parent_and_color & 1UL);
-}
-
-static size_t validate(CRBTree *t) {
- unsigned int i_black, n_black;
- CRBNode *n, *p, *o;
- size_t count = 0;
-
- assert(t);
- assert(!t->root || c_rbnode_is_black(t->root));
-
- /* traverse to left-most child, count black nodes */
- i_black = 0;
- n = t->root;
- while (n && n->left) {
- if (c_rbnode_is_black(n))
- ++i_black;
- n = n->left;
- }
- n_black = i_black;
-
- /*
- * Traverse tree and verify correctness:
- * 1) A node is either red or black
- * 2) The root is black
- * 3) All leaves are black
- * 4) Every red node must have two black child nodes
- * 5) Every path to a leaf contains the same number of black nodes
- *
- * Note that NULL nodes are considered black, which is why we don't
- * check for 3).
- */
- o = NULL;
- while (n) {
- ++count;
-
- /* verify natural order */
- assert(n > o);
- o = n;
-
- /* verify consistency */
- assert(!n->right || c_rbnode_parent(n->right) == n);
- assert(!n->left || c_rbnode_parent(n->left) == n);
-
- /* verify 2) */
- if (!c_rbnode_parent(n))
- assert(c_rbnode_is_black(n));
-
- if (c_rbnode_is_red(n)) {
- /* verify 4) */
- assert(!n->left || c_rbnode_is_black(n->left));
- assert(!n->right || c_rbnode_is_black(n->right));
- } else {
- /* verify 1) */
- assert(c_rbnode_is_black(n));
- }
-
- /* verify 5) */
- if (!n->left && !n->right)
- assert(i_black == n_black);
-
- /* get next node */
- if (n->right) {
- n = n->right;
- if (c_rbnode_is_black(n))
- ++i_black;
-
- while (n->left) {
- n = n->left;
- if (c_rbnode_is_black(n))
- ++i_black;
- }
- } else {
- while ((p = c_rbnode_parent(n)) && n == p->right) {
- n = p;
- if (c_rbnode_is_black(p->right))
- --i_black;
- }
-
- n = p;
- if (p && c_rbnode_is_black(p->left))
- --i_black;
- }
- }
-
- return count;
-}
-
-static void insert(CRBTree *t, CRBNode *n) {
- CRBNode **i, *p;
-
- assert(t);
- assert(n);
- assert(!c_rbnode_is_linked(n));
-
- i = &t->root;
- p = NULL;
- while (*i) {
- p = *i;
- if (n < *i) {
- i = &(*i)->left;
- } else {
- assert(n > *i);
- i = &(*i)->right;
- }
- }
-
- c_rbtree_add(t, p, i, n);
-}
-
-static void shuffle(void **nodes, size_t n_memb) {
- unsigned int i, j;
- void *t;
-
- for (i = 0; i < n_memb; ++i) {
- j = rand() % n_memb;
- t = nodes[j];
- nodes[j] = nodes[i];
- nodes[i] = t;
- }
-}
-
-/* run some pseudo-random tests on the tree */
-static void test_shuffle(void) {
- CRBNode *nodes[256];
- CRBTree t = {};
- unsigned int i, j;
- size_t n;
-
- /* allocate and initialize all nodes */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- nodes[i] = malloc(sizeof(*nodes[i]));
- assert(nodes[i]);
- c_rbnode_init(nodes[i]);
- }
-
- /* shuffle nodes and validate *empty* tree */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
- n = validate(&t);
- assert(n == 0);
-
- /* add all nodes and validate after each insertion */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- insert(&t, nodes[i]);
- n = validate(&t);
- assert(n == i + 1);
- }
-
- /* shuffle nodes again */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
- /* remove all nodes (in different order) and validate on each round */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- c_rbtree_remove(&t, nodes[i]);
- n = validate(&t);
- assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
- c_rbnode_init(nodes[i]);
- }
-
- /* shuffle nodes and validate *empty* tree again */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
- n = validate(&t);
- assert(n == 0);
-
- /* add all nodes again */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- insert(&t, nodes[i]);
- n = validate(&t);
- assert(n == i + 1);
- }
-
- /* 4 times, remove half of the nodes and add them again */
- for (j = 0; j < 4; ++j) {
- /* shuffle nodes again */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
- /* remove half of the nodes */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) {
- c_rbtree_remove(&t, nodes[i]);
- n = validate(&t);
- assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
- c_rbnode_init(nodes[i]);
- }
-
- /* shuffle the removed half */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes) / 2);
-
- /* add the removed half again */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) {
- insert(&t, nodes[i]);
- n = validate(&t);
- assert(n == sizeof(nodes) / sizeof(*nodes) / 2 + i + 1);
- }
- }
-
- /* shuffle nodes again */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
- /* remove all */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- c_rbtree_remove(&t, nodes[i]);
- n = validate(&t);
- assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1);
- c_rbnode_init(nodes[i]);
- }
-
- /* free nodes again */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i)
- free(nodes[i]);
-}
-
-typedef struct {
- unsigned long key;
- CRBNode rb;
-} Node;
-
-#define node_from_rb(_rb) ((Node *)((char *)(_rb) - offsetof(Node, rb)))
-
-static int compare(CRBTree *t, void *k, CRBNode *n) {
- unsigned long key = (unsigned long)k;
- Node *node = node_from_rb(n);
-
- return (key < node->key) ? -1 : (key > node->key) ? 1 : 0;
-}
-
-/* run tests against the c_rbtree_find*() helpers */
-static void test_map(void) {
- CRBNode **slot, *p;
- CRBTree t = {};
- Node *nodes[2048];
- unsigned long i;
-
- /* allocate and initialize all nodes */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- nodes[i] = malloc(sizeof(*nodes[i]));
- assert(nodes[i]);
- nodes[i]->key = i;
- c_rbnode_init(&nodes[i]->rb);
- }
-
- /* shuffle nodes */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
- /* add all nodes, and verify that each node is linked */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- assert(!c_rbnode_is_linked(&nodes[i]->rb));
- assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
-
- slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p);
- assert(slot);
- c_rbtree_add(&t, p, slot, &nodes[i]->rb);
-
- assert(c_rbnode_is_linked(&nodes[i]->rb));
- assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
- }
-
- /* shuffle nodes again */
- shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes));
-
- /* remove all nodes (in different order) */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) {
- assert(c_rbnode_is_linked(&nodes[i]->rb));
- assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
-
- c_rbtree_remove_init(&t, &nodes[i]->rb);
-
- assert(!c_rbnode_is_linked(&nodes[i]->rb));
- assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb));
- }
-
- /* free nodes again */
- for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i)
- free(nodes[i]);
-}
-
-int main(int argc, char **argv) {
- unsigned int i;
-
- /* we want stable tests, so use fixed seed */
- srand(0xdeadbeef);
-
- test_api();
-
- /*
- * The tests are pseudo random; run them multiple times, each run will
- * have different orders and thus different results.
- */
- for (i = 0; i < 4; ++i) {
- test_shuffle();
- test_map();
- }
-
- return 0;
-}
diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c
index d9ac9368cd..62afd2de5e 100644
--- a/src/test/test-rlimit-util.c
+++ b/src/test/test-rlimit-util.c
@@ -99,6 +99,18 @@ int main(int argc, char *argv[]) {
test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL);
test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL);
test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL);
+ test_rlimit_parse_format(RLIMIT_NICE, "20", 20, 20, 0, "20");
+ test_rlimit_parse_format(RLIMIT_NICE, "40", 40, 40, 0, "40");
+ test_rlimit_parse_format(RLIMIT_NICE, "41", 41, 41, -ERANGE, "41");
+ test_rlimit_parse_format(RLIMIT_NICE, "0", 0, 0, 0, "0");
+ test_rlimit_parse_format(RLIMIT_NICE, "-7", 27, 27, 0, "27");
+ test_rlimit_parse_format(RLIMIT_NICE, "-20", 40, 40, 0, "40");
+ test_rlimit_parse_format(RLIMIT_NICE, "-21", 41, 41, -ERANGE, "41");
+ test_rlimit_parse_format(RLIMIT_NICE, "-0", 20, 20, 0, "20");
+ test_rlimit_parse_format(RLIMIT_NICE, "+7", 13, 13, 0, "13");
+ test_rlimit_parse_format(RLIMIT_NICE, "+19", 1, 1, 0, "1");
+ test_rlimit_parse_format(RLIMIT_NICE, "+20", 0, 0, -ERANGE, "0");
+ test_rlimit_parse_format(RLIMIT_NICE, "+0", 20, 20, 0, "20");
return 0;
}
diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c
index 7f515b53d8..c068f5c39e 100644
--- a/src/test/test-sched-prio.c
+++ b/src/test/test-sched-prio.c
@@ -21,9 +21,12 @@
#include "macro.h"
#include "manager.h"
+#include "rm-rf.h"
#include "test-helper.h"
+#include "tests.h"
int main(int argc, char *argv[]) {
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
Manager *m = NULL;
Unit *idle_ok, *idle_bad, *rr_ok, *rr_bad, *rr_sched;
Service *ser;
@@ -31,9 +34,11 @@ int main(int argc, char *argv[]) {
FDSet *fdset = NULL;
int r;
+ assert_se(runtime_dir = setup_fake_runtime_dir());
+
/* prepare the test */
assert_se(set_unit_path(TEST_DIR) >= 0);
- r = manager_new(MANAGER_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, true, &m);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return EXIT_TEST_SKIP;
diff --git a/src/test/test-selinux.c b/src/test/test-selinux.c
new file mode 100644
index 0000000000..7545ad3764
--- /dev/null
+++ b/src/test/test-selinux.c
@@ -0,0 +1,122 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <sys/stat.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "selinux-util.h"
+#include "string-util.h"
+#include "time-util.h"
+#include "util.h"
+
+static void test_testing(void) {
+ bool b;
+
+ log_info("============ %s ==========", __func__);
+
+ b = mac_selinux_use();
+ log_info("mac_selinux_use → %s", yes_no(b));
+
+ b = mac_selinux_have();
+ log_info("mac_selinux_have → %s", yes_no(b));
+
+ mac_selinux_retest();
+
+ b = mac_selinux_use();
+ log_info("mac_selinux_use → %s", yes_no(b));
+
+ b = mac_selinux_have();
+ log_info("mac_selinux_have → %s", yes_no(b));
+}
+
+static void test_loading(void) {
+ usec_t n1, n2;
+ int r;
+
+ log_info("============ %s ==========", __func__);
+
+ n1 = now(CLOCK_MONOTONIC);
+ r = mac_selinux_init();
+ n2 = now(CLOCK_MONOTONIC);
+ log_info_errno(r, "mac_selinux_init → %d (%m) %.2fs", r, (n2 - n1)/1e6);
+}
+
+static void test_cleanup(void) {
+ usec_t n1, n2;
+
+ log_info("============ %s ==========", __func__);
+
+ n1 = now(CLOCK_MONOTONIC);
+ mac_selinux_finish();
+ n2 = now(CLOCK_MONOTONIC);
+ log_info("mac_selinux_finish → %.2fs", (n2 - n1)/1e6);
+}
+
+static void test_misc(const char* fname) {
+ _cleanup_(mac_selinux_freep) char *label = NULL, *label2 = NULL, *label3 = NULL;
+ int r;
+ _cleanup_close_ int fd = -1;
+
+ log_info("============ %s ==========", __func__);
+
+ r = mac_selinux_get_our_label(&label);
+ log_info_errno(r, "mac_selinux_get_our_label → %d (%m), \"%s\"",
+ r, strnull(label));
+
+ r = mac_selinux_get_create_label_from_exe(fname, &label2);
+ log_info_errno(r, "mac_selinux_create_label_from_exe → %d (%m), \"%s\"",
+ r, strnull(label2));
+
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ assert_se(fd >= 0);
+
+ r = mac_selinux_get_child_mls_label(fd, fname, label2, &label3);
+ log_info_errno(r, "mac_selinux_get_child_mls_label → %d (%m), \"%s\"",
+ r, strnull(label3));
+}
+
+static void test_create_file_prepare(const char* fname) {
+ int r;
+
+ log_info("============ %s ==========", __func__);
+
+ r = mac_selinux_create_file_prepare(fname, S_IRWXU);
+ log_info_errno(r, "mac_selinux_create_file_prepare → %d (%m)", r);
+
+ mac_selinux_create_file_clear();
+}
+
+int main(int argc, char **argv) {
+ const char *path = SYSTEMD_BINARY_PATH;
+ if (argc >= 2)
+ path = argv[1];
+
+ log_set_max_level(LOG_DEBUG);
+ log_parse_environment();
+
+ test_testing();
+ test_loading();
+ test_misc(path);
+ test_create_file_prepare(path);
+ test_cleanup();
+
+ return 0;
+}
diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c
index 3083501ce9..671eb869cb 100644
--- a/src/test/test-signal-util.c
+++ b/src/test/test-signal-util.c
@@ -17,6 +17,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <signal.h>
+#include <unistd.h>
+
+#include "macro.h"
#include "signal-util.h"
static void test_block_signals(void) {
@@ -44,6 +48,20 @@ static void test_block_signals(void) {
assert_se(sigismember(&ss, SIGVTALRM) == 0);
}
+static void test_ignore_signals(void) {
+ assert_se(ignore_signals(SIGINT, -1) >= 0);
+ assert_se(kill(getpid(), SIGINT) >= 0);
+ assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
+ assert_se(kill(getpid(), SIGUSR1) >= 0);
+ assert_se(kill(getpid(), SIGUSR2) >= 0);
+ assert_se(kill(getpid(), SIGTERM) >= 0);
+ assert_se(kill(getpid(), SIGPIPE) >= 0);
+ assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
+}
+
int main(int argc, char *argv[]) {
test_block_signals();
+ test_ignore_signals();
+
+ return 0;
}
diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c
index caae911f30..b74b7ad2dd 100644
--- a/src/test/test-siphash24.c
+++ b/src/test/test-siphash24.c
@@ -22,9 +22,9 @@
#define ITERATIONS 10000000ULL
-static int do_test(const uint8_t *in, size_t len, const uint8_t *key) {
+static void do_test(const uint8_t *in, size_t len, const uint8_t *key) {
struct siphash state = {};
- uint64_t out = 0;
+ uint64_t out;
unsigned i, j;
out = siphash24(in, len, key);
@@ -60,7 +60,46 @@ static int do_test(const uint8_t *in, size_t len, const uint8_t *key) {
assert_se(out == 0xa129ca6149be45e5);
}
}
- return 0;
+}
+
+static void test_short_hashes(void) {
+ const uint8_t one[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };
+ const uint8_t key[16] = { 0x22, 0x24, 0x41, 0x22, 0x55, 0x77, 0x88, 0x07,
+ 0x23, 0x09, 0x23, 0x14, 0x0c, 0x33, 0x0e, 0x0f};
+ uint8_t two[sizeof one] = {};
+
+ struct siphash state1 = {}, state2 = {};
+ unsigned i, j;
+
+ siphash24_init(&state1, key);
+ siphash24_init(&state2, key);
+
+ /* hashing 1, 2, 3, 4, 5, ..., 16 bytes, with the byte after the buffer different */
+ for (i = 1; i <= sizeof one; i++) {
+ siphash24_compress(one, i, &state1);
+
+ two[i-1] = one[i-1];
+ siphash24_compress(two, i, &state2);
+
+ assert_se(memcmp(&state1, &state2, sizeof state1) == 0);
+ }
+
+ /* hashing n and 1, n and 2, n and 3, ..., n-1 and 1, n-2 and 2, ... */
+ for (i = sizeof one; i > 0; i--) {
+ zero(two);
+
+ for (j = 1; j <= sizeof one; j++) {
+ siphash24_compress(one, i, &state1);
+ siphash24_compress(one, j, &state1);
+
+ siphash24_compress(one, i, &state2);
+ two[j-1] = one[j-1];
+ siphash24_compress(two, j, &state2);
+
+ assert_se(memcmp(&state1, &state2, sizeof state1) == 0);
+ }
+ }
}
/* see https://131002.net/siphash/siphash.pdf, Appendix A */
@@ -80,4 +119,6 @@ int main(int argc, char *argv[]) {
do_test(in_buf + 2, sizeof(in), key);
memcpy(in_buf + 4, in, sizeof(in));
do_test(in_buf + 4, sizeof(in), key);
+
+ test_short_hashes();
}
diff --git a/src/test/test-sizeof.c b/src/test/test-sizeof.c
new file mode 100644
index 0000000000..8f99a13772
--- /dev/null
+++ b/src/test/test-sizeof.c
@@ -0,0 +1,53 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2016 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "log.h"
+#include "time-util.h"
+
+/* Print information about various types. Useful when diagnosing
+ * gcc diagnostics on an unfamiliar architecture. */
+
+#pragma GCC diagnostic ignored "-Wtype-limits"
+
+#define info(t) \
+ log_info("%s → %zu bits%s", STRINGIFY(t), \
+ sizeof(t)*CHAR_BIT, \
+ strstr(STRINGIFY(t), "signed") ? "" : \
+ ((t)-1 < (t)0 ? ", signed" : ", unsigned"));
+
+int main(void) {
+ info(char);
+ info(signed char);
+ info(unsigned char);
+ info(short unsigned);
+ info(unsigned);
+ info(long unsigned);
+ info(long long unsigned);
+
+ info(float);
+ info(double);
+ info(long double);
+
+ info(size_t);
+ info(ssize_t);
+ info(time_t);
+ info(usec_t);
+
+ return 0;
+}
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 33ff3755bc..b480fdaa9c 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -27,6 +27,29 @@
#include "string-util.h"
#include "util.h"
+static void test_ifname_valid(void) {
+ assert(ifname_valid("foo"));
+ assert(ifname_valid("eth0"));
+
+ assert(!ifname_valid("0"));
+ assert(!ifname_valid("99"));
+ assert(ifname_valid("a99"));
+ assert(ifname_valid("99a"));
+
+ assert(!ifname_valid(NULL));
+ assert(!ifname_valid(""));
+ assert(!ifname_valid(" "));
+ assert(!ifname_valid(" foo"));
+ assert(!ifname_valid("bar\n"));
+ assert(!ifname_valid("."));
+ assert(!ifname_valid(".."));
+ assert(ifname_valid("foo.bar"));
+ assert(!ifname_valid("x:y"));
+
+ assert(ifname_valid("xxxxxxxxxxxxxxx"));
+ assert(!ifname_valid("xxxxxxxxxxxxxxxx"));
+}
+
static void test_socket_address_parse(void) {
SocketAddress a;
@@ -343,10 +366,27 @@ static void test_sockaddr_equal(void) {
assert_se(!sockaddr_equal(&b, &c));
}
+static void test_sockaddr_un_len(void) {
+ static const struct sockaddr_un fs = {
+ .sun_family = AF_UNIX,
+ .sun_path = "/foo/bar/waldo",
+ };
+
+ static const struct sockaddr_un abstract = {
+ .sun_family = AF_UNIX,
+ .sun_path = "\0foobar",
+ };
+
+ assert_se(SOCKADDR_UN_LEN(fs) == offsetof(struct sockaddr_un, sun_path) + strlen(fs.sun_path));
+ assert_se(SOCKADDR_UN_LEN(abstract) == offsetof(struct sockaddr_un, sun_path) + 1 + strlen(abstract.sun_path + 1));
+}
+
int main(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
+ test_ifname_valid();
+
test_socket_address_parse();
test_socket_address_parse_netlink();
test_socket_address_equal();
@@ -363,5 +403,7 @@ int main(int argc, char *argv[]) {
test_sockaddr_equal();
+ test_sockaddr_un_len();
+
return 0;
}
diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c
new file mode 100644
index 0000000000..a10227f823
--- /dev/null
+++ b/src/test/test-stat-util.c
@@ -0,0 +1,68 @@
+/***
+ 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 <unistd.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "macro.h"
+#include "stat-util.h"
+
+static void test_files_same(void) {
+ _cleanup_close_ int fd = -1;
+ char name[] = "/tmp/test-files_same.XXXXXX";
+ char name_alias[] = "/tmp/test-files_same.alias";
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ assert_se(symlink(name, name_alias) >= 0);
+
+ assert_se(files_same(name, name));
+ assert_se(files_same(name, name_alias));
+
+ unlink(name);
+ unlink(name_alias);
+}
+
+static void test_is_symlink(void) {
+ char name[] = "/tmp/test-is_symlink.XXXXXX";
+ char name_link[] = "/tmp/test-is_symlink.link";
+ _cleanup_close_ int fd = -1;
+
+ fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
+ assert_se(fd >= 0);
+ assert_se(symlink(name, name_link) >= 0);
+
+ assert_se(is_symlink(name) == 0);
+ assert_se(is_symlink(name_link) == 1);
+ assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0);
+
+
+ unlink(name);
+ unlink(name_link);
+}
+
+int main(int argc, char *argv[]) {
+ test_files_same();
+ test_is_symlink();
+
+ return 0;
+}
diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c
index 9b48e95998..d0f84d70bc 100644
--- a/src/test/test-string-util.c
+++ b/src/test/test-string-util.c
@@ -17,7 +17,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
+#include "macro.h"
#include "string-util.h"
+#include "strv.h"
static void test_string_erase(void) {
char *x;
@@ -97,9 +100,271 @@ static void test_ascii_strcasecmp_nn(void) {
assert_se(ascii_strcasecmp_nn("BBbb", 4, "aaaa", 4) > 0);
}
+static void test_streq_ptr(void) {
+ assert_se(streq_ptr(NULL, NULL));
+ assert_se(!streq_ptr("abc", "cdef"));
+}
+
+static void test_strstrip(void) {
+ char *r;
+ char input[] = " hello, waldo. ";
+
+ r = strstrip(input);
+ assert_se(streq(r, "hello, waldo."));
+}
+
+static void test_strextend(void) {
+ _cleanup_free_ char *str = strdup("0123");
+ strextend(&str, "456", "78", "9", NULL);
+ assert_se(streq(str, "0123456789"));
+}
+
+static void test_strrep(void) {
+ _cleanup_free_ char *one, *three, *zero;
+ one = strrep("waldo", 1);
+ three = strrep("waldo", 3);
+ zero = strrep("waldo", 0);
+
+ assert_se(streq(one, "waldo"));
+ assert_se(streq(three, "waldowaldowaldo"));
+ assert_se(streq(zero, ""));
+}
+
+
+static void test_strappend(void) {
+ _cleanup_free_ char *t1, *t2, *t3, *t4;
+
+ t1 = strappend(NULL, NULL);
+ assert_se(streq(t1, ""));
+
+ t2 = strappend(NULL, "suf");
+ assert_se(streq(t2, "suf"));
+
+ t3 = strappend("pre", NULL);
+ assert_se(streq(t3, "pre"));
+
+ t4 = strappend("pre", "suf");
+ assert_se(streq(t4, "presuf"));
+}
+
+static void test_string_has_cc(void) {
+ assert_se(string_has_cc("abc\1", NULL));
+ assert_se(string_has_cc("abc\x7f", NULL));
+ assert_se(string_has_cc("abc\x7f", NULL));
+ assert_se(string_has_cc("abc\t\x7f", "\t"));
+ assert_se(string_has_cc("abc\t\x7f", "\t"));
+ assert_se(string_has_cc("\x7f", "\t"));
+ assert_se(string_has_cc("\x7f", "\t\a"));
+
+ assert_se(!string_has_cc("abc\t\t", "\t"));
+ assert_se(!string_has_cc("abc\t\t\a", "\t\a"));
+ assert_se(!string_has_cc("a\ab\tc", "\t\a"));
+}
+
+static void test_ascii_strlower(void) {
+ char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK";
+ assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk"));
+}
+
+static void test_strshorten(void) {
+ char s[] = "foobar";
+
+ assert_se(strlen(strshorten(s, 6)) == 6);
+ assert_se(strlen(strshorten(s, 12)) == 6);
+ assert_se(strlen(strshorten(s, 2)) == 2);
+ assert_se(strlen(strshorten(s, 0)) == 0);
+}
+
+static void test_strjoina(void) {
+ char *actual;
+
+ actual = strjoina("", "foo", "bar");
+ assert_se(streq(actual, "foobar"));
+
+ actual = strjoina("foo", "bar", "baz");
+ assert_se(streq(actual, "foobarbaz"));
+
+ actual = strjoina("foo", "", "bar", "baz");
+ assert_se(streq(actual, "foobarbaz"));
+
+ actual = strjoina("foo");
+ assert_se(streq(actual, "foo"));
+
+ actual = strjoina(NULL);
+ assert_se(streq(actual, ""));
+
+ actual = strjoina(NULL, "foo");
+ assert_se(streq(actual, ""));
+
+ actual = strjoina("foo", NULL, "bar");
+ assert_se(streq(actual, "foo"));
+}
+
+static void test_strcmp_ptr(void) {
+ assert_se(strcmp_ptr(NULL, NULL) == 0);
+ assert_se(strcmp_ptr("", NULL) > 0);
+ assert_se(strcmp_ptr("foo", NULL) > 0);
+ assert_se(strcmp_ptr(NULL, "") < 0);
+ assert_se(strcmp_ptr(NULL, "bar") < 0);
+ assert_se(strcmp_ptr("foo", "bar") > 0);
+ assert_se(strcmp_ptr("bar", "baz") < 0);
+ assert_se(strcmp_ptr("foo", "foo") == 0);
+ assert_se(strcmp_ptr("", "") == 0);
+}
+
+static void test_foreach_word(void) {
+ const char *word, *state;
+ size_t l;
+ int i = 0;
+ const char test[] = "test abc d\te f ";
+ const char * const expected[] = {
+ "test",
+ "abc",
+ "d",
+ "e",
+ "f",
+ "",
+ NULL
+ };
+
+ FOREACH_WORD(word, l, test, state)
+ assert_se(strneq(expected[i++], word, l));
+}
+
+static void check(const char *test, char** expected, bool trailing) {
+ const char *word, *state;
+ size_t l;
+ int i = 0;
+
+ printf("<<<%s>>>\n", test);
+ FOREACH_WORD_QUOTED(word, l, test, state) {
+ _cleanup_free_ char *t = NULL;
+
+ assert_se(t = strndup(word, l));
+ assert_se(strneq(expected[i++], word, l));
+ printf("<%s>\n", t);
+ }
+ printf("<<<%s>>>\n", state);
+ assert_se(expected[i] == NULL);
+ assert_se(isempty(state) == !trailing);
+}
+
+static void test_foreach_word_quoted(void) {
+ check("test a b c 'd' e '' '' hhh '' '' \"a b c\"",
+ STRV_MAKE("test",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "",
+ "",
+ "hhh",
+ "",
+ "",
+ "a b c"),
+ false);
+
+ check("test \"xxx",
+ STRV_MAKE("test"),
+ true);
+
+ check("test\\",
+ STRV_MAKE_EMPTY,
+ true);
+}
+
+static void test_endswith(void) {
+ assert_se(endswith("foobar", "bar"));
+ assert_se(endswith("foobar", ""));
+ assert_se(endswith("foobar", "foobar"));
+ assert_se(endswith("", ""));
+
+ assert_se(!endswith("foobar", "foo"));
+ assert_se(!endswith("foobar", "foobarfoofoo"));
+}
+
+static void test_endswith_no_case(void) {
+ assert_se(endswith_no_case("fooBAR", "bar"));
+ assert_se(endswith_no_case("foobar", ""));
+ assert_se(endswith_no_case("foobar", "FOOBAR"));
+ assert_se(endswith_no_case("", ""));
+
+ assert_se(!endswith_no_case("foobar", "FOO"));
+ assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO"));
+}
+
+static void test_delete_chars(void) {
+ char *r;
+ char input[] = " hello, waldo. abc";
+
+ r = delete_chars(input, WHITESPACE);
+ assert_se(streq(r, "hello,waldo.abc"));
+}
+
+static void test_in_charset(void) {
+ assert_se(in_charset("dddaaabbbcccc", "abcd"));
+ assert_se(!in_charset("dddaaabbbcccc", "abc f"));
+}
+
+static void test_split_pair(void) {
+ _cleanup_free_ char *a = NULL, *b = NULL;
+
+ assert_se(split_pair("", "", &a, &b) == -EINVAL);
+ assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL);
+ assert_se(split_pair("", "=", &a, &b) == -EINVAL);
+ assert_se(split_pair("foo=bar", "=", &a, &b) >= 0);
+ assert_se(streq(a, "foo"));
+ assert_se(streq(b, "bar"));
+ free(a);
+ free(b);
+ assert_se(split_pair("==", "==", &a, &b) >= 0);
+ assert_se(streq(a, ""));
+ assert_se(streq(b, ""));
+ free(a);
+ free(b);
+
+ assert_se(split_pair("===", "==", &a, &b) >= 0);
+ assert_se(streq(a, ""));
+ assert_se(streq(b, "="));
+}
+
+static void test_first_word(void) {
+ assert_se(first_word("Hello", ""));
+ assert_se(first_word("Hello", "Hello"));
+ assert_se(first_word("Hello world", "Hello"));
+ assert_se(first_word("Hello\tworld", "Hello"));
+ assert_se(first_word("Hello\nworld", "Hello"));
+ assert_se(first_word("Hello\rworld", "Hello"));
+ assert_se(first_word("Hello ", "Hello"));
+
+ assert_se(!first_word("Hello", "Hellooo"));
+ assert_se(!first_word("Hello", "xxxxx"));
+ assert_se(!first_word("Hellooo", "Hello"));
+}
+
int main(int argc, char *argv[]) {
test_string_erase();
test_ascii_strcasecmp_n();
test_ascii_strcasecmp_nn();
+ test_streq_ptr();
+ test_strstrip();
+ test_strextend();
+ test_strrep();
+ test_strappend();
+ test_string_has_cc();
+ test_ascii_strlower();
+ test_strshorten();
+ test_strjoina();
+ test_strcmp_ptr();
+ test_foreach_word();
+ test_foreach_word_quoted();
+ test_endswith();
+ test_endswith_no_case();
+ test_delete_chars();
+ test_in_charset();
+ test_split_pair();
+ test_first_word();
+
return 0;
}
diff --git a/src/test/test-strv.c b/src/test/test-strv.c
index 2b2f76cc7f..fc01dcfaf1 100644
--- a/src/test/test-strv.c
+++ b/src/test/test-strv.c
@@ -70,6 +70,18 @@ static const char* const input_table_none[] = {
NULL,
};
+static const char* const input_table_two_empties[] = {
+ "",
+ "",
+ NULL,
+};
+
+static const char* const input_table_one_empty[] = {
+ "",
+ NULL,
+};
+
+
static const char* const input_table_quotes[] = {
"\"",
"'",
@@ -130,7 +142,7 @@ static void test_strv_find_startswith(void) {
}
static void test_strv_join(void) {
- _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL;
+ _cleanup_free_ char *p = NULL, *q = NULL, *r = NULL, *s = NULL, *t = NULL, *v = NULL, *w = NULL;
p = strv_join((char **)input_table_multiple, ", ");
assert_se(p);
@@ -151,6 +163,14 @@ static void test_strv_join(void) {
t = strv_join((char **)input_table_none, ", ");
assert_se(t);
assert_se(streq(t, ""));
+
+ v = strv_join((char **)input_table_two_empties, ", ");
+ assert_se(v);
+ assert_se(streq(v, ", "));
+
+ w = strv_join((char **)input_table_one_empty, ", ");
+ assert_se(w);
+ assert_se(streq(w, ""));
}
static void test_strv_quote_unquote(const char* const *split, const char *quoted) {
@@ -338,7 +358,7 @@ static void test_strv_extend_strv_concat(void) {
}
static void test_strv_extend_strv(void) {
- _cleanup_strv_free_ char **a = NULL, **b = NULL;
+ _cleanup_strv_free_ char **a = NULL, **b = NULL, **n = NULL;
a = strv_new("abc", "def", "ghi", NULL);
b = strv_new("jkl", "mno", "abc", "pqr", NULL);
@@ -353,8 +373,14 @@ static void test_strv_extend_strv(void) {
assert_se(streq(a[3], "jkl"));
assert_se(streq(a[4], "mno"));
assert_se(streq(a[5], "pqr"));
-
assert_se(strv_length(a) == 6);
+
+ assert_se(strv_extend_strv(&n, b, false) >= 0);
+ assert_se(streq(n[0], "jkl"));
+ assert_se(streq(n[1], "mno"));
+ assert_se(streq(n[2], "abc"));
+ assert_se(streq(n[3], "pqr"));
+ assert_se(strv_length(n) == 4);
}
static void test_strv_extend(void) {
@@ -640,6 +666,25 @@ static void test_strv_make_nulstr(void) {
test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux"));
}
+static void test_foreach_string(void) {
+ const char * const t[] = {
+ "foo",
+ "bar",
+ "waldo",
+ NULL
+ };
+ const char *x;
+ unsigned i = 0;
+
+ FOREACH_STRING(x, "foo", "bar", "waldo")
+ assert_se(streq_ptr(t[i++], x));
+
+ assert_se(i == 3);
+
+ FOREACH_STRING(x, "zzz")
+ assert_se(streq(x, "zzz"));
+}
+
int main(int argc, char *argv[]) {
test_specifier_printf();
test_strv_foreach();
@@ -653,6 +698,8 @@ int main(int argc, char *argv[]) {
test_strv_quote_unquote(input_table_multiple, "\"one\" \"two\" \"three\"");
test_strv_quote_unquote(input_table_one, "\"one\"");
test_strv_quote_unquote(input_table_none, "");
+ test_strv_quote_unquote(input_table_one_empty, "\"\"");
+ test_strv_quote_unquote(input_table_two_empties, "\"\" \"\"");
test_strv_quote_unquote(input_table_quotes, QUOTES_STRING);
test_strv_quote_unquote(input_table_spaces, SPACES_STRING);
@@ -702,5 +749,7 @@ int main(int argc, char *argv[]) {
test_strv_extend_n();
test_strv_make_nulstr();
+ test_foreach_string();
+
return 0;
}
diff --git a/src/test/test-tables.c b/src/test/test-tables.c
index aef992ee3c..0be74921fc 100644
--- a/src/test/test-tables.c
+++ b/src/test/test-tables.c
@@ -19,7 +19,6 @@
#include "architecture.h"
#include "automount.h"
-#include "bus-xml-policy.h"
#include "busname.h"
#include "cgroup.h"
#include "compress.h"
@@ -83,8 +82,6 @@ int main(int argc, char **argv) {
test_table(path_result, PATH_RESULT);
test_table(path_state, PATH_STATE);
test_table(path_type, PATH_TYPE);
- test_table(policy_item_class, POLICY_ITEM_CLASS);
- test_table(policy_item_type, POLICY_ITEM_TYPE);
test_table(protect_home, PROTECT_HOME);
test_table(protect_system, PROTECT_SYSTEM);
test_table(rlimit, RLIMIT);
diff --git a/src/test/test-time.c b/src/test/test-time.c
index 9062c3f3c1..ee7d55c5ab 100644
--- a/src/test/test-time.c
+++ b/src/test/test-time.c
@@ -220,7 +220,7 @@ int main(int argc, char *argv[]) {
/* Ensure TIME_T_MAX works correctly */
x = (uintmax_t) TIME_T_MAX;
- x ++;
+ x++;
assert((time_t) x < 0);
return 0;
diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c
index d7223dd2bf..b34ebeefb2 100644
--- a/src/test/test-tmpfiles.c
+++ b/src/test/test-tmpfiles.c
@@ -32,15 +32,17 @@
#include "util.h"
int main(int argc, char** argv) {
+ _cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL;
+ _cleanup_close_ int fd = -1, fd2 = -1;
const char *p = argv[1] ?: "/tmp";
- char *pattern = strjoina(p, "/systemd-test-XXXXXX");
- _cleanup_close_ int fd, fd2;
- _cleanup_free_ char *cmd, *cmd2, *ans, *ans2;
+ char *pattern;
log_set_max_level(LOG_DEBUG);
log_parse_environment();
- fd = open_tmpfile(p, O_RDWR|O_CLOEXEC);
+ pattern = strjoina(p, "/systemd-test-XXXXXX");
+
+ fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC);
assert_se(fd >= 0);
assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0);
@@ -59,5 +61,21 @@ int main(int argc, char** argv) {
log_debug("link2: %s", ans2);
assert_se(endswith(ans2, " (deleted)"));
+ pattern = strjoina(p, "/tmpfiles-test");
+ assert_se(tempfn_random(pattern, NULL, &d) >= 0);
+
+ fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp);
+ assert_se(fd >= 0);
+ assert_se(write(fd, "foobar\n", 7) == 7);
+
+ assert_se(touch(d) >= 0);
+ assert_se(link_tmpfile(fd, tmp, d) == -EEXIST);
+ assert_se(unlink(d) >= 0);
+ assert_se(link_tmpfile(fd, tmp, d) >= 0);
+
+ assert_se(read_one_line_file(d, &line) >= 0);
+ assert_se(streq(line, "foobar"));
+ assert_se(unlink(d) >= 0);
+
return 0;
}
diff --git a/src/test/test-udev.c b/src/test/test-udev.c
index 9cc64f7c68..e965b4494a 100644
--- a/src/test/test-udev.c
+++ b/src/test/test-udev.c
@@ -27,6 +27,7 @@
#include <unistd.h>
#include "fs-util.h"
+#include "log.h"
#include "missing.h"
#include "selinux-util.h"
#include "signal-util.h"
@@ -39,39 +40,31 @@ static int fake_filesystems(void) {
const char *src;
const char *target;
const char *error;
+ bool ignore_mount_error;
} fakefss[] = {
- { "test/sys", "/sys", "failed to mount test /sys" },
- { "test/dev", "/dev", "failed to mount test /dev" },
- { "test/run", "/run", "failed to mount test /run" },
- { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" },
- { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" },
+ { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false },
+ { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false },
+ { "test/run", "/run", "failed to mount test /run", false },
+ { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true },
+ { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true },
};
unsigned int i;
- int err;
- err = unshare(CLONE_NEWNS);
- if (err < 0) {
- err = -errno;
- fprintf(stderr, "failed to call unshare(): %m\n");
- goto out;
- }
+ if (unshare(CLONE_NEWNS) < 0)
+ return log_error_errno(errno, "failed to call unshare(): %m");
- if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0) {
- err = -errno;
- fprintf(stderr, "failed to mount / as private: %m\n");
- goto out;
- }
+ if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) < 0)
+ return log_error_errno(errno, "failed to mount / as private: %m");
for (i = 0; i < ELEMENTSOF(fakefss); i++) {
- err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL);
- if (err < 0) {
- err = -errno;
- fprintf(stderr, "%s %m\n", fakefss[i].error);
- return err;
+ if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
+ log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error);
+ if (!fakefss[i].ignore_mount_error)
+ return -errno;
}
}
-out:
- return err;
+
+ return 0;
}
int main(int argc, char *argv[]) {
@@ -84,6 +77,9 @@ int main(int argc, char *argv[]) {
const char *action;
int err;
+ log_parse_environment();
+ log_open();
+
err = fake_filesystems();
if (err < 0)
return EXIT_FAILURE;
@@ -93,7 +89,7 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
log_debug("version %s", VERSION);
- mac_selinux_init("/dev");
+ mac_selinux_init();
action = argv[1];
if (action == NULL) {
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index b0c343590d..ade0ff2a63 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -35,10 +35,12 @@
#include "install.h"
#include "load-fragment.h"
#include "macro.h"
+#include "rm-rf.h"
#include "specifier.h"
#include "string-util.h"
#include "strv.h"
#include "test-helper.h"
+#include "tests.h"
#include "user-util.h"
#include "util.h"
@@ -51,7 +53,7 @@ static int test_unit_file_get_set(void) {
h = hashmap_new(&string_hash_ops);
assert_se(h);
- r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h);
+ r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h, NULL, NULL);
if (r == -EPERM || r == -EACCES) {
printf("Skipping test: unit_file_get_list: %s", strerror(-r));
@@ -113,7 +115,7 @@ static void test_config_parse_exec(void) {
Manager *m = NULL;
Unit *u = NULL;
- r = manager_new(MANAGER_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, true, &m);
if (MANAGER_SKIP_TEST(r)) {
printf("Skipping test: manager_new: %s\n", strerror(-r));
return;
@@ -606,7 +608,7 @@ static void test_install_printf(void) {
} else assert_se(t == NULL); \
strcpy(i.name, d1); \
strcpy(i.path, d2); \
- } while(false)
+ } while (false)
expect(i, "%n", "name.service");
expect(i, "%N", "name");
@@ -840,11 +842,14 @@ static void test_config_parse_pass_environ(void) {
}
int main(int argc, char *argv[]) {
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
int r;
log_parse_environment();
log_open();
+ assert_se(runtime_dir = setup_fake_runtime_dir());
+
r = test_unit_file_get_set();
test_config_parse_exec();
test_config_parse_capability_set();
diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c
index 3de94ef425..2fd83f321c 100644
--- a/src/test/test-unit-name.c
+++ b/src/test/test-unit-name.c
@@ -209,7 +209,7 @@ static int test_unit_printf(void) {
assert_se(get_home_dir(&home) >= 0);
assert_se(get_shell(&shell) >= 0);
- r = manager_new(MANAGER_USER, true, &m);
+ r = manager_new(UNIT_FILE_USER, true, &m);
if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) {
puts("manager_new: Permission denied. Skipping test.");
return EXIT_TEST_SKIP;
diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c
index 42c6a8d5e2..8d1ec19f17 100644
--- a/src/test/test-user-util.c
+++ b/src/test/test-user-util.c
@@ -37,6 +37,30 @@ static void test_gid_to_name_one(gid_t gid, const char *name) {
assert_se(streq_ptr(t, name));
}
+static void test_parse_uid(void) {
+ int r;
+ uid_t uid;
+
+ r = parse_uid("100", &uid);
+ assert_se(r == 0);
+ assert_se(uid == 100);
+
+ r = parse_uid("65535", &uid);
+ assert_se(r == -ENXIO);
+
+ r = parse_uid("asdsdas", &uid);
+ assert_se(r == -EINVAL);
+}
+
+static void test_uid_ptr(void) {
+
+ assert_se(UID_TO_PTR(0) != NULL);
+ assert_se(UID_TO_PTR(1000) != NULL);
+
+ assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0);
+ assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
+}
+
int main(int argc, char*argv[]) {
test_uid_to_name_one(0, "root");
@@ -48,5 +72,8 @@ int main(int argc, char*argv[]) {
test_gid_to_name_one(0xFFFF, "65535");
test_gid_to_name_one(0xFFFFFFFF, "4294967295");
+ test_parse_uid();
+ test_uid_ptr();
+
return 0;
}
diff --git a/src/test/test-util.c b/src/test/test-util.c
index 9a8a265790..05cb1eae76 100644
--- a/src/test/test-util.c
+++ b/src/test/test-util.c
@@ -19,47 +19,16 @@
***/
#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <string.h>
-#include <sys/types.h>
#include <sys/wait.h>
-#include <sys/xattr.h>
#include <unistd.h>
-#include "alloc-util.h"
-#include "conf-parser.h"
-#include "cpu-set-util.h"
#include "def.h"
-#include "escape.h"
-#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
-#include "fstab-util.h"
-#include "glob-util.h"
-#include "hexdecoct.h"
-#include "io-util.h"
-#include "mkdir.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "proc-cmdline.h"
-#include "process-util.h"
#include "rm-rf.h"
-#include "signal-util.h"
-#include "special.h"
-#include "stat-util.h"
#include "string-util.h"
-#include "strv.h"
-#include "user-util.h"
#include "util.h"
-#include "virt.h"
-#include "web-util.h"
-#include "xattr-util.h"
-
-static void test_streq_ptr(void) {
- assert_se(streq_ptr(NULL, NULL));
- assert_se(!streq_ptr("abc", "cdef"));
-}
static void test_align_power2(void) {
unsigned long i, p2;
@@ -151,19 +120,6 @@ static void test_container_of(void) {
v1) == &myval);
}
-static void test_alloca(void) {
- static const uint8_t zero[997] = { };
- char *t;
-
- t = alloca_align(17, 512);
- assert_se(!((uintptr_t)t & 0xff));
- memzero(t, 17);
-
- t = alloca0_align(997, 1024);
- assert_se(!((uintptr_t)t & 0x1ff));
- assert_se(!memcmp(t, zero, 997));
-}
-
static void test_div_round_up(void) {
int div;
@@ -197,544 +153,6 @@ static void test_div_round_up(void) {
assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U);
}
-static void test_first_word(void) {
- assert_se(first_word("Hello", ""));
- assert_se(first_word("Hello", "Hello"));
- assert_se(first_word("Hello world", "Hello"));
- assert_se(first_word("Hello\tworld", "Hello"));
- assert_se(first_word("Hello\nworld", "Hello"));
- assert_se(first_word("Hello\rworld", "Hello"));
- assert_se(first_word("Hello ", "Hello"));
-
- assert_se(!first_word("Hello", "Hellooo"));
- assert_se(!first_word("Hello", "xxxxx"));
- assert_se(!first_word("Hellooo", "Hello"));
-}
-
-static void test_close_many(void) {
- int fds[3];
- char name0[] = "/tmp/test-close-many.XXXXXX";
- char name1[] = "/tmp/test-close-many.XXXXXX";
- char name2[] = "/tmp/test-close-many.XXXXXX";
-
- fds[0] = mkostemp_safe(name0, O_RDWR|O_CLOEXEC);
- fds[1] = mkostemp_safe(name1, O_RDWR|O_CLOEXEC);
- fds[2] = mkostemp_safe(name2, O_RDWR|O_CLOEXEC);
-
- close_many(fds, 2);
-
- assert_se(fcntl(fds[0], F_GETFD) == -1);
- assert_se(fcntl(fds[1], F_GETFD) == -1);
- assert_se(fcntl(fds[2], F_GETFD) >= 0);
-
- safe_close(fds[2]);
-
- unlink(name0);
- unlink(name1);
- unlink(name2);
-}
-
-static void test_parse_uid(void) {
- int r;
- uid_t uid;
-
- r = parse_uid("100", &uid);
- assert_se(r == 0);
- assert_se(uid == 100);
-
- r = parse_uid("65535", &uid);
- assert_se(r == -ENXIO);
-
- r = parse_uid("asdsdas", &uid);
- assert_se(r == -EINVAL);
-}
-
-static void test_strappend(void) {
- _cleanup_free_ char *t1, *t2, *t3, *t4;
-
- t1 = strappend(NULL, NULL);
- assert_se(streq(t1, ""));
-
- t2 = strappend(NULL, "suf");
- assert_se(streq(t2, "suf"));
-
- t3 = strappend("pre", NULL);
- assert_se(streq(t3, "pre"));
-
- t4 = strappend("pre", "suf");
- assert_se(streq(t4, "presuf"));
-}
-
-static void test_strstrip(void) {
- char *r;
- char input[] = " hello, waldo. ";
-
- r = strstrip(input);
- assert_se(streq(r, "hello, waldo."));
-}
-
-static void test_delete_chars(void) {
- char *r;
- char input[] = " hello, waldo. abc";
-
- r = delete_chars(input, WHITESPACE);
- assert_se(streq(r, "hello,waldo.abc"));
-}
-
-static void test_in_charset(void) {
- assert_se(in_charset("dddaaabbbcccc", "abcd"));
- assert_se(!in_charset("dddaaabbbcccc", "abc f"));
-}
-
-static void test_hexchar(void) {
- assert_se(hexchar(0xa) == 'a');
- assert_se(hexchar(0x0) == '0');
-}
-
-static void test_unhexchar(void) {
- assert_se(unhexchar('a') == 0xA);
- assert_se(unhexchar('A') == 0xA);
- assert_se(unhexchar('0') == 0x0);
-}
-
-static void test_base32hexchar(void) {
- assert_se(base32hexchar(0) == '0');
- assert_se(base32hexchar(9) == '9');
- assert_se(base32hexchar(10) == 'A');
- assert_se(base32hexchar(31) == 'V');
-}
-
-static void test_unbase32hexchar(void) {
- assert_se(unbase32hexchar('0') == 0);
- assert_se(unbase32hexchar('9') == 9);
- assert_se(unbase32hexchar('A') == 10);
- assert_se(unbase32hexchar('V') == 31);
- assert_se(unbase32hexchar('=') == -EINVAL);
-}
-
-static void test_base64char(void) {
- assert_se(base64char(0) == 'A');
- assert_se(base64char(26) == 'a');
- assert_se(base64char(63) == '/');
-}
-
-static void test_unbase64char(void) {
- assert_se(unbase64char('A') == 0);
- assert_se(unbase64char('Z') == 25);
- assert_se(unbase64char('a') == 26);
- assert_se(unbase64char('z') == 51);
- assert_se(unbase64char('0') == 52);
- assert_se(unbase64char('9') == 61);
- assert_se(unbase64char('+') == 62);
- assert_se(unbase64char('/') == 63);
- assert_se(unbase64char('=') == -EINVAL);
-}
-
-static void test_octchar(void) {
- assert_se(octchar(00) == '0');
- assert_se(octchar(07) == '7');
-}
-
-static void test_unoctchar(void) {
- assert_se(unoctchar('0') == 00);
- assert_se(unoctchar('7') == 07);
-}
-
-static void test_decchar(void) {
- assert_se(decchar(0) == '0');
- assert_se(decchar(9) == '9');
-}
-
-static void test_undecchar(void) {
- assert_se(undecchar('0') == 0);
- assert_se(undecchar('9') == 9);
-}
-
-static void test_unhexmem(void) {
- const char *hex = "efa214921";
- const char *hex_invalid = "efa214921o";
- _cleanup_free_ char *hex2 = NULL;
- _cleanup_free_ void *mem = NULL;
- size_t len;
-
- assert_se(unhexmem(hex, strlen(hex), &mem, &len) == 0);
- assert_se(unhexmem(hex, strlen(hex) + 1, &mem, &len) == -EINVAL);
- assert_se(unhexmem(hex_invalid, strlen(hex_invalid), &mem, &len) == -EINVAL);
-
- assert_se((hex2 = hexmem(mem, len)));
-
- free(mem);
-
- assert_se(memcmp(hex, hex2, strlen(hex)) == 0);
-
- free(hex2);
-
- assert_se(unhexmem(hex, strlen(hex) - 1, &mem, &len) == 0);
- assert_se((hex2 = hexmem(mem, len)));
- assert_se(memcmp(hex, hex2, strlen(hex) - 1) == 0);
-}
-
-/* https://tools.ietf.org/html/rfc4648#section-10 */
-static void test_base32hexmem(void) {
- char *b32;
-
- b32 = base32hexmem("", strlen(""), true);
- assert_se(b32);
- assert_se(streq(b32, ""));
- free(b32);
-
- b32 = base32hexmem("f", strlen("f"), true);
- assert_se(b32);
- assert_se(streq(b32, "CO======"));
- free(b32);
-
- b32 = base32hexmem("fo", strlen("fo"), true);
- assert_se(b32);
- assert_se(streq(b32, "CPNG===="));
- free(b32);
-
- b32 = base32hexmem("foo", strlen("foo"), true);
- assert_se(b32);
- assert_se(streq(b32, "CPNMU==="));
- free(b32);
-
- b32 = base32hexmem("foob", strlen("foob"), true);
- assert_se(b32);
- assert_se(streq(b32, "CPNMUOG="));
- free(b32);
-
- b32 = base32hexmem("fooba", strlen("fooba"), true);
- assert_se(b32);
- assert_se(streq(b32, "CPNMUOJ1"));
- free(b32);
-
- b32 = base32hexmem("foobar", strlen("foobar"), true);
- assert_se(b32);
- assert_se(streq(b32, "CPNMUOJ1E8======"));
- free(b32);
-
- b32 = base32hexmem("", strlen(""), false);
- assert_se(b32);
- assert_se(streq(b32, ""));
- free(b32);
-
- b32 = base32hexmem("f", strlen("f"), false);
- assert_se(b32);
- assert_se(streq(b32, "CO"));
- free(b32);
-
- b32 = base32hexmem("fo", strlen("fo"), false);
- assert_se(b32);
- assert_se(streq(b32, "CPNG"));
- free(b32);
-
- b32 = base32hexmem("foo", strlen("foo"), false);
- assert_se(b32);
- assert_se(streq(b32, "CPNMU"));
- free(b32);
-
- b32 = base32hexmem("foob", strlen("foob"), false);
- assert_se(b32);
- assert_se(streq(b32, "CPNMUOG"));
- free(b32);
-
- b32 = base32hexmem("fooba", strlen("fooba"), false);
- assert_se(b32);
- assert_se(streq(b32, "CPNMUOJ1"));
- free(b32);
-
- b32 = base32hexmem("foobar", strlen("foobar"), false);
- assert_se(b32);
- assert_se(streq(b32, "CPNMUOJ1E8"));
- free(b32);
-}
-
-static void test_unbase32hexmem(void) {
- void *mem;
- size_t len;
-
- assert_se(unbase32hexmem("", strlen(""), true, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), ""));
- free(mem);
-
- assert_se(unbase32hexmem("CO======", strlen("CO======"), true, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "f"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNG====", strlen("CPNG===="), true, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "fo"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMU===", strlen("CPNMU==="), true, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foo"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), true, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foob"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "fooba"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), true, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foobar"));
- free(mem);
-
- assert_se(unbase32hexmem("A", strlen("A"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("A=======", strlen("A======="), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAA=====", strlen("AAA====="), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAAAA==", strlen("AAAAAA=="), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AB======", strlen("AB======"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAB====", strlen("AAAB===="), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAAB===", strlen("AAAAB==="), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAAAAB=", strlen("AAAAAAB="), true, &mem, &len) == -EINVAL);
-
- assert_se(unbase32hexmem("XPNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CXNMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CPXMUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CPNXUOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CPNMXOJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CPNMUXJ1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CPNMUOX1", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CPNMUOJX", strlen("CPNMUOJ1"), true, &mem, &len) == -EINVAL);
-
- assert_se(unbase32hexmem("", strlen(""), false, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), ""));
- free(mem);
-
- assert_se(unbase32hexmem("CO", strlen("CO"), false, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "f"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNG", strlen("CPNG"), false, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "fo"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMU", strlen("CPNMU"), false, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foo"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMUOG", strlen("CPNMUOG"), false, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foob"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMUOJ1", strlen("CPNMUOJ1"), false, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "fooba"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMUOJ1E8", strlen("CPNMUOJ1E8"), false, &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foobar"));
- free(mem);
-
- assert_se(unbase32hexmem("CPNMUOG=", strlen("CPNMUOG="), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("CPNMUOJ1E8======", strlen("CPNMUOJ1E8======"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("A", strlen("A"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAA", strlen("AAA"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAAAA", strlen("AAAAAA"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AB", strlen("AB"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAB", strlen("AAAB"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAAB", strlen("AAAAB"), false, &mem, &len) == -EINVAL);
- assert_se(unbase32hexmem("AAAAAAB", strlen("AAAAAAB"), false, &mem, &len) == -EINVAL);
-}
-
-/* https://tools.ietf.org/html/rfc4648#section-10 */
-static void test_base64mem(void) {
- char *b64;
-
- assert_se(base64mem("", strlen(""), &b64) == 0);
- assert_se(streq(b64, ""));
- free(b64);
-
- assert_se(base64mem("f", strlen("f"), &b64) == 4);
- assert_se(streq(b64, "Zg=="));
- free(b64);
-
- assert_se(base64mem("fo", strlen("fo"), &b64) == 4);
- assert_se(streq(b64, "Zm8="));
- free(b64);
-
- assert_se(base64mem("foo", strlen("foo"), &b64) == 4);
- assert_se(streq(b64, "Zm9v"));
- free(b64);
-
- assert_se(base64mem("foob", strlen("foob"), &b64) == 8);
- assert_se(streq(b64, "Zm9vYg=="));
- free(b64);
-
- assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8);
- assert_se(streq(b64, "Zm9vYmE="));
- free(b64);
-
- assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8);
- assert_se(streq(b64, "Zm9vYmFy"));
- free(b64);
-}
-
-static void test_unbase64mem(void) {
- void *mem;
- size_t len;
-
- assert_se(unbase64mem("", strlen(""), &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), ""));
- free(mem);
-
- assert_se(unbase64mem("Zg==", strlen("Zg=="), &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "f"));
- free(mem);
-
- assert_se(unbase64mem("Zm8=", strlen("Zm8="), &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "fo"));
- free(mem);
-
- assert_se(unbase64mem("Zm9v", strlen("Zm9v"), &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foo"));
- free(mem);
-
- assert_se(unbase64mem("Zm9vYg==", strlen("Zm9vYg=="), &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foob"));
- free(mem);
-
- assert_se(unbase64mem("Zm9vYmE=", strlen("Zm9vYmE="), &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "fooba"));
- free(mem);
-
- assert_se(unbase64mem("Zm9vYmFy", strlen("Zm9vYmFy"), &mem, &len) == 0);
- assert_se(streq(strndupa(mem, len), "foobar"));
- free(mem);
-
- assert_se(unbase64mem("A", strlen("A"), &mem, &len) == -EINVAL);
- assert_se(unbase64mem("A====", strlen("A===="), &mem, &len) == -EINVAL);
- assert_se(unbase64mem("AAB==", strlen("AAB=="), &mem, &len) == -EINVAL);
- assert_se(unbase64mem("AAAB=", strlen("AAAB="), &mem, &len) == -EINVAL);
-}
-
-static void test_cescape(void) {
- _cleanup_free_ char *escaped;
-
- assert_se(escaped = cescape("abc\\\"\b\f\n\r\t\v\a\003\177\234\313"));
- assert_se(streq(escaped, "abc\\\\\\\"\\b\\f\\n\\r\\t\\v\\a\\003\\177\\234\\313"));
-}
-
-static void test_cunescape(void) {
- _cleanup_free_ char *unescaped;
-
- assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", 0, &unescaped) < 0);
- assert_se(cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00", UNESCAPE_RELAX, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00"));
- unescaped = mfree(unescaped);
-
- /* incomplete sequences */
- assert_se(cunescape("\\x0", 0, &unescaped) < 0);
- assert_se(cunescape("\\x0", UNESCAPE_RELAX, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, "\\x0"));
- unescaped = mfree(unescaped);
-
- assert_se(cunescape("\\x", 0, &unescaped) < 0);
- assert_se(cunescape("\\x", UNESCAPE_RELAX, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, "\\x"));
- unescaped = mfree(unescaped);
-
- assert_se(cunescape("\\", 0, &unescaped) < 0);
- assert_se(cunescape("\\", UNESCAPE_RELAX, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, "\\"));
- unescaped = mfree(unescaped);
-
- assert_se(cunescape("\\11", 0, &unescaped) < 0);
- assert_se(cunescape("\\11", UNESCAPE_RELAX, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, "\\11"));
- unescaped = mfree(unescaped);
-
- assert_se(cunescape("\\1", 0, &unescaped) < 0);
- assert_se(cunescape("\\1", UNESCAPE_RELAX, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, "\\1"));
- unescaped = mfree(unescaped);
-
- assert_se(cunescape("\\u0000", 0, &unescaped) < 0);
- assert_se(cunescape("\\u00DF\\U000000df\\u03a0\\U00000041", UNESCAPE_RELAX, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, "ßßΠA"));
- unescaped = mfree(unescaped);
-
- assert_se(cunescape("\\073", 0, &unescaped) >= 0);
- assert_se(streq_ptr(unescaped, ";"));
-}
-
-static void test_foreach_word(void) {
- const char *word, *state;
- size_t l;
- int i = 0;
- const char test[] = "test abc d\te f ";
- const char * const expected[] = {
- "test",
- "abc",
- "d",
- "e",
- "f",
- "",
- NULL
- };
-
- FOREACH_WORD(word, l, test, state)
- assert_se(strneq(expected[i++], word, l));
-}
-
-static void check(const char *test, char** expected, bool trailing) {
- const char *word, *state;
- size_t l;
- int i = 0;
-
- printf("<<<%s>>>\n", test);
- FOREACH_WORD_QUOTED(word, l, test, state) {
- _cleanup_free_ char *t = NULL;
-
- assert_se(t = strndup(word, l));
- assert_se(strneq(expected[i++], word, l));
- printf("<%s>\n", t);
- }
- printf("<<<%s>>>\n", state);
- assert_se(expected[i] == NULL);
- assert_se(isempty(state) == !trailing);
-}
-
-static void test_foreach_word_quoted(void) {
- check("test a b c 'd' e '' '' hhh '' '' \"a b c\"",
- STRV_MAKE("test",
- "a",
- "b",
- "c",
- "d",
- "e",
- "",
- "",
- "hhh",
- "",
- "",
- "a b c"),
- false);
-
- check("test \"xxx",
- STRV_MAKE("test"),
- true);
-
- check("test\\",
- STRV_MAKE_EMPTY,
- true);
-}
-
-static void test_memdup_multiply(void) {
- int org[] = {1, 2, 3};
- int *dup;
-
- dup = (int*)memdup_multiply(org, sizeof(int), 3);
-
- assert_se(dup);
- assert_se(dup[0] == 1);
- assert_se(dup[1] == 2);
- assert_se(dup[2] == 3);
- free(dup);
-}
-
static void test_u64log2(void) {
assert_se(u64log2(0) == 0);
assert_se(u64log2(8) == 3);
@@ -754,210 +172,6 @@ static void test_protect_errno(void) {
assert_se(errno == 12);
}
-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_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));
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 2);
- c = mfree(c);
-
- /* A more interesting range */
- 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);
-
- /* Quoted strings */
- 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++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- c = mfree(c);
-
- /* Use commas as separators */
- ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
- for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- c = mfree(c);
-
- /* Commas with spaces (and trailing comma, space) */
- ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
- for (cpu = 0; cpu < 8; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- c = mfree(c);
-
- /* Ranges */
- ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
- for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- c = mfree(c);
-
- /* Ranges with trailing comma, space */
- ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8);
- for (cpu = 0; cpu < 4; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- for (cpu = 8; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- c = mfree(c);
-
- /* Negative range (returns empty cpu_set) */
- ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0);
- c = mfree(c);
-
- /* Overlapping ranges */
- ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12);
- for (cpu = 0; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- c = mfree(c);
-
- /* Mix ranges and individual CPUs */
- ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus >= 1024);
- assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10);
- assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c));
- assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c));
- for (cpu = 4; cpu < 12; cpu++)
- assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c));
- c = mfree(c);
-
- /* Garbage */
- ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus < 0);
- assert_se(!c);
-
- /* Range with garbage */
- ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus < 0);
- assert_se(!c);
-
- /* Empty string */
- c = NULL;
- ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity");
- assert_se(ncpus == 0); /* empty string returns 0 */
- assert_se(!c);
-
- /* Runnaway quoted string */
- 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);
-}
-
-static void test_config_parse_iec_uint64(void) {
- uint64_t offset = 0;
- assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4M", &offset, NULL) == 0);
- assert_se(offset == 4 * 1024 * 1024);
-
- assert_se(config_parse_iec_uint64(NULL, "/this/file", 11, "Section", 22, "Size", 0, "4.5M", &offset, NULL) == 0);
-}
-
-static void test_strextend(void) {
- _cleanup_free_ char *str = strdup("0123");
- strextend(&str, "456", "78", "9", NULL);
- assert_se(streq(str, "0123456789"));
-}
-
-static void test_strrep(void) {
- _cleanup_free_ char *one, *three, *zero;
- one = strrep("waldo", 1);
- three = strrep("waldo", 3);
- zero = strrep("waldo", 0);
-
- assert_se(streq(one, "waldo"));
- assert_se(streq(three, "waldowaldowaldo"));
- assert_se(streq(zero, ""));
-}
-
-static void test_split_pair(void) {
- _cleanup_free_ char *a = NULL, *b = NULL;
-
- assert_se(split_pair("", "", &a, &b) == -EINVAL);
- assert_se(split_pair("foo=bar", "", &a, &b) == -EINVAL);
- assert_se(split_pair("", "=", &a, &b) == -EINVAL);
- assert_se(split_pair("foo=bar", "=", &a, &b) >= 0);
- assert_se(streq(a, "foo"));
- assert_se(streq(b, "bar"));
- free(a);
- free(b);
- assert_se(split_pair("==", "==", &a, &b) >= 0);
- assert_se(streq(a, ""));
- assert_se(streq(b, ""));
- free(a);
- free(b);
-
- assert_se(split_pair("===", "==", &a, &b) >= 0);
- assert_se(streq(a, ""));
- assert_se(streq(b, "="));
-}
-
-static void test_fstab_node_to_udev_node(void) {
- char *n;
-
- n = fstab_node_to_udev_node("LABEL=applé/jack");
- puts(n);
- assert_se(streq(n, "/dev/disk/by-label/applé\\x2fjack"));
- free(n);
-
- n = fstab_node_to_udev_node("PARTLABEL=pinkié pie");
- puts(n);
- assert_se(streq(n, "/dev/disk/by-partlabel/pinkié\\x20pie"));
- free(n);
-
- n = fstab_node_to_udev_node("UUID=037b9d94-148e-4ee4-8d38-67bfe15bb535");
- puts(n);
- assert_se(streq(n, "/dev/disk/by-uuid/037b9d94-148e-4ee4-8d38-67bfe15bb535"));
- free(n);
-
- n = fstab_node_to_udev_node("PARTUUID=037b9d94-148e-4ee4-8d38-67bfe15bb535");
- puts(n);
- assert_se(streq(n, "/dev/disk/by-partuuid/037b9d94-148e-4ee4-8d38-67bfe15bb535"));
- free(n);
-
- n = fstab_node_to_udev_node("PONIES=awesome");
- puts(n);
- assert_se(streq(n, "PONIES=awesome"));
- free(n);
-
- n = fstab_node_to_udev_node("/dev/xda1");
- puts(n);
- assert_se(streq(n, "/dev/xda1"));
- free(n);
-}
-
-static void test_get_files_in_directory(void) {
- _cleanup_strv_free_ char **l = NULL, **t = NULL;
-
- assert_se(get_files_in_directory("/tmp", &l) >= 0);
- assert_se(get_files_in_directory(".", &t) >= 0);
- assert_se(get_files_in_directory(".", NULL) >= 0);
-}
-
static void test_in_set(void) {
assert_se(IN_SET(1, 1));
assert_se(IN_SET(1, 1, 2, 3, 4));
@@ -968,50 +182,6 @@ static void test_in_set(void) {
assert_se(!IN_SET(0, 1, 2, 3, 4));
}
-static void test_writing_tmpfile(void) {
- char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
- _cleanup_free_ char *contents = NULL;
- size_t size;
- int fd, r;
- struct iovec iov[3];
-
- IOVEC_SET_STRING(iov[0], "abc\n");
- IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n");
- IOVEC_SET_STRING(iov[2], "");
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- printf("tmpfile: %s", name);
-
- r = writev(fd, iov, 3);
- assert_se(r >= 0);
-
- r = read_full_file(name, &contents, &size);
- assert_se(r == 0);
- printf("contents: %s", contents);
- assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
-
- unlink(name);
-}
-
-static void test_hexdump(void) {
- uint8_t data[146];
- unsigned i;
-
- hexdump(stdout, NULL, 0);
- hexdump(stdout, "", 0);
- hexdump(stdout, "", 1);
- hexdump(stdout, "x", 1);
- hexdump(stdout, "x", 2);
- hexdump(stdout, "foobar", 7);
- hexdump(stdout, "f\nobar", 7);
- hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23);
-
- for (i = 0; i < ELEMENTSOF(data); i++)
- data[i] = i*2;
-
- hexdump(stdout, data, sizeof(data));
-}
-
static void test_log2i(void) {
assert_se(log2i(1) == 0);
assert_se(log2i(2) == 1);
@@ -1023,341 +193,6 @@ static void test_log2i(void) {
assert_se(log2i(INT_MAX) == sizeof(int)*8-2);
}
-static void test_foreach_string(void) {
- const char * const t[] = {
- "foo",
- "bar",
- "waldo",
- NULL
- };
- const char *x;
- unsigned i = 0;
-
- FOREACH_STRING(x, "foo", "bar", "waldo")
- assert_se(streq_ptr(t[i++], x));
-
- assert_se(i == 3);
-
- FOREACH_STRING(x, "zzz")
- assert_se(streq(x, "zzz"));
-}
-
-static void test_filename_is_valid(void) {
- char foo[FILENAME_MAX+2];
- int i;
-
- assert_se(!filename_is_valid(""));
- assert_se(!filename_is_valid("/bar/foo"));
- assert_se(!filename_is_valid("/"));
- assert_se(!filename_is_valid("."));
- assert_se(!filename_is_valid(".."));
-
- for (i=0; i<FILENAME_MAX+1; i++)
- foo[i] = 'a';
- foo[FILENAME_MAX+1] = '\0';
-
- assert_se(!filename_is_valid(foo));
-
- assert_se(filename_is_valid("foo_bar-333"));
- assert_se(filename_is_valid("o.o"));
-}
-
-static void test_string_has_cc(void) {
- assert_se(string_has_cc("abc\1", NULL));
- assert_se(string_has_cc("abc\x7f", NULL));
- assert_se(string_has_cc("abc\x7f", NULL));
- assert_se(string_has_cc("abc\t\x7f", "\t"));
- assert_se(string_has_cc("abc\t\x7f", "\t"));
- assert_se(string_has_cc("\x7f", "\t"));
- assert_se(string_has_cc("\x7f", "\t\a"));
-
- assert_se(!string_has_cc("abc\t\t", "\t"));
- assert_se(!string_has_cc("abc\t\t\a", "\t\a"));
- assert_se(!string_has_cc("a\ab\tc", "\t\a"));
-}
-
-static void test_ascii_strlower(void) {
- char a[] = "AabBcC Jk Ii Od LKJJJ kkd LK";
- assert_se(streq(ascii_strlower(a), "aabbcc jk ii od lkjjj kkd lk"));
-}
-
-static void test_files_same(void) {
- _cleanup_close_ int fd = -1;
- char name[] = "/tmp/test-files_same.XXXXXX";
- char name_alias[] = "/tmp/test-files_same.alias";
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- assert_se(symlink(name, name_alias) >= 0);
-
- assert_se(files_same(name, name));
- assert_se(files_same(name, name_alias));
-
- unlink(name);
- unlink(name_alias);
-}
-
-static void test_is_valid_documentation_url(void) {
- assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd"));
- assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt"));
- assert_se(documentation_url_is_valid("file:/foo/foo"));
- assert_se(documentation_url_is_valid("man:systemd.special(7)"));
- assert_se(documentation_url_is_valid("info:bar"));
-
- assert_se(!documentation_url_is_valid("foo:"));
- assert_se(!documentation_url_is_valid("info:"));
- assert_se(!documentation_url_is_valid(""));
-}
-
-static void test_file_in_same_dir(void) {
- char *t;
-
- t = file_in_same_dir("/", "a");
- assert_se(streq(t, "/a"));
- free(t);
-
- t = file_in_same_dir("/", "/a");
- assert_se(streq(t, "/a"));
- free(t);
-
- t = file_in_same_dir("", "a");
- assert_se(streq(t, "a"));
- free(t);
-
- t = file_in_same_dir("a/", "a");
- assert_se(streq(t, "a/a"));
- free(t);
-
- t = file_in_same_dir("bar/foo", "bar");
- assert_se(streq(t, "bar/bar"));
- free(t);
-}
-
-static void test_endswith(void) {
- assert_se(endswith("foobar", "bar"));
- assert_se(endswith("foobar", ""));
- assert_se(endswith("foobar", "foobar"));
- assert_se(endswith("", ""));
-
- assert_se(!endswith("foobar", "foo"));
- assert_se(!endswith("foobar", "foobarfoofoo"));
-}
-
-static void test_endswith_no_case(void) {
- assert_se(endswith_no_case("fooBAR", "bar"));
- assert_se(endswith_no_case("foobar", ""));
- assert_se(endswith_no_case("foobar", "FOOBAR"));
- assert_se(endswith_no_case("", ""));
-
- assert_se(!endswith_no_case("foobar", "FOO"));
- assert_se(!endswith_no_case("foobar", "FOOBARFOOFOO"));
-}
-
-static void test_close_nointr(void) {
- char name[] = "/tmp/test-test-close_nointr.XXXXXX";
- int fd;
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- assert_se(close_nointr(fd) >= 0);
- assert_se(close_nointr(fd) < 0);
-
- unlink(name);
-}
-
-
-static void test_unlink_noerrno(void) {
- char name[] = "/tmp/test-close_nointr.XXXXXX";
- int fd;
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- assert_se(close_nointr(fd) >= 0);
-
- {
- PROTECT_ERRNO;
- errno = -42;
- assert_se(unlink_noerrno(name) >= 0);
- assert_se(errno == -42);
- assert_se(unlink_noerrno(name) < 0);
- assert_se(errno == -42);
- }
-}
-
-static void test_readlink_and_make_absolute(void) {
- char tempdir[] = "/tmp/test-readlink_and_make_absolute";
- char name[] = "/tmp/test-readlink_and_make_absolute/original";
- char name2[] = "test-readlink_and_make_absolute/original";
- char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias";
- char *r = NULL;
-
- assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0);
- assert_se(touch(name) >= 0);
-
- assert_se(symlink(name, name_alias) >= 0);
- assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
- assert_se(streq(r, name));
- free(r);
- assert_se(unlink(name_alias) >= 0);
-
- assert_se(chdir(tempdir) >= 0);
- assert_se(symlink(name2, name_alias) >= 0);
- assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
- assert_se(streq(r, name));
- free(r);
- assert_se(unlink(name_alias) >= 0);
-
- assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
-}
-
-static void test_ignore_signals(void) {
- assert_se(ignore_signals(SIGINT, -1) >= 0);
- assert_se(kill(getpid(), SIGINT) >= 0);
- assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
- assert_se(kill(getpid(), SIGUSR1) >= 0);
- assert_se(kill(getpid(), SIGUSR2) >= 0);
- assert_se(kill(getpid(), SIGTERM) >= 0);
- assert_se(kill(getpid(), SIGPIPE) >= 0);
- assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
-}
-
-static void test_strshorten(void) {
- char s[] = "foobar";
-
- assert_se(strlen(strshorten(s, 6)) == 6);
- assert_se(strlen(strshorten(s, 12)) == 6);
- assert_se(strlen(strshorten(s, 2)) == 2);
- assert_se(strlen(strshorten(s, 0)) == 0);
-}
-
-static void test_strjoina(void) {
- char *actual;
-
- actual = strjoina("", "foo", "bar");
- assert_se(streq(actual, "foobar"));
-
- actual = strjoina("foo", "bar", "baz");
- assert_se(streq(actual, "foobarbaz"));
-
- actual = strjoina("foo", "", "bar", "baz");
- assert_se(streq(actual, "foobarbaz"));
-
- actual = strjoina("foo");
- assert_se(streq(actual, "foo"));
-
- actual = strjoina(NULL);
- assert_se(streq(actual, ""));
-
- actual = strjoina(NULL, "foo");
- assert_se(streq(actual, ""));
-
- actual = strjoina("foo", NULL, "bar");
- assert_se(streq(actual, "foo"));
-}
-
-static void test_is_symlink(void) {
- char name[] = "/tmp/test-is_symlink.XXXXXX";
- char name_link[] = "/tmp/test-is_symlink.link";
- _cleanup_close_ int fd = -1;
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- assert_se(symlink(name, name_link) >= 0);
-
- assert_se(is_symlink(name) == 0);
- assert_se(is_symlink(name_link) == 1);
- assert_se(is_symlink("/a/file/which/does/not/exist/i/guess") < 0);
-
-
- unlink(name);
- unlink(name_link);
-}
-
-static void test_search_and_fopen(void) {
- const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
- char name[] = "/tmp/test-search_and_fopen.XXXXXX";
- int fd = -1;
- int r;
- FILE *f;
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- close(fd);
-
- r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
- assert_se(r >= 0);
- fclose(f);
-
- r = search_and_fopen(name, "r", NULL, dirs, &f);
- assert_se(r >= 0);
- fclose(f);
-
- r = search_and_fopen(basename(name), "r", "/", dirs, &f);
- assert_se(r >= 0);
- fclose(f);
-
- r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
- assert_se(r < 0);
- r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
- assert_se(r < 0);
-
- r = unlink(name);
- assert_se(r == 0);
-
- r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
- assert_se(r < 0);
-}
-
-
-static void test_search_and_fopen_nulstr(void) {
- const char dirs[] = "/tmp/foo/bar\0/tmp\0";
- char name[] = "/tmp/test-search_and_fopen.XXXXXX";
- int fd = -1;
- int r;
- FILE *f;
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- close(fd);
-
- r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
- assert_se(r >= 0);
- fclose(f);
-
- r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f);
- assert_se(r >= 0);
- fclose(f);
-
- r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
- assert_se(r < 0);
- r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
- assert_se(r < 0);
-
- r = unlink(name);
- assert_se(r == 0);
-
- r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
- assert_se(r < 0);
-}
-
-static void test_glob_exists(void) {
- char name[] = "/tmp/test-glob_exists.XXXXXX";
- int fd = -1;
- int r;
-
- fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
- assert_se(fd >= 0);
- close(fd);
-
- r = glob_exists("/tmp/test-glob_exists*");
- assert_se(r == 1);
-
- r = unlink(name);
- assert_se(r == 0);
- r = glob_exists("/tmp/test-glob_exists*");
- assert_se(r == 0);
-}
-
static void test_execute_directory(void) {
char template_lo[] = "/tmp/test-readlink_and_make_absolute-lo.XXXXXXX";
char template_hi[] = "/tmp/test-readlink_and_make_absolute-hi.XXXXXXX";
@@ -1402,17 +237,6 @@ static void test_execute_directory(void) {
(void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
}
-static int parse_item(const char *key, const char *value) {
- assert_se(key);
-
- log_info("kernel cmdline option <%s> = <%s>", key, strna(value));
- return 0;
-}
-
-static void test_parse_proc_cmdline(void) {
- assert_se(parse_proc_cmdline(parse_item) >= 0);
-}
-
static void test_raw_clone(void) {
pid_t parent, pid, pid2;
@@ -1438,285 +262,20 @@ static void test_raw_clone(void) {
}
}
-static void test_same_fd(void) {
- _cleanup_close_pair_ int p[2] = { -1, -1 };
- _cleanup_close_ int a = -1, b = -1, c = -1;
-
- assert_se(pipe2(p, O_CLOEXEC) >= 0);
- assert_se((a = dup(p[0])) >= 0);
- assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0);
- assert_se((c = dup(a)) >= 0);
-
- assert_se(same_fd(p[0], p[0]) > 0);
- assert_se(same_fd(p[1], p[1]) > 0);
- assert_se(same_fd(a, a) > 0);
- assert_se(same_fd(b, b) > 0);
-
- assert_se(same_fd(a, p[0]) > 0);
- assert_se(same_fd(p[0], a) > 0);
- assert_se(same_fd(c, p[0]) > 0);
- assert_se(same_fd(p[0], c) > 0);
- assert_se(same_fd(a, c) > 0);
- assert_se(same_fd(c, a) > 0);
-
- assert_se(same_fd(p[0], p[1]) == 0);
- assert_se(same_fd(p[1], p[0]) == 0);
- assert_se(same_fd(p[0], b) == 0);
- assert_se(same_fd(b, p[0]) == 0);
- assert_se(same_fd(p[1], a) == 0);
- assert_se(same_fd(a, p[1]) == 0);
- assert_se(same_fd(p[1], b) == 0);
- assert_se(same_fd(b, p[1]) == 0);
-
- assert_se(same_fd(a, b) == 0);
- assert_se(same_fd(b, a) == 0);
-}
-
-static void test_uid_ptr(void) {
-
- assert_se(UID_TO_PTR(0) != NULL);
- assert_se(UID_TO_PTR(1000) != NULL);
-
- assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0);
- assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
-}
-
-static void test_sparse_write_one(int fd, const char *buffer, size_t n) {
- char check[n];
-
- assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(ftruncate(fd, 0) >= 0);
- assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n);
-
- assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n);
- assert_se(ftruncate(fd, n) >= 0);
-
- assert_se(lseek(fd, 0, SEEK_SET) == 0);
- assert_se(read(fd, check, n) == (ssize_t) n);
-
- assert_se(memcmp(buffer, check, n) == 0);
-}
-
-static void test_sparse_write(void) {
- const char test_a[] = "test";
- const char test_b[] = "\0\0\0\0test\0\0\0\0";
- const char test_c[] = "\0\0test\0\0\0\0";
- const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0";
- const char test_e[] = "test\0\0\0\0test";
- _cleanup_close_ int fd = -1;
- char fn[] = "/tmp/sparseXXXXXX";
-
- fd = mkostemp(fn, O_CLOEXEC);
- assert_se(fd >= 0);
- unlink(fn);
-
- test_sparse_write_one(fd, test_a, sizeof(test_a));
- test_sparse_write_one(fd, test_b, sizeof(test_b));
- test_sparse_write_one(fd, test_c, sizeof(test_c));
- test_sparse_write_one(fd, test_d, sizeof(test_d));
- test_sparse_write_one(fd, test_e, sizeof(test_e));
-}
-
-static void test_shell_escape_one(const char *s, const char *bad, const char *expected) {
- _cleanup_free_ char *r;
-
- assert_se(r = shell_escape(s, bad));
- assert_se(streq_ptr(r, expected));
-}
-
-static void test_shell_escape(void) {
- test_shell_escape_one("", "", "");
- test_shell_escape_one("\\", "", "\\\\");
- test_shell_escape_one("foobar", "", "foobar");
- test_shell_escape_one("foobar", "o", "f\\o\\obar");
- test_shell_escape_one("foo:bar,baz", ",:", "foo\\:bar\\,baz");
-}
-
-static void test_shell_maybe_quote_one(const char *s, const char *expected) {
- _cleanup_free_ char *r;
-
- assert_se(r = shell_maybe_quote(s));
- assert_se(streq(r, expected));
-}
-
-static void test_shell_maybe_quote(void) {
-
- test_shell_maybe_quote_one("", "");
- test_shell_maybe_quote_one("\\", "\"\\\\\"");
- test_shell_maybe_quote_one("\"", "\"\\\"\"");
- test_shell_maybe_quote_one("foobar", "foobar");
- test_shell_maybe_quote_one("foo bar", "\"foo bar\"");
- test_shell_maybe_quote_one("foo \"bar\" waldo", "\"foo \\\"bar\\\" waldo\"");
- test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\"");
-}
-
-static void test_tempfn(void) {
- char *ret = NULL, *p;
-
- assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0);
- assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX"));
- free(ret);
-
- assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0);
- assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX"));
- free(ret);
-
- assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0);
- assert_se(p = startswith(ret, "/foo/bar/.#waldo"));
- assert_se(strlen(p) == 16);
- assert_se(in_charset(p, "0123456789abcdef"));
- free(ret);
-
- assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0);
- assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo"));
- assert_se(strlen(p) == 16);
- assert_se(in_charset(p, "0123456789abcdef"));
- free(ret);
-
- assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0);
- assert_se(p = startswith(ret, "/foo/bar/waldo/.#"));
- assert_se(strlen(p) == 16);
- assert_se(in_charset(p, "0123456789abcdef"));
- free(ret);
-
- assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0);
- assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]"));
- assert_se(strlen(p) == 16);
- assert_se(in_charset(p, "0123456789abcdef"));
- free(ret);
-}
-
-static void test_strcmp_ptr(void) {
- assert_se(strcmp_ptr(NULL, NULL) == 0);
- assert_se(strcmp_ptr("", NULL) > 0);
- assert_se(strcmp_ptr("foo", NULL) > 0);
- assert_se(strcmp_ptr(NULL, "") < 0);
- assert_se(strcmp_ptr(NULL, "bar") < 0);
- assert_se(strcmp_ptr("foo", "bar") > 0);
- assert_se(strcmp_ptr("bar", "baz") < 0);
- assert_se(strcmp_ptr("foo", "foo") == 0);
- 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();
- test_streq_ptr();
test_align_power2();
test_max();
test_container_of();
- test_alloca();
test_div_round_up();
- test_first_word();
- test_close_many();
- test_parse_uid();
- test_strappend();
- test_strstrip();
- test_delete_chars();
- test_in_charset();
- test_hexchar();
- test_unhexchar();
- test_base32hexchar();
- test_unbase32hexchar();
- test_base64char();
- test_unbase64char();
- test_octchar();
- test_unoctchar();
- test_decchar();
- test_undecchar();
- test_unhexmem();
- test_base32hexmem();
- test_unbase32hexmem();
- test_base64mem();
- test_unbase64mem();
- test_cescape();
- test_cunescape();
- test_foreach_word();
- test_foreach_word_quoted();
- test_memdup_multiply();
test_u64log2();
test_protect_errno();
- test_parse_cpu_set();
- test_config_parse_iec_uint64();
- test_strextend();
- test_strrep();
- test_split_pair();
- test_fstab_node_to_udev_node();
- test_get_files_in_directory();
test_in_set();
- test_writing_tmpfile();
- test_hexdump();
test_log2i();
- test_foreach_string();
- test_filename_is_valid();
- test_string_has_cc();
- test_ascii_strlower();
- test_files_same();
- test_is_valid_documentation_url();
- test_file_in_same_dir();
- test_endswith();
- test_endswith_no_case();
- test_close_nointr();
- test_unlink_noerrno();
- test_readlink_and_make_absolute();
- test_ignore_signals();
- test_strshorten();
- test_strjoina();
- test_is_symlink();
- test_search_and_fopen();
- test_search_and_fopen_nulstr();
- test_glob_exists();
test_execute_directory();
- test_parse_proc_cmdline();
test_raw_clone();
- test_same_fd();
- test_uid_ptr();
- test_sparse_write();
- test_shell_escape();
- test_shell_maybe_quote();
- test_tempfn();
- test_strcmp_ptr();
- test_fgetxattrat_fake();
- test_runlevel_to_target();
return 0;
}
diff --git a/src/test/test-web-util.c b/src/test/test-web-util.c
new file mode 100644
index 0000000000..79a3a13af6
--- /dev/null
+++ b/src/test/test-web-util.c
@@ -0,0 +1,39 @@
+/***
+ 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"
+#include "web-util.h"
+
+static void test_is_valid_documentation_url(void) {
+ assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd"));
+ assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt"));
+ assert_se(documentation_url_is_valid("file:/foo/foo"));
+ assert_se(documentation_url_is_valid("man:systemd.special(7)"));
+ assert_se(documentation_url_is_valid("info:bar"));
+
+ assert_se(!documentation_url_is_valid("foo:"));
+ assert_se(!documentation_url_is_valid("info:"));
+ assert_se(!documentation_url_is_valid(""));
+}
+
+int main(int argc, char *argv[]) {
+ test_is_valid_documentation_url();
+
+ return 0;
+}
diff --git a/src/test/test-xattr-util.c b/src/test/test-xattr-util.c
new file mode 100644
index 0000000000..267f29426c
--- /dev/null
+++ b/src/test/test-xattr-util.c
@@ -0,0 +1,69 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "macro.h"
+#include "string-util.h"
+#include "xattr-util.h"
+
+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);
+}
+
+int main(void) {
+ test_fgetxattrat_fake();
+
+ return 0;
+}
diff --git a/src/udev/Makefile b/src/udev/Makefile
index 8449d56635..1c8fbe52a6 100644
--- a/src/udev/Makefile
+++ b/src/udev/Makefile
@@ -29,7 +29,8 @@ INSTALL_DIRS += \
dist_network_DATA = \
network/99-default.link \
network/80-container-host0.network \
- network/80-container-ve.network
+ network/80-container-ve.network \
+ network/80-container-vz.network
dist_udevrules_DATA += \
rules/50-udev-default.rules \
diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h
index caea5c2693..68e4954537 100644
--- a/src/udev/mtd_probe/mtd_probe.h
+++ b/src/udev/mtd_probe/mtd_probe.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) 2010 - Maxim Levitsky
*
@@ -17,8 +19,6 @@
* Boston, MA 02110-1301 USA
*/
-#pragma once
-
#include <mtd/mtd-user.h>
#include "macro.h"
diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c
index 6a6c5522a7..2a7ba17637 100644
--- a/src/udev/mtd_probe/probe_smartmedia.c
+++ b/src/udev/mtd_probe/probe_smartmedia.c
@@ -73,7 +73,7 @@ void probe_smart_media(int mtd_fd, mtd_info_t* info)
for (offset = 0 ; offset < block_size * spare_count ;
offset += sector_size) {
lseek(mtd_fd, SEEK_SET, offset);
- if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE){
+ if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE) {
cis_found = 1;
break;
}
diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h
index 2e6e1d7150..7716516e76 100644
--- a/src/udev/net/ethtool-util.h
+++ b/src/udev/net/ethtool-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include <macro.h>
/* we can't use DUPLEX_ prefix, as it
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index e712d2ce73..350cd24e9c 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -18,7 +18,6 @@
***/
#include <netinet/ether.h>
-#include <linux/netdevice.h>
#include <systemd/sd-netlink.h>
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index f525fe2116..9df5529d05 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -1,3 +1,5 @@
+#pragma once
+
/***
This file is part of systemd.
@@ -17,8 +19,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#pragma once
-
#include "libudev.h"
#include "condition.h"
diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h
index 3bf1a94200..a27a84a40a 100644
--- a/src/udev/scsi_id/scsi.h
+++ b/src/udev/scsi_id/scsi.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* scsi.h
*
@@ -10,8 +12,6 @@
* Free Software Foundation version 2 of the License.
*/
-#pragma once
-
#include <scsi/scsi.h>
struct scsi_ioctl_command {
diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h
index 141b116a88..5c2e1c28ee 100644
--- a/src/udev/scsi_id/scsi_id.h
+++ b/src/udev/scsi_id/scsi_id.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) IBM Corp. 2003
*
@@ -15,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
-
#define MAX_PATH_LEN 512
/*
diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c
index 3a3d8a1770..51a55cdbc4 100644
--- a/src/udev/udev-builtin-input_id.c
+++ b/src/udev/udev-builtin-input_id.c
@@ -177,7 +177,7 @@ static bool test_pointers(struct udev_device *dev,
has_mt_coordinates = test_bit(ABS_MT_POSITION_X, bitmask_abs) && test_bit(ABS_MT_POSITION_Y, bitmask_abs);
/* unset has_mt_coordinates if devices claims to have all abs axis */
- if(has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs))
+ if (has_mt_coordinates && test_bit(ABS_MT_SLOT, bitmask_abs) && test_bit(ABS_MT_SLOT - 1, bitmask_abs))
has_mt_coordinates = false;
is_direct = test_bit(INPUT_PROP_DIRECT, bitmask_props);
has_touch = test_bit(BTN_TOUCH, bitmask_key);
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 8b1bcefe2d..a7be2a4eed 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -27,21 +27,21 @@
* http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames
*
* Two character prefixes based on the type of interface:
- * en -- Ethernet
- * sl -- serial line IP (slip)
- * wl -- wlan
- * ww -- wwan
+ * en — Ethernet
+ * sl — serial line IP (slip)
+ * wl — wlan
+ * ww — wwan
*
* Type of names:
- * b<number> -- BCMA bus core number
- * c<bus_id> -- CCW bus group name, without leading zeros [s390]
- * o<index>[d<dev_port>] -- on-board device index number
- * s<slot>[f<function>][d<dev_port>] -- hotplug slot index number
- * x<MAC> -- MAC address
+ * b<number> — BCMA bus core number
+ * c<bus_id> — CCW bus group name, without leading zeros [s390]
+ * o<index>[d<dev_port>] — on-board device index number
+ * s<slot>[f<function>][d<dev_port>] — hotplug slot index number
+ * x<MAC> — MAC address
* [P<domain>]p<bus>s<slot>[f<function>][d<dev_port>]
- * -- PCI geographical location
+ * — PCI geographical location
* [P<domain>]p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>]
- * -- USB port number chain
+ * — USB port number chain
*
* All multi-function PCI devices will carry the [f<function>] number in the
* device name, including the function 0 device.
@@ -140,9 +140,9 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) {
const char *attr;
int idx;
- /* ACPI _DSM -- device specific method for naming a PCI or PCI Express device */
+ /* ACPI _DSM — device specific method for naming a PCI or PCI Express device */
attr = udev_device_get_sysattr_value(names->pcidev, "acpi_index");
- /* SMBIOS type 41 -- Onboard Devices Extended Information */
+ /* SMBIOS type 41 — Onboard Devices Extended Information */
if (!attr)
attr = udev_device_get_sysattr_value(names->pcidev, "index");
if (!attr)
@@ -230,7 +230,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) {
if (l == 0)
names->pci_path[0] = '\0';
- /* ACPI _SUN -- slot user number */
+ /* ACPI _SUN — slot user number */
pci = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci");
if (!pci) {
err = -ENOENT;
diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c
index b6ed45d8ba..6e9adc6e96 100644
--- a/src/udev/udev-builtin-path_id.c
+++ b/src/udev/udev-builtin-path_id.c
@@ -712,7 +712,7 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool
* devices do not expose their buses and do not provide a unique
* and predictable name that way.
*/
- if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport)
+ if (streq_ptr(udev_device_get_subsystem(dev), "block") && !supported_transport)
path = mfree(path);
if (path != NULL) {
diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c
index 962de22f43..f68a09d7a8 100644
--- a/src/udev/udev-ctrl.c
+++ b/src/udev/udev-ctrl.c
@@ -105,7 +105,7 @@ struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd) {
uctrl->saddr.un.sun_family = AF_LOCAL;
strscpy(uctrl->saddr.un.sun_path, sizeof(uctrl->saddr.un.sun_path), "/run/udev/control");
- uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.un.sun_path);
+ uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un);
return uctrl;
}
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index c06ace09cf..26fa52cf6c 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -33,9 +33,11 @@
#include "conf-files.h"
#include "escape.h"
#include "fd-util.h"
+#include "fs-util.h"
#include "glob-util.h"
#include "path-util.h"
#include "stat-util.h"
+#include "stdio-util.h"
#include "strbuf.h"
#include "string-util.h"
#include "strv.h"
@@ -327,8 +329,8 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
enum token_type type = token->type;
enum operation_type op = token->key.op;
enum string_glob_type glob = token->key.glob;
- const char *value = str(rules, token->key.value_off);
- const char *attr = &rules->buf[token->key.attr_off];
+ const char *value = rules_str(rules, token->key.value_off);
+ const char *attr = &rules->strbuf->buf[token->key.attr_off];
switch (type) {
case TK_RULE:
@@ -338,9 +340,9 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token);
log_debug("* RULE %s:%u, token: %u, count: %u, label: '%s'",
- &rules->buf[token->rule.filename_off], token->rule.filename_line,
+ &rules->strbuf->buf[token->rule.filename_off], token->rule.filename_line,
idx, token->rule.token_count,
- &rules->buf[token->rule.label_off]);
+ &rules->strbuf->buf[token->rule.label_off]);
break;
}
case TK_M_ACTION:
@@ -437,11 +439,11 @@ static void dump_token(struct udev_rules *rules, struct token *token) {
static void dump_rules(struct udev_rules *rules) {
unsigned int i;
- log_debug("dumping %u (%zu bytes) tokens, %u (%zu bytes) strings",
+ log_debug("dumping %u (%zu bytes) tokens, %zu (%zu bytes) strings",
rules->token_cur,
rules->token_cur * sizeof(struct token),
- rules->buf_count,
- rules->buf_cur);
+ rules->strbuf->nodes_count,
+ rules->strbuf->len);
for (i = 0; i < rules->token_cur; i++)
dump_token(rules, &rules->tokens[i]);
}
@@ -686,41 +688,31 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi
return 0;
}
-static int attr_subst_subdir(char *attr, size_t len) {
- bool found = false;
+static void attr_subst_subdir(char *attr, size_t len) {
+ const char *pos, *tail, *path;
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *dent;
- if (strstr(attr, "/*/")) {
- char *pos;
- char dirname[UTIL_PATH_SIZE];
- const char *tail;
- DIR *dir;
+ pos = strstr(attr, "/*/");
+ if (!pos)
+ return;
- strscpy(dirname, sizeof(dirname), attr);
- pos = strstr(dirname, "/*/");
- if (pos == NULL)
- return -1;
- pos[0] = '\0';
- tail = &pos[2];
- dir = opendir(dirname);
- if (dir != NULL) {
- struct dirent *dent;
+ tail = pos + 2;
+ path = strndupa(attr, pos - attr + 1); /* include slash at end */
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
- for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
- struct stat stats;
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir))
+ if (dent->d_name[0] != '.') {
+ char n[strlen(dent->d_name) + strlen(tail) + 1];
- if (dent->d_name[0] == '.')
- continue;
- strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL);
- if (stat(attr, &stats) == 0) {
- found = true;
- break;
- }
+ strscpyl(n, sizeof n, dent->d_name, tail, NULL);
+ if (faccessat(dirfd(dir), n, F_OK, 0) == 0) {
+ strscpyl(attr, len, path, n, NULL);
+ break;
}
- closedir(dir);
}
- }
-
- return found;
}
static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value) {
@@ -831,12 +823,13 @@ static const char *get_key_attribute(struct udev *udev, char *str) {
return NULL;
}
-static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
- enum operation_type op,
- const char *value, const void *data) {
- struct token *token = &rule_tmp->token[rule_tmp->token_cur];
+static void rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
+ enum operation_type op,
+ const char *value, const void *data) {
+ struct token *token = rule_tmp->token + rule_tmp->token_cur;
const char *attr = NULL;
+ assert(rule_tmp->token_cur < ELEMENTSOF(rule_tmp->token));
memzero(token, sizeof(struct token));
switch (type) {
@@ -919,8 +912,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
case TK_M_MAX:
case TK_END:
case TK_UNSET:
- log_error("wrong type %u", type);
- return -1;
+ assert_not_reached("wrong type");
}
if (value != NULL && type < TK_M_MAX) {
@@ -969,11 +961,6 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
token->key.type = type;
token->key.op = op;
rule_tmp->token_cur++;
- if (rule_tmp->token_cur >= ELEMENTSOF(rule_tmp->token)) {
- log_error("temporary rule array too small");
- return -1;
- }
- return 0;
}
static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) {
@@ -1010,8 +997,13 @@ static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) {
return 0;
}
-static int add_rule(struct udev_rules *rules, char *line,
- const char *filename, unsigned int filename_off, unsigned int lineno) {
+#define LOG_RULE_ERROR(fmt, ...) log_error("Invalid rule %s:%u: " fmt, filename, lineno, ##__VA_ARGS__)
+#define LOG_RULE_WARNING(fmt, ...) log_warning("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__)
+#define LOG_RULE_DEBUG(fmt, ...) log_debug("%s:%u: " fmt, filename, lineno, ##__VA_ARGS__)
+#define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; }
+
+static void add_rule(struct udev_rules *rules, char *line,
+ const char *filename, unsigned int filename_off, unsigned int lineno) {
char *linepos;
const char *attr;
struct rule_tmp rule_tmp = {
@@ -1052,427 +1044,322 @@ static int add_rule(struct udev_rules *rules, char *line,
break;
}
+ if (rule_tmp.token_cur >= ELEMENTSOF(rule_tmp.token))
+ LOG_AND_RETURN("temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur);
+
if (streq(key, "ACTION")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid ACTION operation");
- goto invalid;
- }
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL);
- continue;
- }
- if (streq(key, "DEVPATH")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid DEVPATH operation");
- goto invalid;
- }
+ } else if (streq(key, "DEVPATH")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL);
- continue;
- }
- if (streq(key, "KERNEL")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid KERNEL operation");
- goto invalid;
- }
+ } else if (streq(key, "KERNEL")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL);
- continue;
- }
- if (streq(key, "SUBSYSTEM")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid SUBSYSTEM operation");
- goto invalid;
- }
+ } else if (streq(key, "SUBSYSTEM")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
/* bus, class, subsystem events should all be the same */
- if (streq(value, "subsystem") ||
- streq(value, "bus") ||
- streq(value, "class")) {
- if (streq(value, "bus") || streq(value, "class"))
- log_error("'%s' must be specified as 'subsystem' "
- "please fix it in %s:%u", value, filename, lineno);
+ if (STR_IN_SET(value, "subsystem", "bus", "class")) {
+ if (!streq(value, "subsystem"))
+ LOG_RULE_WARNING("'%s' must be specified as 'subsystem'; please fix", value);
+
rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL);
} else
rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL);
- continue;
- }
- if (streq(key, "DRIVER")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid DRIVER operation");
- goto invalid;
- }
+ } else if (streq(key, "DRIVER")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL);
- continue;
- }
- if (startswith(key, "ATTR{")) {
+ } else if (startswith(key, "ATTR{")) {
attr = get_key_attribute(rules->udev, key + strlen("ATTR"));
- if (attr == NULL) {
- log_error("error parsing ATTR attribute");
- goto invalid;
- }
- if (op == OP_REMOVE) {
- log_error("invalid ATTR operation");
- goto invalid;
- }
+ if (attr == NULL)
+ LOG_AND_RETURN("error parsing %s attribute", "ATTR");
+
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", "ATTR");
+
if (op < OP_MATCH_MAX)
rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr);
else
rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr);
- continue;
- }
- if (startswith(key, "SYSCTL{")) {
+ } else if (startswith(key, "SYSCTL{")) {
attr = get_key_attribute(rules->udev, key + strlen("SYSCTL"));
- if (attr == NULL) {
- log_error("error parsing SYSCTL attribute");
- goto invalid;
- }
- if (op == OP_REMOVE) {
- log_error("invalid SYSCTL operation");
- goto invalid;
- }
+ if (attr == NULL)
+ LOG_AND_RETURN("error parsing %s attribute", "ATTR");
+
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", "ATTR");
+
if (op < OP_MATCH_MAX)
rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr);
else
rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr);
- continue;
- }
- if (startswith(key, "SECLABEL{")) {
+ } else if (startswith(key, "SECLABEL{")) {
attr = get_key_attribute(rules->udev, key + strlen("SECLABEL"));
- if (!attr) {
- log_error("error parsing SECLABEL attribute");
- goto invalid;
- }
- if (op == OP_REMOVE) {
- log_error("invalid SECLABEL operation");
- goto invalid;
- }
+ if (attr == NULL)
+ LOG_AND_RETURN("error parsing %s attribute", "SECLABEL");
+
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", "SECLABEL");
rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr);
- continue;
- }
- if (streq(key, "KERNELS")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid KERNELS operation");
- goto invalid;
- }
+ } else if (streq(key, "KERNELS")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
- continue;
- }
- if (streq(key, "SUBSYSTEMS")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid SUBSYSTEMS operation");
- goto invalid;
- }
+ } else if (streq(key, "SUBSYSTEMS")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
- continue;
- }
- if (streq(key, "DRIVERS")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid DRIVERS operation");
- goto invalid;
- }
+ } else if (streq(key, "DRIVERS")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
- continue;
- }
- if (startswith(key, "ATTRS{")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid ATTRS operation");
- goto invalid;
- }
+ } else if (startswith(key, "ATTRS{")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", "ATTRS");
+
attr = get_key_attribute(rules->udev, key + strlen("ATTRS"));
- if (attr == NULL) {
- log_error("error parsing ATTRS attribute");
- goto invalid;
- }
+ if (attr == NULL)
+ LOG_AND_RETURN("error parsing %s attribute", "ATTRS");
+
if (startswith(attr, "device/"))
- log_error("the 'device' link may not be available in a future kernel, "
- "please fix it in %s:%u", filename, lineno);
- else if (strstr(attr, "../") != NULL)
- log_error("do not reference parent sysfs directories directly, "
- "it may break with a future kernel, please fix it in %s:%u", filename, lineno);
+ LOG_RULE_WARNING("'device' link may not be available in future kernels; please fix");
+ if (strstr(attr, "../") != NULL)
+ LOG_RULE_WARNING("direct reference to parent sysfs directory, may break in future kernels; please fix");
rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
- continue;
- }
- if (streq(key, "TAGS")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid TAGS operation");
- goto invalid;
- }
+ } else if (streq(key, "TAGS")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL);
- continue;
- }
- if (startswith(key, "ENV{")) {
+ } else if (startswith(key, "ENV{")) {
attr = get_key_attribute(rules->udev, key + strlen("ENV"));
- if (attr == NULL) {
- log_error("error parsing ENV attribute");
- goto invalid;
- }
- if (op == OP_REMOVE) {
- log_error("invalid ENV operation");
- goto invalid;
- }
- if (op < OP_MATCH_MAX) {
- if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0)
- goto invalid;
- } else {
- static const char *blacklist[] = {
- "ACTION",
- "SUBSYSTEM",
- "DEVTYPE",
- "MAJOR",
- "MINOR",
- "DRIVER",
- "IFINDEX",
- "DEVNAME",
- "DEVLINKS",
- "DEVPATH",
- "TAGS",
- };
- unsigned int i;
-
- for (i = 0; i < ELEMENTSOF(blacklist); i++) {
- if (!streq(attr, blacklist[i]))
- continue;
- log_error("invalid ENV attribute, '%s' can not be set %s:%u", attr, filename, lineno);
- goto invalid;
- }
- if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0)
- goto invalid;
- }
- continue;
- }
+ if (attr == NULL)
+ LOG_AND_RETURN("error parsing %s attribute", "ENV");
+
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", "ENV");
- if (streq(key, "TAG")) {
+ if (op < OP_MATCH_MAX)
+ rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr);
+ else {
+ if (STR_IN_SET(attr,
+ "ACTION",
+ "SUBSYSTEM",
+ "DEVTYPE",
+ "MAJOR",
+ "MINOR",
+ "DRIVER",
+ "IFINDEX",
+ "DEVNAME",
+ "DEVLINKS",
+ "DEVPATH",
+ "TAGS"))
+ LOG_AND_RETURN("invalid ENV attribute, '%s' cannot be set", attr);
+
+ rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr);
+ }
+
+ } else if (streq(key, "TAG")) {
if (op < OP_MATCH_MAX)
rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL);
else
rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL);
- continue;
- }
- if (streq(key, "PROGRAM")) {
- if (op == OP_REMOVE) {
- log_error("invalid PROGRAM operation");
- goto invalid;
- }
+ } else if (streq(key, "PROGRAM")) {
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
- continue;
- }
- if (streq(key, "RESULT")) {
- if (op > OP_MATCH_MAX) {
- log_error("invalid RESULT operation");
- goto invalid;
- }
+ } else if (streq(key, "RESULT")) {
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL);
- continue;
- }
- if (startswith(key, "IMPORT")) {
+ } else if (startswith(key, "IMPORT")) {
attr = get_key_attribute(rules->udev, key + strlen("IMPORT"));
if (attr == NULL) {
- log_error("IMPORT{} type missing, ignoring IMPORT %s:%u", filename, lineno);
+ LOG_RULE_WARNING("ignoring IMPORT{} with missing type");
continue;
}
- if (op == OP_REMOVE) {
- log_error("invalid IMPORT operation");
- goto invalid;
- }
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", "IMPORT");
+
if (streq(attr, "program")) {
/* find known built-in command */
if (value[0] != '/') {
- enum udev_builtin_cmd cmd;
+ const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
- cmd = udev_builtin_lookup(value);
if (cmd < UDEV_BUILTIN_MAX) {
- log_debug("IMPORT found builtin '%s', replacing %s:%u",
- value, filename, lineno);
+ LOG_RULE_DEBUG("IMPORT found builtin '%s', replacing", value);
rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
continue;
}
}
rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
} else if (streq(attr, "builtin")) {
- enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
+ const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
- if (cmd < UDEV_BUILTIN_MAX)
- rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
+ if (cmd >= UDEV_BUILTIN_MAX)
+ LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown", value);
else
- log_error("IMPORT{builtin}: '%s' unknown %s:%u", value, filename, lineno);
- } else if (streq(attr, "file")) {
+ rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
+ } else if (streq(attr, "file"))
rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
- } else if (streq(attr, "db")) {
+ else if (streq(attr, "db"))
rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
- } else if (streq(attr, "cmdline")) {
+ else if (streq(attr, "cmdline"))
rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
- } else if (streq(attr, "parent")) {
+ else if (streq(attr, "parent"))
rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
- } else
- log_error("IMPORT{} unknown type, ignoring IMPORT %s:%u", filename, lineno);
- continue;
- }
+ else
+ LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "IMPORT", attr);
- if (startswith(key, "TEST")) {
+ } else if (startswith(key, "TEST")) {
mode_t mode = 0;
- if (op > OP_MATCH_MAX) {
- log_error("invalid TEST operation");
- goto invalid;
- }
+ if (op > OP_MATCH_MAX)
+ LOG_AND_RETURN("invalid %s operation", "TEST");
+
attr = get_key_attribute(rules->udev, key + strlen("TEST"));
if (attr != NULL) {
mode = strtol(attr, NULL, 8);
rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode);
- } else {
+ } else
rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL);
- }
- continue;
- }
- if (startswith(key, "RUN")) {
+ } else if (startswith(key, "RUN")) {
attr = get_key_attribute(rules->udev, key + strlen("RUN"));
if (attr == NULL)
attr = "program";
- if (op == OP_REMOVE) {
- log_error("invalid RUN operation");
- goto invalid;
- }
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", "RUN");
if (streq(attr, "builtin")) {
- enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
+ const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
if (cmd < UDEV_BUILTIN_MAX)
rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd);
else
- log_error("RUN{builtin}: '%s' unknown %s:%u", value, filename, lineno);
+ LOG_RULE_ERROR("RUN{builtin}: '%s' unknown", value);
} else if (streq(attr, "program")) {
- enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX;
+ const enum udev_builtin_cmd cmd = UDEV_BUILTIN_MAX;
rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd);
- } else {
- log_error("RUN{} unknown type, ignoring RUN %s:%u", filename, lineno);
- }
+ } else
+ LOG_RULE_ERROR("ignoring unknown %s{} type '%s'", "RUN", attr);
- continue;
- }
+ } else if (streq(key, "LABEL")) {
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
- if (streq(key, "LABEL")) {
- if (op == OP_REMOVE) {
- log_error("invalid LABEL operation");
- goto invalid;
- }
rule_tmp.rule.rule.label_off = rules_add_string(rules, value);
- continue;
- }
- if (streq(key, "GOTO")) {
- if (op == OP_REMOVE) {
- log_error("invalid GOTO operation");
- goto invalid;
- }
+ } else if (streq(key, "GOTO")) {
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
+
rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL);
- continue;
- }
- if (startswith(key, "NAME")) {
- if (op == OP_REMOVE) {
- log_error("invalid NAME operation");
- goto invalid;
- }
- if (op < OP_MATCH_MAX) {
+ } else if (startswith(key, "NAME")) {
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
+
+ if (op < OP_MATCH_MAX)
rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL);
- } else {
+ else {
if (streq(value, "%k")) {
- log_error("NAME=\"%%k\" is ignored, because it breaks kernel supplied names, "
- "please remove it from %s:%u\n", filename, lineno);
+ LOG_RULE_WARNING("NAME=\"%%k\" is ignored, because it breaks kernel supplied names; please remove");
continue;
}
- if (value[0] == '\0') {
- log_debug("NAME=\"\" is ignored, because udev will not delete any device nodes, "
- "please remove it from %s:%u\n", filename, lineno);
+ if (isempty(value)) {
+ LOG_RULE_DEBUG("NAME=\"\" is ignored, because udev will not delete any device nodes; please remove");
continue;
}
rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL);
}
rule_tmp.rule.rule.can_set_name = true;
- continue;
- }
- if (streq(key, "SYMLINK")) {
- if (op == OP_REMOVE) {
- log_error("invalid SYMLINK operation");
- goto invalid;
- }
+ } else if (streq(key, "SYMLINK")) {
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
+
if (op < OP_MATCH_MAX)
rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
else
rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL);
rule_tmp.rule.rule.can_set_name = true;
- continue;
- }
- if (streq(key, "OWNER")) {
+ } else if (streq(key, "OWNER")) {
uid_t uid;
char *endptr;
- if (op == OP_REMOVE) {
- log_error("invalid OWNER operation");
- goto invalid;
- }
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
uid = strtoul(value, &endptr, 10);
- if (endptr[0] == '\0') {
+ if (endptr[0] == '\0')
rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
- } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
+ else if (rules->resolve_names > 0 && strchr("$%", value[0]) == NULL) {
uid = add_uid(rules, value);
rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
} else if (rules->resolve_names >= 0)
rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL);
rule_tmp.rule.rule.can_set_name = true;
- continue;
- }
- if (streq(key, "GROUP")) {
+ } else if (streq(key, "GROUP")) {
gid_t gid;
char *endptr;
- if (op == OP_REMOVE) {
- log_error("invalid GROUP operation");
- goto invalid;
- }
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
gid = strtoul(value, &endptr, 10);
- if (endptr[0] == '\0') {
+ if (endptr[0] == '\0')
rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
- } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
+ else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
gid = add_gid(rules, value);
rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
} else if (rules->resolve_names >= 0)
rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL);
rule_tmp.rule.rule.can_set_name = true;
- continue;
- }
- if (streq(key, "MODE")) {
+ } else if (streq(key, "MODE")) {
mode_t mode;
char *endptr;
- if (op == OP_REMOVE) {
- log_error("invalid MODE operation");
- goto invalid;
- }
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
mode = strtol(value, &endptr, 8);
if (endptr[0] == '\0')
@@ -1480,27 +1367,23 @@ static int add_rule(struct udev_rules *rules, char *line,
else
rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL);
rule_tmp.rule.rule.can_set_name = true;
- continue;
- }
- if (streq(key, "OPTIONS")) {
+ } else if (streq(key, "OPTIONS")) {
const char *pos;
- if (op == OP_REMOVE) {
- log_error("invalid OPTIONS operation");
- goto invalid;
- }
+ if (op == OP_REMOVE)
+ LOG_AND_RETURN("invalid %s operation", key);
pos = strstr(value, "link_priority=");
if (pos != NULL) {
- int prio = atoi(&pos[strlen("link_priority=")]);
+ int prio = atoi(pos + strlen("link_priority="));
rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio);
}
pos = strstr(value, "string_escape=");
if (pos != NULL) {
- pos = &pos[strlen("string_escape=")];
+ pos += strlen("string_escape=");
if (startswith(pos, "none"))
rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL);
else if (startswith(pos, "replace"))
@@ -1527,30 +1410,19 @@ static int add_rule(struct udev_rules *rules, char *line,
pos = strstr(value, "static_node=");
if (pos != NULL) {
- rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL);
+ pos += strlen("static_node=");
+ rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL);
rule_tmp.rule.rule.has_static_node = true;
}
- continue;
- }
-
- log_error("unknown key '%s' in %s:%u", key, filename, lineno);
- goto invalid;
+ } else
+ LOG_AND_RETURN("unknown key '%s'", key);
}
- /* add rule token */
+ /* add rule token and sort tokens */
rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur;
- if (add_token(rules, &rule_tmp.rule) != 0)
- goto invalid;
-
- /* add tokens to list, sorted by type */
- if (sort_token(rules, &rule_tmp) != 0)
- goto invalid;
-
- return 0;
-invalid:
- log_error("invalid rule '%s:%u'", filename, lineno);
- return -1;
+ if (add_token(rules, &rule_tmp.rule) != 0 || sort_token(rules, &rule_tmp) != 0)
+ LOG_RULE_ERROR("failed to add rule token");
}
static int parse_file(struct udev_rules *rules, const char *filename) {
@@ -1849,18 +1721,18 @@ enum escape_type {
ESCAPE_REPLACE,
};
-int udev_rules_apply_to_event(struct udev_rules *rules,
- struct udev_event *event,
- usec_t timeout_usec,
- usec_t timeout_warn_usec,
- struct udev_list *properties_list) {
+void udev_rules_apply_to_event(struct udev_rules *rules,
+ struct udev_event *event,
+ usec_t timeout_usec,
+ usec_t timeout_warn_usec,
+ struct udev_list *properties_list) {
struct token *cur;
struct token *rule;
enum escape_type esc = ESCAPE_UNSET;
bool can_set_name;
if (rules->tokens == NULL)
- return -1;
+ return;
can_set_name = ((!streq(udev_device_get_action(event->dev), "remove")) &&
(major(udev_device_get_devnum(event->dev)) > 0 ||
@@ -2168,7 +2040,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
break;
}
case TK_M_IMPORT_CMDLINE: {
- FILE *f;
+ _cleanup_fclose_ FILE *f = NULL;
bool imported = false;
f = fopen("/proc/cmdline", "re");
@@ -2181,12 +2053,12 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
pos = strstr(cmdline, key);
if (pos != NULL) {
+ imported = true;
pos += strlen(key);
- if (pos[0] == '\0' || isspace(pos[0])) {
+ if (pos[0] == '\0' || isspace(pos[0]))
/* we import simple flags as 'FLAG=1' */
udev_device_add_property(event->dev, key, "1");
- imported = true;
- } else if (pos[0] == '=') {
+ else if (pos[0] == '=') {
const char *value;
pos++;
@@ -2195,11 +2067,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
pos++;
pos[0] = '\0';
udev_device_add_property(event->dev, key, value);
- imported = true;
}
}
}
- fclose(f);
}
if (!imported && cur->key.op != OP_NOMATCH)
goto nomatch;
@@ -2428,13 +2298,17 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
log_debug("%i character(s) replaced", count);
}
if (major(udev_device_get_devnum(event->dev)) &&
- (!streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/")))) {
- log_error("NAME=\"%s\" ignored, kernel device nodes "
- "can not be renamed; please fix it in %s:%u\n", name,
- rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
+ !streq(name_str, udev_device_get_devnode(event->dev) + strlen("/dev/"))) {
+ log_error("NAME=\"%s\" ignored, kernel device nodes cannot be renamed; please fix it in %s:%u\n",
+ name,
+ rules_str(rules, rule->rule.filename_off),
+ rule->rule.filename_line);
break;
}
- free_and_strdup(&event->name, name_str);
+ if (free_and_strdup(&event->name, name_str) < 0) {
+ log_oom();
+ return;
+ }
log_debug("NAME '%s' %s:%u",
event->name,
rules_str(rules, rule->rule.filename_off),
@@ -2491,7 +2365,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
const char *key_name = rules_str(rules, cur->key.attr_off);
char attr[UTIL_PATH_SIZE];
char value[UTIL_NAME_SIZE];
- FILE *f;
+ _cleanup_fclose_ FILE *f = NULL;
if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0)
strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL);
@@ -2502,13 +2376,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
rules_str(rules, rule->rule.filename_off),
rule->rule.filename_line);
f = fopen(attr, "we");
- if (f != NULL) {
- if (fprintf(f, "%s", value) <= 0)
- log_error_errno(errno, "error writing ATTR{%s}: %m", attr);
- fclose(f);
- } else {
+ if (f == NULL)
log_error_errno(errno, "error opening ATTR{%s} for writing: %m", attr);
- }
+ else if (fprintf(f, "%s", value) <= 0)
+ log_error_errno(errno, "error writing ATTR{%s}: %m", attr);
break;
}
case TK_A_SYSCTL: {
@@ -2546,7 +2417,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules,
cur = &rules->tokens[cur->key.rule_goto];
continue;
case TK_END:
- return 0;
+ return;
case TK_M_PARENTS_MIN:
case TK_M_PARENTS_MAX:
@@ -2574,7 +2445,7 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) {
char **t;
FILE *f = NULL;
_cleanup_free_ char *path = NULL;
- int r = 0;
+ int r;
if (rules->tokens == NULL)
return 0;
@@ -2645,8 +2516,6 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) {
if (r < 0 && errno != EEXIST)
return log_error_errno(errno, "failed to create symlink %s -> %s: %m",
tag_symlink, device_node);
- else
- r = 0;
}
}
@@ -2698,12 +2567,11 @@ finish:
fflush(f);
fchmod(fileno(f), 0644);
if (ferror(f) || rename(path, "/run/udev/static_node-tags") < 0) {
- r = -errno;
- unlink("/run/udev/static_node-tags");
- unlink(path);
+ unlink_noerrno("/run/udev/static_node-tags");
+ unlink_noerrno(path);
+ return -errno;
}
- fclose(f);
}
- return r;
+ return 0;
}
diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c
index f9cb5e63a2..c0ef073476 100644
--- a/src/udev/udevadm-monitor.c
+++ b/src/udev/udevadm-monitor.c
@@ -40,7 +40,7 @@ static void sig_handler(int signum) {
static void print_device(struct udev_device *device, const char *source, int prop) {
struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
+ assert_se(clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
printf("%-6s[%"PRI_TIME".%06ld] %-8s %s (%s)\n",
source,
ts.tv_sec, ts.tv_nsec/1000,
@@ -100,7 +100,7 @@ static int adm_monitor(struct udev *udev, int argc, char *argv[]) {
udev_list_init(udev, &subsystem_match_list, true);
udev_list_init(udev, &tag_match_list, true);
- while((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "pekus:t:h", options, NULL)) >= 0)
switch (c) {
case 'p':
case 'e':
diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c
index ff427cf292..702dbe5282 100644
--- a/src/udev/udevadm-test.c
+++ b/src/udev/udevadm-test.c
@@ -61,7 +61,7 @@ static int adm_test(struct udev *udev, int argc, char *argv[]) {
log_debug("version %s", VERSION);
- while((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "a:N:h", options, NULL)) >= 0)
switch (c) {
case 'a':
action = optarg;
diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h
index 37e4fe8369..dc712b0d93 100644
--- a/src/udev/udevadm-util.h
+++ b/src/udev/udevadm-util.h
@@ -1,3 +1,5 @@
+#pragma once
+
/*
* Copyright (C) 2014 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
*
@@ -15,8 +17,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#pragma once
-
#include "udev.h"
struct udev_device *find_device(struct udev *udev,
diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c
index 7bd2c1ea42..a6a873e5de 100644
--- a/src/udev/udevadm.c
+++ b/src/udev/udevadm.c
@@ -93,7 +93,7 @@ int main(int argc, char *argv[]) {
log_parse_environment();
log_open();
- mac_selinux_init("/dev");
+ mac_selinux_init();
while ((c = getopt_long(argc, argv, "+dhV", options, NULL)) >= 0)
switch (c) {
diff --git a/src/udev/udevd.c b/src/udev/udevd.c
index 37489c6ce7..89006e6e3a 100644
--- a/src/udev/udevd.c
+++ b/src/udev/udevd.c
@@ -400,10 +400,11 @@ static void worker_spawn(Manager *manager, struct event *event) {
goto out;
}
- /* request TERM signal if parent exits */
- prctl(PR_SET_PDEATHSIG, SIGTERM);
+ /* Request TERM signal if parent exits.
+ Ignore error, not much we can do in that case. */
+ (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
- /* reset OOM score, we only protect the main daemon */
+ /* Reset OOM score, we only protect the main daemon. */
write_string_file("/proc/self/oom_score_adj", "0", 0);
for (;;) {
@@ -1695,7 +1696,7 @@ int main(int argc, char *argv[]) {
umask(022);
- r = mac_selinux_init("/dev");
+ r = mac_selinux_init();
if (r < 0) {
log_error_errno(r, "could not initialize labelling: %m");
goto exit;