diff options
962 files changed, 30596 insertions, 20618 deletions
diff --git a/.gitignore b/.gitignore index 709c8b53d0..922ff3244f 100644 --- a/.gitignore +++ b/.gitignore @@ -20,12 +20,12 @@ /*.tar.bz2 /*.tar.gz /*.tar.xz -/Makefile -/TAGS /GPATH /GRTAGS /GSYMS /GTAGS +/Makefile +/TAGS /ata_id /bootctl /build-aux @@ -42,14 +42,12 @@ /journalctl /libsystemd-*.c /libtool +/linuxx64.efi.stub /localectl /loginctl /machinectl /mtd_probe /networkctl -/linuxx64.efi.stub -/systemd-bootx64.efi -/test-efi-disk.img /scsi_id /systemadm /systemctl @@ -61,6 +59,7 @@ /systemd-backlight /systemd-binfmt /systemd-bootchart +/systemd-bootx64.efi /systemd-bus-proxyd /systemd-cat /systemd-cgls @@ -135,11 +134,11 @@ /systemd-vconsole-setup /tags /test-acd -/test-architecture -/test-audit-type /test-af-list +/test-architecture /test-arphrd-list /test-async +/test-audit-type /test-barrier /test-bitmap /test-boot-timestamp @@ -183,19 +182,20 @@ /test-dhcp-server /test-dhcp6-client /test-dns-domain +/test-efi-disk.img /test-ellipsize /test-engine /test-env-replace /test-event /test-execute +/test-extract-word /test-fdset /test-fileio -/test-fstab-util /test-firewall-util +/test-fstab-util /test-hashmap /test-hostname /test-hostname-util -/test-icmp6-rs /test-id128 /test-inhibit /test-install @@ -229,13 +229,16 @@ /test-machine-tables /test-mmap-cache /test-namespace +/test-ndisc-rs +/test-netlink +/test-netlink-manual /test-network /test-network-tables /test-ns +/test-parse-util /test-path /test-path-lookup /test-path-util -/test-pppoe /test-prioq /test-process-util /test-pty @@ -244,8 +247,6 @@ /test-replace-var /test-resolve /test-ring -/test-netlink -/test-netlink-manual /test-sched-prio /test-set /test-sigbus @@ -254,6 +255,7 @@ /test-socket-util /test-ssd /test-strbuf +/test-string-util /test-strip-tab-ansi /test-strv /test-strxcpyx @@ -266,6 +268,7 @@ /test-unaligned /test-unit-file /test-unit-name +/test-user-util /test-utf8 /test-util /test-verbs @@ -63,3 +63,4 @@ Arnd Bergmann <arnd@arndb.de> Tom Rini <trini@kernel.crashing.org> Paul Mundt <lethal@linux-sh.org> Atul Sabharwal <atul.sabharwal@intel.com> +Daniel Machon <Danielmachon@live.dk> diff --git a/CODING_STYLE b/CODING_STYLE index d373f4dea3..0064303203 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -145,11 +145,15 @@ - Think about the types you use. If a value cannot sensibly be negative, do not use "int", but use "unsigned". -- Do not use types like "short". They *never* make sense. Use ints, - longs, long longs, all in unsigned+signed fashion, and the fixed - size types uint32_t and so on, as well as size_t, but nothing - else. Do not use kernel types like u32 and so on, leave that to the - kernel. +- Use "char" only for actual characters. Use "uint8_t" or "int8_t" + when you actually mean a byte-sized signed or unsigned + integers. When referring to a generic byte, we generally prefer the + unsigned variant "uint8_t". Do not use types based on "short". They + *never* make sense. Use ints, longs, long longs, all in + unsigned+signed fashion, and the fixed size types + uint8_t/uint16_t/uint32_t/uint64_t/int8_t/int16_t/int32_t and so on, + as well as size_t, but nothing else. Do not use kernel types like + u32 and so on, leave that to the kernel. - Public API calls (i.e. functions exported by our shared libraries) must be marked "_public_" and need to be prefixed with "sd_". No @@ -346,3 +350,29 @@ - If you want to concatenate two or more strings, consider using strjoin() rather than asprintf(), as the latter is a lot slower. This matters particularly in inner loops. + +- Please avoid using global variables as much as you can. And if you + do use them make sure they are static at least, instead of + exported. Especially in library-like code it is important to avoid + global variables. Why are global variables bad? They usually hinder + generic reusability of code (since they break in threaded programs, + and usually would require locking there), and as the code using them + has side-effects make programs intransparent. That said, there are + many cases where they explicitly make a lot of sense, and are OK to + use. For example, the log level and target in log.c is stored in a + global variable, and that's OK and probably expected by most. Also + in many cases we cache data in global variables. If you add more + caches like this, please be careful however, and think about + threading. Only use static variables if you are sure that + thread-safety doesn't matter in your case. Alternatively consider + using TLS, which is pretty easy to use with gcc's "thread_local" + concept. It's also OK to store data that is inherently global in + global variables, for example data parsed from command lines, see + below. + +- If you parse a command line, and want to store the parsed parameters + in global variables, please consider prefixing their names with + "arg_". We have been following this naming rule in most of our + tools, and we should continue to do so, as it makes it easy to + identify command line parameter variables, and makes it clear why it + is OK that they are global variables. diff --git a/Makefile-man.am b/Makefile-man.am index 1ff85d7d2c..c792c89324 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -136,7 +136,6 @@ MANPAGES += \ man/systemd.scope.5 \ man/systemd.service.5 \ man/systemd.slice.5 \ - man/systemd.snapshot.5 \ man/systemd.socket.5 \ man/systemd.special.7 \ man/systemd.swap.5 \ @@ -374,6 +373,7 @@ MANPAGES_ALIAS += \ man/systemd-hybrid-sleep.service.8 \ man/systemd-initctl.8 \ man/systemd-initctl.socket.8 \ + man/systemd-journald-audit.socket.8 \ man/systemd-journald-dev-log.socket.8 \ man/systemd-journald.8 \ man/systemd-journald.socket.8 \ @@ -663,6 +663,7 @@ man/systemd-hibernate.service.8: man/systemd-suspend.service.8 man/systemd-hybrid-sleep.service.8: man/systemd-suspend.service.8 man/systemd-initctl.8: man/systemd-initctl.service.8 man/systemd-initctl.socket.8: man/systemd-initctl.service.8 +man/systemd-journald-audit.socket.8: man/systemd-journald.service.8 man/systemd-journald-dev-log.socket.8: man/systemd-journald.service.8 man/systemd-journald.8: man/systemd-journald.service.8 man/systemd-journald.socket.8: man/systemd-journald.service.8 @@ -1378,6 +1379,9 @@ man/systemd-initctl.html: man/systemd-initctl.service.html man/systemd-initctl.socket.html: man/systemd-initctl.service.html $(html-alias) +man/systemd-journald-audit.socket.html: man/systemd-journald.service.html + $(html-alias) + man/systemd-journald-dev-log.socket.html: man/systemd-journald.service.html $(html-alias) @@ -2408,7 +2412,6 @@ EXTRA_DIST += \ man/systemd.scope.xml \ man/systemd.service.xml \ man/systemd.slice.xml \ - man/systemd.snapshot.xml \ man/systemd.socket.xml \ man/systemd.special.xml \ man/systemd.swap.xml \ diff --git a/Makefile.am b/Makefile.am index 8646e55450..9b93d0025c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -616,7 +616,8 @@ EXTRA_DIST += \ units/initrd-udevadm-cleanup-db.service.in \ units/initrd-switch-root.service.in \ units/systemd-nspawn@.service.in \ - units/systemd-update-done.service.in + units/systemd-update-done.service.in \ + units/tmp.mount.m4 if HAVE_SYSV_COMPAT nodist_systemunit_DATA += \ @@ -724,8 +725,8 @@ SOURCE_XML_FILES = ${patsubst %,$(top_srcdir)/%,$(filter-out man/systemd.directi # This target should only be run manually. It recreates Makefile-man.am # file in the source directory based on all man/*.xml files. Run it after # adding, removing, or changing the conditional in a man page. -update-man-list: $(top_srcdir)/tools/make-man-rules.py $(XML_GLOB) - $(AM_V_GEN)$(PYTHON) $^ > $(top_srcdir)/Makefile-man.tmp +update-man-list: $(top_srcdir)/tools/make-man-rules.py $(XML_GLOB) man/custom-entities.ent + $(AM_V_GEN)$(PYTHON) $< $(XML_GLOB) > $(top_srcdir)/Makefile-man.tmp $(AM_V_at)mv $(top_srcdir)/Makefile-man.tmp $(top_srcdir)/Makefile-man.am @echo "Makefile-man.am has been regenerated" @@ -761,10 +762,11 @@ noinst_LTLIBRARIES += \ libbasic_la_SOURCES = \ src/basic/missing.h \ - src/basic/capability.c \ - src/basic/capability.h \ + src/basic/capability-util.c \ + src/basic/capability-util.h \ src/basic/conf-files.c \ src/basic/conf-files.h \ + src/basic/stdio-util.h \ src/basic/hostname-util.h \ src/basic/hostname-util.c \ src/basic/unit-name.c \ @@ -780,6 +782,42 @@ libbasic_la_SOURCES = \ src/basic/refcnt.h \ src/basic/util.c \ src/basic/util.h \ + src/basic/io-util.c \ + src/basic/io-util.h \ + src/basic/string-util.c \ + src/basic/string-util.h \ + src/basic/fd-util.c \ + src/basic/fd-util.h \ + src/basic/parse-util.c \ + src/basic/parse-util.h \ + src/basic/user-util.c \ + src/basic/user-util.h \ + src/basic/rlimit-util.c \ + src/basic/rlimit-util.h \ + src/basic/dirent-util.c \ + src/basic/dirent-util.h \ + src/basic/xattr-util.c \ + src/basic/xattr-util.h \ + src/basic/chattr-util.c \ + src/basic/chattr-util.h \ + src/basic/proc-cmdline.c \ + src/basic/proc-cmdline.h \ + src/basic/fs-util.c \ + src/basic/fs-util.h \ + src/basic/syslog-util.c \ + src/basic/syslog-util.h \ + src/basic/stat-util.c \ + src/basic/stat-util.h \ + src/basic/mount-util.c \ + src/basic/mount-util.h \ + src/basic/hexdecoct.c \ + src/basic/hexdecoct.h \ + src/basic/glob-util.h \ + src/basic/glob-util.c \ + src/basic/extract-word.c \ + src/basic/extract-word.h \ + src/basic/escape.c \ + src/basic/escape.h \ src/basic/cpu-set-util.c \ src/basic/cpu-set-util.h \ src/basic/lockfile-util.c \ @@ -790,8 +828,11 @@ libbasic_la_SOURCES = \ src/basic/time-util.h \ src/basic/locale-util.c \ src/basic/locale-util.h \ + src/basic/umask-util.h \ src/basic/signal-util.c \ src/basic/signal-util.h \ + src/basic/string-table.c \ + src/basic/string-table.h \ src/basic/mempool.c \ src/basic/mempool.h \ src/basic/hashmap.c \ @@ -806,6 +847,8 @@ libbasic_la_SOURCES = \ src/basic/fdset.h \ src/basic/prioq.c \ src/basic/prioq.h \ + src/basic/web-util.c \ + src/basic/web-util.h \ src/basic/strv.c \ src/basic/strv.h \ src/basic/env-util.c \ @@ -837,6 +880,7 @@ libbasic_la_SOURCES = \ src/basic/in-addr-util.c \ src/basic/in-addr-util.h \ src/basic/ether-addr-util.h \ + src/basic/ether-addr-util.c \ src/basic/replace-var.c \ src/basic/replace-var.h \ src/basic/clock-util.c \ @@ -863,8 +907,8 @@ libbasic_la_SOURCES = \ src/basic/login-util.c \ src/basic/cap-list.c \ src/basic/cap-list.h \ - src/basic/audit.c \ - src/basic/audit.h \ + src/basic/audit-util.c \ + src/basic/audit-util.h \ src/basic/xml.c \ src/basic/xml.h \ src/basic/json.c \ @@ -898,7 +942,10 @@ libbasic_la_SOURCES = \ src/basic/rm-rf.c \ src/basic/rm-rf.h \ src/basic/copy.c \ - src/basic/copy.h + src/basic/copy.h \ + src/basic/alloc-util.h \ + src/basic/alloc-util.c \ + src/basic/formats-util.h nodist_libbasic_la_SOURCES = \ src/basic/errno-from-name.h \ @@ -919,7 +966,6 @@ libbasic_la_CFLAGS = \ libbasic_la_LIBADD = \ $(SELINUX_LIBS) \ $(CAP_LIBS) \ - -ldl \ -lrt \ -lm @@ -939,7 +985,6 @@ libshared_la_SOURCES = \ src/shared/architecture.h \ src/shared/efivars.c \ src/shared/efivars.h \ - src/shared/formats-util.h \ src/shared/fstab-util.c \ src/shared/fstab-util.h \ src/shared/sleep-config.c \ @@ -1093,8 +1138,6 @@ libcore_la_SOURCES = \ src/core/bus-policy.h \ src/core/target.c \ src/core/target.h \ - src/core/snapshot.c \ - src/core/snapshot.h \ src/core/device.c \ src/core/device.h \ src/core/mount.c \ @@ -1133,8 +1176,6 @@ libcore_la_SOURCES = \ src/core/dbus-busname.h \ src/core/dbus-target.c \ src/core/dbus-target.h \ - src/core/dbus-snapshot.c \ - src/core/dbus-snapshot.h \ src/core/dbus-device.c \ src/core/dbus-device.h \ src/core/dbus-mount.c \ @@ -1229,7 +1270,7 @@ BUILT_SOURCES += \ $(gperf_gperf_m4_sources:-gperf.gperf.m4=-gperf-nulstr.c) \ $(gperf_gperf_sources:-gperf.gperf=-gperf.c) \ $(gperf_txt_sources:-list.txt=-from-name.h) \ - $(gperf_txt_sources:-list.txt=-to-name.h) + $(filter-out %keyboard-keys-to-name.h,$(gperf_txt_sources:-list.txt=-to-name.h)) CLEANFILES += \ $(gperf_txt_sources:-list.txt=-from-name.gperf) @@ -1402,6 +1443,10 @@ tests += \ test-utf8 \ test-ellipsize \ test-util \ + test-string-util \ + test-extract-word \ + test-parse-util \ + test-user-util \ test-hostname-util \ test-process-util \ test-terminal-util \ @@ -1448,7 +1493,8 @@ tests += \ test-verbs \ test-af-list \ test-arphrd-list \ - test-dns-domain + test-dns-domain \ + test-install-root EXTRA_DIST += \ test/a.service \ @@ -1457,7 +1503,7 @@ EXTRA_DIST += \ test/c.service \ test/daughter.service \ test/d.service \ - test/end.service.in \ + test/end.service \ test/e.service \ test/f.service \ test/grandchild.service \ @@ -1467,7 +1513,6 @@ EXTRA_DIST += \ test/h.service \ test/parent-deep.slice \ test/parent.slice \ - test/paths.target \ test/sched_idle_bad.service \ test/sched_idle_ok.service \ test/sched_rr_bad.service \ @@ -1481,43 +1526,62 @@ EXTRA_DIST += \ test/testsuite.target \ test/timers.target \ test/unstoppable.service \ - test/path-changed.service \ - test/path-directorynotempty.service \ - test/path-existsglob.service \ - test/path-exists.service \ - test/path-makedirectory.service \ - test/path-modified.service \ - test/path-mycustomunit.service \ - test/path-service.service \ - test/path-changed.path \ - test/path-directorynotempty.path \ - test/path-existsglob.path \ - test/path-exists.path \ - test/path-makedirectory.path \ - test/path-modified.path \ - test/path-unit.path \ - test/exec-environment-empty.service \ - test/exec-environment-multiple.service \ - test/exec-environment.service \ - test/exec-group.service \ - test/exec-ignoresigpipe-no.service \ - test/exec-ignoresigpipe-yes.service \ - test/exec-personality-x86-64.service \ - test/exec-personality-x86.service \ - test/exec-personality-s390.service \ - test/exec-privatedevices-no.service \ - test/exec-privatedevices-yes.service \ - test/exec-privatetmp-no.service \ - test/exec-privatetmp-yes.service \ - test/exec-systemcallerrornumber.service \ - test/exec-systemcallfilter-failing2.service \ - test/exec-systemcallfilter-failing.service \ - test/exec-systemcallfilter-not-failing2.service \ - test/exec-systemcallfilter-not-failing.service \ - test/exec-user.service \ - test/exec-workingdirectory.service \ - test/exec-umask-0177.service \ - test/exec-umask-default.service \ + test/test-path/paths.target \ + test/test-path/basic.target \ + test/test-path/sysinit.target \ + test/test-path/path-changed.service \ + test/test-path/path-directorynotempty.service \ + test/test-path/path-existsglob.service \ + test/test-path/path-exists.service \ + test/test-path/path-makedirectory.service \ + test/test-path/path-modified.service \ + test/test-path/path-mycustomunit.service \ + test/test-path/path-service.service \ + test/test-path/path-changed.path \ + test/test-path/path-directorynotempty.path \ + test/test-path/path-existsglob.path \ + test/test-path/path-exists.path \ + test/test-path/path-makedirectory.path \ + test/test-path/path-modified.path \ + test/test-path/path-unit.path \ + test/test-execute/exec-environment-empty.service \ + test/test-execute/exec-environment-multiple.service \ + test/test-execute/exec-environment.service \ + test/test-execute/exec-passenvironment-absent.service \ + test/test-execute/exec-passenvironment-empty.service \ + test/test-execute/exec-passenvironment-repeated.service \ + test/test-execute/exec-passenvironment.service \ + test/test-execute/exec-group.service \ + test/test-execute/exec-ignoresigpipe-no.service \ + test/test-execute/exec-ignoresigpipe-yes.service \ + test/test-execute/exec-personality-x86-64.service \ + test/test-execute/exec-personality-x86.service \ + test/test-execute/exec-personality-s390.service \ + test/test-execute/exec-privatedevices-no.service \ + test/test-execute/exec-privatedevices-yes.service \ + test/test-execute/exec-privatetmp-no.service \ + test/test-execute/exec-privatetmp-yes.service \ + test/test-execute/exec-systemcallerrornumber.service \ + test/test-execute/exec-systemcallfilter-failing2.service \ + test/test-execute/exec-systemcallfilter-failing.service \ + test/test-execute/exec-systemcallfilter-not-failing2.service \ + test/test-execute/exec-systemcallfilter-not-failing.service \ + test/test-execute/exec-user.service \ + test/test-execute/exec-workingdirectory.service \ + test/test-execute/exec-umask-0177.service \ + test/test-execute/exec-umask-default.service \ + test/test-execute/exec-privatenetwork-yes.service \ + test/test-execute/exec-environmentfile.service \ + test/test-execute/exec-oomscoreadjust-positive.service \ + test/test-execute/exec-oomscoreadjust-negative.service \ + test/test-execute/exec-ioschedulingclass-best-effort.service \ + test/test-execute/exec-ioschedulingclass-idle.service \ + test/test-execute/exec-ioschedulingclass-none.service \ + test/test-execute/exec-ioschedulingclass-realtime.service \ + test/test-execute/exec-capabilityboundingset-invert.service \ + test/test-execute/exec-capabilityboundingset-merge.service \ + test/test-execute/exec-capabilityboundingset-reset.service \ + test/test-execute/exec-capabilityboundingset-simple.service \ test/bus-policy/hello.conf \ test/bus-policy/methods.conf \ test/bus-policy/ownerships.conf \ @@ -1686,6 +1750,30 @@ test_util_SOURCES = \ test_util_LDADD = \ libshared.la +test_string_util_SOURCES = \ + src/test/test-string-util.c + +test_string_util_LDADD = \ + libshared.la + +test_extract_word_SOURCES = \ + src/test/test-extract-word.c + +test_extract_word_LDADD = \ + libshared.la + +test_parse_util_SOURCES = \ + src/test/test-parse-util.c + +test_parse_util_LDADD = \ + libshared.la + +test_user_util_SOURCES = \ + src/test/test-user-util.c + +test_user_util_LDADD = \ + libshared.la + test_hostname_util_SOURCES = \ src/test/test-hostname-util.c @@ -1749,6 +1837,12 @@ test_verbs_SOURCES = \ test_verbs_LDADD = \ libshared.la +test_install_root_SOURCES = \ + src/test/test-install-root.c + +test_install_root_LDADD = \ + libshared.la + test_namespace_LDADD = \ libcore.la @@ -3215,10 +3309,9 @@ libsystemd_network_la_SOURCES = \ src/systemd/sd-dhcp-lease.h \ src/systemd/sd-ipv4ll.h \ src/systemd/sd-ipv4acd.h \ - src/systemd/sd-icmp6-nd.h \ + src/systemd/sd-ndisc.h \ src/systemd/sd-dhcp6-client.h \ src/systemd/sd-dhcp6-lease.h \ - src/systemd/sd-pppoe.h \ src/systemd/sd-lldp.h \ src/libsystemd-network/sd-dhcp-client.c \ src/libsystemd-network/sd-dhcp-server.c \ @@ -3234,10 +3327,11 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/sd-ipv4acd.c \ src/libsystemd-network/arp-util.h \ src/libsystemd-network/arp-util.c \ - src/libsystemd-network/sd-pppoe.c \ src/libsystemd-network/network-internal.c \ src/libsystemd-network/network-internal.h \ - src/libsystemd-network/sd-icmp6-nd.c \ + src/libsystemd-network/sd-ndisc.c \ + src/libsystemd-network/icmp6-util.h \ + src/libsystemd-network/icmp6-util.c \ src/libsystemd-network/sd-dhcp6-client.c \ src/libsystemd-network/dhcp6-internal.h \ src/libsystemd-network/dhcp6-protocol.h \ @@ -3313,23 +3407,15 @@ test_acd_LDADD = \ libsystemd-network.la \ libshared.la -test_pppoe_SOURCES = \ - src/systemd/sd-pppoe.h \ - src/libsystemd-network/test-pppoe.c - -test_pppoe_LDADD = \ - libsystemd-network.la \ - libshared.la - -test_icmp6_rs_SOURCES = \ +test_ndisc_rs_SOURCES = \ src/systemd/sd-dhcp6-client.h \ - src/systemd/sd-icmp6-nd.h \ - src/libsystemd-network/dhcp6-internal.h \ - src/libsystemd-network/test-icmp6-rs.c \ + src/systemd/sd-ndisc.h \ + src/libsystemd-network/icmp6-util.h \ + src/libsystemd-network/test-ndisc-rs.c \ src/libsystemd-network/dhcp-identifier.h \ src/libsystemd-network/dhcp-identifier.c -test_icmp6_rs_LDADD = \ +test_ndisc_rs_LDADD = \ libsystemd-network.la \ libudev.la \ libshared.la @@ -3361,13 +3447,10 @@ tests += \ test-dhcp-client \ test-dhcp-server \ test-ipv4ll \ - test-icmp6-rs \ + test-ndisc-rs \ test-dhcp6-client \ test-lldp -manual_tests += \ - test-pppoe - # ------------------------------------------------------------------------------ include_HEADERS += \ src/libudev/libudev.h @@ -3483,7 +3566,7 @@ noinst_LTLIBRARIES += \ src/udev/keyboard-keys-list.txt: $(AM_V_at)$(MKDIR_P) $(dir $@) - $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/input.h - < /dev/null | $(AWK) '/^#define[ \t]+KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@ + $(AM_V_GEN)$(CPP) $(CFLAGS) $(AM_CPPFLAGS) $(CPPFLAGS) -dM -include linux/input.h - < /dev/null | $(AWK) '/^#define[ \t]+KEY_[^ ]+[ \t]+[0-9K]/ { if ($$2 != "KEY_MAX") { print $$2 } }' > $@ src/udev/keyboard-keys-from-name.gperf: src/udev/keyboard-keys-list.txt $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print tolower(substr($$1 ,5)) ", " $$1 }' < $< > $@ @@ -3491,9 +3574,6 @@ src/udev/keyboard-keys-from-name.gperf: src/udev/keyboard-keys-list.txt src/udev/keyboard-keys-from-name.h: src/udev/keyboard-keys-from-name.gperf $(AM_V_GPERF)$(GPERF) -L ANSI-C -t -N keyboard_lookup_key -H hash_key_name -p -C < $< > $@ -src/udev/keyboard-keys-to-name.h: src/udev/keyboard-keys-list.txt - $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@ - gperf_txt_sources += \ src/udev/keyboard-keys-list.txt @@ -3520,7 +3600,6 @@ libudev_core_la_SOURCES = \ nodist_libudev_core_la_SOURCES = \ src/udev/keyboard-keys-from-name.h \ - src/udev/keyboard-keys-to-name.h \ src/udev/net/link-config-gperf.c gperf_gperf_sources += \ @@ -3831,6 +3910,7 @@ endif if HAVE_GNUTLS systemd_journal_remote_LDADD += \ $(GNUTLS_LIBS) +endif # systemd-journal-remote make sense mostly with full crypto stack dist_systemunit_DATA += \ @@ -3845,7 +3925,6 @@ journal-remote-install-hook: journal-install-hook -chmod 755 $(DESTDIR)/var/log/journal/remote INSTALL_EXEC_HOOKS += journal-remote-install-hook -endif nodist_pkgsysconf_DATA += \ src/journal-remote/journal-remote.conf @@ -4184,6 +4263,7 @@ dist_catalog_DATA = \ catalog/systemd.pl.catalog \ catalog/systemd.pt_BR.catalog \ catalog/systemd.ru.catalog \ + catalog/systemd.zh_CN.catalog \ catalog/systemd.zh_TW.catalog \ catalog/systemd.catalog @@ -5148,7 +5228,8 @@ libnss_resolve_la_LDFLAGS = \ -Wl,--version-script=$(top_srcdir)/src/nss-resolve/nss-resolve.sym libnss_resolve_la_LIBADD = \ - libshared.la + libshared.la \ + -ldl lib_LTLIBRARIES += \ libnss_resolve.la @@ -5234,6 +5315,7 @@ libnetworkd_core_la_SOURCES = \ src/network/networkd-ipv4ll.c \ src/network/networkd-dhcp4.c \ src/network/networkd-dhcp6.c \ + src/network/networkd-ndisc.c \ src/network/networkd-network.h \ src/network/networkd-network.c \ src/network/networkd-network-bus.c \ @@ -1,5 +1,161 @@ systemd System and Service Manager +CHANGES WITH 228: + + * A number of properties previously only settable in unit + files are now also available as properties to set when + creating transient units programmatically via the bus, as it + is exposed with systemd-run's --property= + setting. Specifically, these are: SyslogIdentifier=, + SyslogLevelPrefix=, TimerSlackNSec=, OOMScoreAdjust=, + EnvironmentFile=, ReadWriteDirectories=, + ReadOnlyDirectories=, InaccessibleDirectories=, + ProtectSystem=, ProtectHome=, RuntimeDirectory=. + + * When creating transient services via the bus API it is now + possible to pass in a set of file descriptors to use as + STDIN/STDOUT/STDERR for the invoked process. + + * Wherever systemd expects a calendar timestamp specification + (like in journalctl's --since= and --until= switches) UTC + timestamps are now supported. Timestamps suffixed with "UTC" + are now considered to be in Universal Time Coordinated + instead of the local timezone. Also, timestamps may now + optionally be specified with a sub-second accuracy. Both of + these additions also apply to recurring calendar event + specification, such as OnCalendar= in timer units. + + * journalctl gained a new "--sync" switch that asks the + journal daemon to write all so far unwritten log messages to + disk and sync the files, before returning. + + * systemd-tmpfiles learned two new line types "q" and "Q" that + operate like "v", but also set up a basic btrfs quota + hierarchy when used on a btrfs file system with quota + enabled. + + * systemd-detect-virt gained a new --chroot switch to detect + whether execution takes place in a chroot() environment. + + * CPUAffinity= now takes CPU index ranges in addition to + individual indexes. + + * The various memory-related resource limit settings (such as + LimitAS=) now understand the usual K, M, G, ... suffixes to + the base of 1024 (IEC). Similar, the time-related resource + limit settings understand the usual min, h, day, ... + suffixes now. + + * systemd-nspawn gained the new --network-veth-extra= switch + to define additional and arbitrarily-named virtual Ethernet + links between the host and the container. + + * A new service execution setting PassEnvironment= has been + added that allows importing select environment variables + from PID1's environment block into the environment block of + the service. + + * systemd will now bump the net.unix.max_dgram_qlen to 512 by + default now (the kernel default is 16). This is beneficial + for avoiding blocking on AF_UNIX/SOCK_DGRAM sockets since it + allows substantially larger numbers of queued + datagrams. This should increase the capability of systemd to + parallelize boot-up, as logging and sd_notify() are unlikely + to stall execution anymore. If you need to change the value + from the new defaults, use the usual sysctl.d/ snippets. + + * The compression framing format used by the journal or + coredump processing has changed to be in line with what the + official LZ4 tools generate. LZ4 compression support in + systemd was considered unsupported previously, as the format + was not compatible with the normal tools. With this release + this has changed now, and it is hence safe for downstream + distributions to turn it on. While not compressing as well + as the XZ,LZ4 is substantially faster, which makes + it a good default choice for the compression logic in the + journal and in coredump handling. + + * Any reference to /etc/mtab has been dropped from + systemd. The file has been obsolete since a while, but + systemd refused to work on systems where it was incorrectly + set up (it should be a symlink or non-existant). Please make + sure to update to util-linux 2.27.1 or newer in conjunction + with this systemd release, which also drops any reference to + /etc/mtab. If you maintain a distribution make sure that no + software you package still references it, as this is a + likely source of bugs. There's also a glibc bug pending, + asking for removal of any reference to this obsolete file: + + https://sourceware.org/bugzilla/show_bug.cgi?id=19108 + + * Support for the ".snapshot" unit type has been removed. This + feature turned out to be little useful and little used, and + has now been removed from the core and from systemctl. + + * The dependency types RequiresOverridable= and + RequisiteOverridable= have been removed from systemd. They + have been used only very sparingly to our knowledge and + other options that provide a similar effect (such as + systemctl --mode=ignore-dependencies) are much more useful + and commonly used. Moreover, they were only half-way + implemented as the option to control behaviour regarding + these dependencies was never added to systemctl. By removing + these dependency types the execution engine becomes a bit + simpler. Unit files that use these dependencies should be + changed to use the non-Overridable dependency types + instead. In fact, when parsing unit files with these + options, that's what systemd will automatically convert them + too, but it will also warn, asking users to fix the unit + files accordingly. Removal of these dependency types should + only affect a negligible number of unit files in the wild. + + * Behaviour of networkd's IPForward= option changed + (again). It will no longer maintain a per-interface setting, + but propagate one way from interfaces where this is enabled + to the global kernel setting. The global setting will be + enabled when requested by a network that is set up, but + never be disabled again. This change was made to make sure + IPv4 and IPv6 behaviour regarding packet forwarding is + similar (as the Linux IPv6 stack does not support + per-interface control of this setting) and to minimize + surprises. + + * In unit files the behaviour of %u, %U, %h, %s has + changed. These specifiers will now unconditionally resolve + to the various user database fields of the user that the + systemd instance is running as, instead of the user + configured in the specific unit via User=. Note that this + effectively doesn't change much, as resolving of these + specifiers was already turned off in the --system instance + of systemd, as we cannot do NSS lookups from PID 1. In the + --user instance of systemd these specifiers where correctly + resolved, but hardly made any sense, since the user instance + lacks privileges to do user switches anyway, and User= is + hence useless. Morever, even in the --user instance of + systemd behaviour was awkward as it would only take settings + from User= assignment placed before the specifier into + account. In order to unify and simplify the logic around + this the specifiers will now always resolve to the + credentials of the user invoking the manager (which in case + of PID 1 is the root user). + + Contributions from: Andrew Jones, Beniamino Galvani, Boyuan + Yang, Daniel Machon, Daniel Mack, David Herrmann, David + Reynolds, David Strauss, Dongsu Park, Evgeny Vereshchagin, + Filipe Brandenburger, Franck Bui, Hristo Venev, Iago López + Galeiras, Jan Engelhardt, Jan Janssen, Jan Synacek, Jesus + Ornelas Aguayo, Karel Zak, kayrus, Kay Sievers, Lennart + Poettering, Mantas Mikulėnas, Marcel Holtmann, Marcin Bachry, + Marcos Alano, Marcos Mello, Mark Theunissen, Martin Pitt, + Michael Marineau, Michael Olbrich, Michal Schmidt, Michal + Sekletar, Mirco Tischler, Nick Owens, Nicolas Cornu, Patrik + Flykt, Peter Hutterer, reverendhomer, Ronny Chevalier, + Sangjung Woo, Seong-ho Cho, Shawn Landden, Susant Sahani, + Thomas Haller, Thomas Hindoe Paaboel Andersen, Tom Gundersen, + Torstein Husebø, Vito Caputo, Zbigniew Jędrzejewski-Szmek + + -- Berlin, 2015-11-XX + CHANGES WITH 227: * systemd now depends on util-linux v2.27. More specifically, @@ -117,7 +273,7 @@ CHANGES WITH 227: * File descriptors passed during socket activation may now be named. A new API sd_listen_fds_with_names() is added to - access the names. The default names may be overriden, + access the names. The default names may be overridden, either in the .socket file using the FileDescriptorName= parameter, or by passing FDNAME= when storing the file descriptors using sd_notify(). @@ -1156,7 +1312,7 @@ CHANGES WITH 218: another unit listed in its Also= setting might be. * Similar to the various existing ConditionXYZ= settings for - units there are now matching AssertXYZ= settings. While + units, there are now matching AssertXYZ= settings. While failing conditions cause a unit to be skipped, but its job to succeed, failing assertions declared like this will cause a unit start operation and its job to fail. @@ -1164,7 +1320,7 @@ CHANGES WITH 218: * hostnamed now knows a new chassis type "embedded". * systemctl gained a new "edit" command. When used on a unit - file this allows extending unit files with .d/ drop-in + file, this allows extending unit files with .d/ drop-in configuration snippets or editing the full file (after copying it from /usr/lib to /etc). This will invoke the user's editor (as configured with $EDITOR), and reload the @@ -1188,7 +1344,7 @@ CHANGES WITH 218: inhibitors. * Scope and service units gained a new "Delegate" boolean - property, which when set allows processes running inside the + property, which, when set, allows processes running inside the unit to further partition resources. This is primarily useful for systemd user instances as well as container managers. @@ -1198,7 +1354,7 @@ CHANGES WITH 218: audit fields are split up and fully indexed. This means that journalctl in many ways is now a (nicer!) alternative to ausearch, the traditional audit client. Note that this - implements only a minimal audit client, if you want the + implements only a minimal audit client. If you want the special audit modes like reboot-on-log-overflow, please use the traditional auditd instead, which can be used in parallel to journald. @@ -1209,7 +1365,7 @@ CHANGES WITH 218: * journalctl gained two new commands --vacuum-size= and --vacuum-time= to delete old journal files until the - remaining ones take up no more the specified size on disk, + remaining ones take up no more than the specified size on disk, or are not older than the specified time. * A new, native PPPoE library has been added to sd-network, @@ -1262,9 +1418,9 @@ CHANGES WITH 218: will spew out warnings if the compilation fails. This requires libxkbcommon to be installed. - * When a coredump is collected a larger number of metadata + * When a coredump is collected, a larger number of metadata fields is now collected and included in the journal records - created for it. More specifically control group membership, + created for it. More specifically, control group membership, environment variables, memory maps, working directory, chroot directory, /proc/$PID/status, and a list of open file descriptors is now stored in the log entry. @@ -1303,7 +1459,7 @@ CHANGES WITH 218: a fixed machine ID for subsequent boots. * networkd's .netdev files now provide a large set of - configuration parameters for VXLAN devices. Similar, the + configuration parameters for VXLAN devices. Similarly, the bridge port cost parameter is now configurable in .network files. There's also new support for configuring IP source routing. networkd .link files gained support for a new @@ -1636,7 +1792,7 @@ CHANGES WITH 216: * .socket units gained a new DeferAcceptSec= setting that controls the kernels' TCP_DEFER_ACCEPT sockopt for - TCP. Similar, support for controlling TCP keep-alive + TCP. Similarly, support for controlling TCP keep-alive settings has been added (KeepAliveTimeSec=, KeepAliveIntervalSec=, KeepAliveProbes=). Also, support for turning off Nagle's algorithm on TCP has been added @@ -1852,7 +2008,7 @@ CHANGES WITH 215: * tmpfiles learnt a new "L+" directive which creates a symlink but (unlike "L") deletes a pre-existing file first, should it already exist and not already be the correct - symlink. Similar, "b+", "c+" and "p+" directives have been + symlink. Similarly, "b+", "c+" and "p+" directives have been added as well, which create block and character devices, as well as fifos in the filesystem, possibly removing any pre-existing files of different types. @@ -1934,8 +2090,8 @@ CHANGES WITH 215: open_by_handle_at() is now prohibited for containers, closing a hole similar to a recently discussed vulnerability in docker regarding access to files on file hierarchies the - container should normally not have access to. Note that for - nspawn we generally make no security claims anyway (and + container should normally not have access to. Note that, for + nspawn, we generally make no security claims anyway (and this is explicitly documented in the man page), so this is just a fix for one of the most obvious problems. @@ -2035,14 +2191,14 @@ CHANGES WITH 214: CAP_NET_BROADCAST, CAP_NET_RAW capabilities though, but loses the ability to write to files owned by root this way. - * Similar, systemd-resolved now runs under its own + * Similarly, systemd-resolved now runs under its own "systemd-resolve" user with no capabilities remaining. - * Similar, systemd-bus-proxyd now runs under its own + * Similarly, systemd-bus-proxyd now runs under its own "systemd-bus-proxy" user with only CAP_IPC_OWNER remaining. * systemd-networkd gained support for setting up "veth" - virtual ethernet devices for container connectivity, as well + virtual Ethernet devices for container connectivity, as well as GRE and VTI tunnels. * systemd-networkd will no longer automatically attempt to @@ -2744,7 +2900,7 @@ CHANGES WITH 209: * The configuration of network interface naming rules for "permanent interface names" has changed: a new NamePolicy= setting in the [Link] section of .link files determines the - priority of possible naming schemes (onboard, slot, mac, + priority of possible naming schemes (onboard, slot, MAC, path). The default value of this setting is determined by /usr/lib/net/links/99-default.link. Old 80-net-name-slot.rules udev configuration file has been @@ -4274,8 +4430,8 @@ CHANGES WITH 197: devices as seat masters, i.e. as devices that are required to be existing before a seat is considered preset. Instead, it will now look for all devices that are tagged as - "seat-master" in udev. By default framebuffer devices will - be marked as such, but depending on local systems other + "seat-master" in udev. By default, framebuffer devices will + be marked as such, but depending on local systems, other devices might be marked as well. This may be used to integrate graphics cards using closed source drivers (such as NVidia ones) more nicely into logind. Note however, that @@ -5315,7 +5471,7 @@ CHANGES WITH 44: * Reorder configuration file lookup order. /etc now always overrides /run in order to allow the administrator to always - and unconditionally override vendor supplied or + and unconditionally override vendor-supplied or automatically generated data. * The various user visible bits of the journal now have man @@ -122,7 +122,7 @@ REQUIREMENTS: glibc >= 2.16 libcap - libmount >= 2.27 (from util-linux) + libmount >= 2.27.1 (from util-linux) libseccomp >= 1.0.0 (optional) libblkid >= 2.24 (from util-linux) (optional) libkmod >= 15 (optional) @@ -144,7 +144,7 @@ REQUIREMENTS: During runtime, you need the following additional dependencies: - util-linux >= v2.27 required + util-linux >= v2.27.1 required dbus >= 1.4.0 (strictly speaking optional, but recommended) dracut (optional) PolicyKit (optional) @@ -21,12 +21,32 @@ External: * wiki: update journal format documentation for lz4 additions -* When lz4 gets an API for lz4 command output, make use of it to - compress coredumps in a way compatible with /usr/bin/lz4. +Janitorial Clean-ups: + +* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead + +* replace manual readdir() loops with FOREACH_DIRENT or FOREACH_DIRENT_ALL + +* Get rid of the last strerror() invocations in favour of %m and strerror_r() + +* Rearrange tests so that the various test-xyz.c match a specific src/basic/xyz.c again Features: -* when creating transient services, support passing in a tty fd to use for stdin/stdout +* PID1: find a way how we can reload unit file configuration for + specific units only, without reloading the whole of systemd + +* add an explicit parser for LimitNICE= and LimitRTPRIO= that verifies + the specified range and generates sane error messages for incorrect + specifications. Also, for LimitNICE= maybe introduce a syntax such + as "+5" or "-7" in order to make the limits more readable as they + are otherwise shifted by 20. + +* do something about "/control" subcgroups in the unified cgroup hierarchy + +* when we detect that there are waiting jobs but no running jobs, do something + +* push CPUAffinity= also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy) * add a concept of RemainAfterExit= to scope units @@ -53,18 +73,11 @@ Features: prefixed with /sys generally special. http://lists.freedesktop.org/archives/systemd-devel/2015-June/032962.html -* Add PassEnvironment= setting to service units, to import select env vars from PID 1 into the service env block - * nspawn: fix logic always print a final newline on output. https://github.com/systemd/systemd/pull/272#issuecomment-113153176 -* make nspawn's --network-veth switch more powerful: - http://lists.freedesktop.org/archives/systemd-devel/2015-June/033121.html - * man: document that unless you use StandardError=null the shell >/dev/stderr won't work in shell scripts in services -* man: clarify that "machinectl show" shows different information than "machinectl status" (no cgroup tree, no IP addresses, ...) - * "systemctl daemon-reload" should result in /etc/systemd/system.conf being reloaded by systemd * install: include generator dirs in unit file search paths @@ -134,9 +147,6 @@ Features: * .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC -* create a btrfs qgroup for /var/lib/machines, and add all container - subvolumes we create to it. - * When logging about multiple units (stopping BoundTo units, conflicts, etc.), log both units as UNIT=, so that journalctl -u triggers on both. @@ -176,14 +186,12 @@ Features: * networkd/udev: implement SR_IOV configuration in .link files: http://lists.freedesktop.org/archives/systemd-devel/2015-January/027451.html -* When RLIMIT_NPROC is set from a unit file it currently always is set - for root, not for the user set in User=, which makes it - useless. After fixing this, set RLIMIT_NPROC for - systemd-journal-xyz, and all other of our services that run under - their own user ids, and use User= (but only in a world where userns - is ubiquitous since otherwise we cannot invoke those daemons on the - host AND in a container anymore). Also, if LimitNPROC= is used - without User= we should warn and refuse operation. +* Set RLIMIT_NPROC for systemd-journal-xyz, and all other of our + services that run under their own user ids, and use User= (but only + in a world where userns is ubiquitous since otherwise we cannot + invoke those daemons on the host AND in a container anymore). Also, + if LimitNPROC= is used without User= we should warn and refuse + operation. * logind: maybe allow configuration of the StopTimeout for session scopes @@ -222,8 +230,6 @@ Features: * Find a solution for SMACK capabilities stuff: http://lists.freedesktop.org/archives/systemd-devel/2014-December/026188.html -* port libmount hookup to use API's own inotify interface, as soon as that is table in libmount - * "systemctl preset-all" should probably order the unit files it operates on lexicographically before starting to work, in order to ensure deterministic behaviour if two unit files conflict (like DMs @@ -265,8 +271,6 @@ Features: * maybe add support for specifier expansion in user.conf, specifically DefaultEnvironment= -* code cleanup: retire FOREACH_WORD_QUOTED, port to extract_first_word() loops instead - * introduce systemd-timesync-wait.service or so to sync on an NTP fix? * systemd --user should issue sd_notify() upon reaching basic.target, not on becoming idle @@ -554,9 +558,6 @@ Features: * maybe do not install getty@tty1.service symlink in /etc but in /usr? -* fstab: add new mount option x-systemd-after=/foobar/waldo to allow manual dependencies to other mount points - https://bugzilla.redhat.com/show_bug.cgi?id=812826 - * print a nicer explanation if people use variable/specifier expansion in ExecStart= for the first word * mount: turn dependency information from /proc/self/mountinfo into dependency information between systemd units. @@ -599,7 +600,6 @@ Features: - add API to close/reopen/get fd for journal client fd in libsystemd-journal. - fallback to /dev/log based logging in libsystemd-journal, if we cannot log natively? - declare the local journal protocol stable in the wiki interface chart - - journal: reuse XZ context - sd-journal: speed up sd_journal_get_data() with transparent hash table in bg - journald: when dropping msgs due to ratelimit make sure to write "dropped %u messages" not only when we are about to print the next @@ -653,7 +653,6 @@ Features: - document systemd-journal-flush.service properly - documentation: recommend to connect the timer units of a service to the service via Also= in [Install] - man: document the very specific env the shutdown drop-in tools live in - - man: extend runlevel(8) to mention that runlevels suck, and are dead. Maybe add runlevel(7) with a note about that too - man: add more examples to man pages - man: maybe sort directives in man pages, and take sections from --help and apply them to man too @@ -668,8 +667,6 @@ Features: - add new command to systemctl: "systemctl system-reexec" which reexecs as many daemons as virtually possible - systemctl enable: fail if target to alias into does not exist? maybe show how many units are enabled afterwards? - systemctl: "Journal has been rotated since unit was started." message is misleading - - support "systemctl stop foobar@.service" to stop all units matching a certain template - - Something is wrong with symlink handling of "autovt@.service" in "systemctl list-unit-files" - better error message if you run systemctl without systemd running - systemctl status output should should include list of triggering units and their status @@ -684,7 +681,6 @@ Features: o DST changes - Support 2012-02~4 as syntax for specifying the fourth to last day of the month. - calendarspec: support value ranges with ".." notation. Example: 2013-4..8-1 - - when parsing calendar timestamps support the UTC timezone (even if we will not support arbitrary timezone specs, support UTC itself certainly makes sense), also support syntaxes such as +0200 - Modulate timer frequency based on battery state * add libsystemd-password or so to query passwords during boot using the password agent logic @@ -744,8 +740,6 @@ Features: * introduce Type=pid-file -* change Requires=basic.target to RequisiteOverride=basic.target - * when breaking cycles drop sysv services first, then services from /run, then from /etc, then from /usr * ExecOnFailure=/usr/bin/foo @@ -764,8 +758,6 @@ Features: * add option to sockets to avoid activation. Instead just drop packets/connections, see http://cyberelk.net/tim/2012/02/15/portreserve-systemd-solution/ -* default unix qlen is too small (10). bump sysctl? add sockopt? - * save coredump in Windows/Mozilla minidump format * support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting) @@ -874,7 +866,7 @@ Features: - add Scope= parsing option for [Network] - properly handle routerless dhcp leases - add more attribute support for SIT tunnel - - work with non-ethernet devices + - work with non-Ethernet devices - add support for more bond options * networkd-wait-online: @@ -913,12 +905,8 @@ External: * drop accountsservice's StandardOutput=syslog and Type=dbus fields -* dbus upstream still refers to dbus.target and should not - * dbus: in fedora, make /var/lib/dbus/machine-id a symlink to /etc/machine-id -* add "# export SYSTEMD_PAGER=" to bash login - * /usr/bin/service should actually show the new command line * fedora: suggest auto-restart on failure, but not on success and not on coredump. also, ask people to think about changing the start limit logic. Also point people to RestartPreventExitStatus=, SuccessExitStatus= @@ -951,7 +939,3 @@ Regularly: * use secure_getenv() instead of getenv() where appropriate * link up selected blog stories from man pages and unit files Documentation= fields - -Scheduled for removal or fixing: - -* xxxOverridable dependencies (probably: fix) diff --git a/systemd-master/catalog/systemd.da.catalog b/catalog/systemd.da.catalog index dc3f8b552e..bd4d742d8a 100644 --- a/systemd-master/catalog/systemd.da.catalog +++ b/catalog/systemd.da.catalog @@ -1,261 +1,261 @@ -# This file is part of systemd.
-#
-# Copyright 2012 Lennart Poettering
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
-
-# Message catalog for systemd's own messages
-# Danish translation
-
-# The catalog format is documented on
-# http://www.freedesktop.org/wiki/Software/systemd/catalog
-
-# For an explanation why we do all this, see https://xkcd.com/1024/
-
--- f77379a8490b408bbe5f6940505a777b
-Subject: Journalen er blevet startet
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-System-journal processen har startet op, åbnet journal filerne for
-tilskrivning og er nu klar til at modtage anmodninger.
-
--- d93fb3c9c24d451a97cea615ce59c00b
-Subject: Journalen er blevet stoppet
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-System-journal processen er stoppet og har lukket alle aktive journal
-filer.
-
--- a596d6fe7bfa4994828e72309e95d61e
-Subject: Beskeder fra en service er blevet undertrykt
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: man:journald.conf(5)
-
-En service har logget for mange beskeder inden for en given tidsperiode.
-Beskeder fra omtalte service er blevet smidt væk.
-
-Kun beskeder fra omtalte service er smidt væk. Beskeder fra andre
-services er ikke påvirket.
-
-Grænsen for hvornår beskeder bliver smidt væk kan konfigureres
-med RateLimitInterval= og RateLimitBurst= i
-/etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom.
-
--- e9bf28e6e834481bb6f48f548ad13606
-Subject: Journal beskeder er gået tabt
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Kernel beskeder er gået tabt da journal systemet ikke har været i stand
-til at håndtere dem hurtigt nok.
-
--- fc2e22bc6ee647b6b90729ab34a250b1
-Subject: Fejl-fil genereret for process @COREDUMP_PID@ (@COREDUMP_COMM@)
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: man:core(5)
-
-Process @COREDUMP_PID@ (@COREDUMP_COMM@) har lukket ned og genereret en
-fejl-fil.
-
-Dette indikerer som regel en programmeringsfejl i det nedlukkede program
-og burde blive reporteret som en bug til folkene bag
-
--- 8d45620c1a4348dbb17410da57c60c66
-Subject: En ny session @SESSION_ID@ er blevet lavet for bruger @USER_ID@
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
-
-En ny session med ID @SESSION_ID@ er blevet lavet for brugeren @USER_ID@.
-
-Den ledende process for sessionen er @LEADER@.
-
--- 3354939424b4456d9802ca8333ed424a
-Subject: Session @SESSION_ID@ er blevet lukket ned
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
-
-En session med ID @SESSION_ID@ er blevet lukket ned.
-
--- fcbefc5da23d428093f97c82a9290f7b
-Subject: En ny arbejdsstation $SEAT_ID@ er nu tilgængelig
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
-
-En ny arbejdsstation @SEAT_ID@ er blevet konfigureret og er nu tilgængelig.
-
--- e7852bfe46784ed0accde04bc864c2d5
-Subject: Arbejdsstation @SEAT_ID@ er nu blevet fjernet
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat
-
-En arbejdsstation @SEAT_ID@ er blevet fjernet og er ikke længere tilgængelig.
-
--- c7a787079b354eaaa9e77b371893cd27
-Subject: Tidsændring
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Systemtiden er blevet ændret til @REALTIME@ mikrosekunder efter d. 1. Januar 1970.
-
--- 45f82f4aef7a4bbf942ce861d1f20990
-Subject: Tidszoneændring til @TIMEZONE@
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Tidszonen for systemet er blevet ændret til @TIMEZONE@.
-
--- b07a249cd024414a82dd00cd181378ff
-Subject: Opstart af systemet er nu fuldført
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Alle system services i kø til at køre ved opstart, er blevet startet
-med success. Bemærk at dette ikke betyder at maskinen er i dvale, da
-services stadig kan være i gang med at færdiggøre deres opstart.
-
-Opstart af kernel tog @KERNEL_USEC@ mikrosekunder.
-
-Opstart af initrd tog @INITRD_USEC@ mikrosekunder.
-
-Opstart af userspace tog @USERSPACE_USEC@ mikrosekunder.
-
--- 6bbd95ee977941e497c48be27c254128
-Subject: System slumretilstand @SLEEP@ trådt i kraft
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-System er nu gået i @SLEEP@ slumretilstand.
-
--- 8811e6df2a8e40f58a94cea26f8ebf14
-Subject: System slumretilstand @SLEEP@ forladt
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Systemet har nu forladt @SLEEP@ slumretilstand.
-
--- 98268866d1d54a499c4e98921d93bc40
-Subject: Systemnedlukning påbegyndt
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Systemnedlukning er blevet påbegyndt. Nedlukningen er nu begyndt og
-alle system services er blevet afbrudt og alle filsystemer afmonteret.
-
--- 7d4958e842da4a758f6c1cdc7b36dcc5
-Subject: Enhed @UNIT@ har påbegyndt opstart
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Enhed @UNIT@ er begyndt at starte op.
-
--- 39f53479d3a045ac8e11786248231fbf
-Subject: Enhed @UNIT har færdiggjort opstart
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Enhed @UNIT@ er færdig med at starte op.
-
-Resultat for opstart er @RESULT@.
-
--- de5b426a63be47a7b6ac3eaac82e2f6f
-Subject: Enhed @UNIT@ har påbegyndt nedlukning
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Enhed @UNIT@ har påbegyndt nedlukning.
-
--- 9d1aaa27d60140bd96365438aad20286
-Subject: Enhed @UNIT@ har færdiggjort nedlukning
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Enhed @UNIT@ har færdiggjort nedlukning.
-
--- be02cf6855d2428ba40df7e9d022f03d
-Subject: Enhed @UNIT@ har fejlet
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Enhed @UNIT@ har fejlet.
-
-Resultatet er @RESULT@
-
--- d34d037fff1847e6ae669a370e694725
-Subject: Enhed @UNIT@ har påbegyndt genindlæsning af sin konfiguration
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Enhed @UNIT@ er begyndt at genindlæse sin konfiguration
-
--- 7b05ebc668384222baa8881179cfda54
-Subject: Enhed @UNIT@ har færdiggjort genindlæsning af sin konfiguration
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Enhed @UNIT@ er færdig med at genindlæse sin konfiguration
-
-Resultatet er: @RESULT@.
-
--- 641257651c1b4ec9a8624d7a40a9e1e7
-Subject: Process @EXECUTABLE@ kunne ikke eksekveres
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Processen @EXECUTABLE@ kunne ikke eksekveres og fejlede.
-
-Processens returnerede fejlkode er @ERRNO@.
-
--- 0027229ca0644181a76c4e92458afa2e
-Subject: Èn eller flere beskeder kunne ikke videresendes til syslog
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Èn eller flere beskeder kunne ikke videresendes til syslog servicen
-der kører side-om-side med journald. Dette indikerer typisk at syslog
-implementationen ikke har kunnet følge med mængden af ventende beskeder.
-
--- 1dee0369c7fc4736b7099b38ecb46ee7
-Subject: Monteringspunkt er ikke tomt
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Folderen @WHERE@ er specificeret som monteringspunkt (andet felt i
-/etc/fstab eller Where= feltet i systemd enhedsfil) men er ikke tom.
-Dette forstyrrer ikke monteringen, men de pre-eksisterende filer i folderen
-bliver utilgængelige. For at se de over-monterede filer; montér det
-underlæggende filsystem til en anden lokation.
-
--- 24d8d4452573402496068381a6312df2
-Subject: En virtuel maskine eller container er blevet startet
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet
-startet og er klar til brug.
-
--- 58432bd3bace477cb514b56381b8a758
-Subject: En virtuel maskine eller container er blevet afbrudt
-Defined-By: systemd
-Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-
-Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet
-nedlukket.
+# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +# Message catalog for systemd's own messages +# Danish translation + +# The catalog format is documented on +# http://www.freedesktop.org/wiki/Software/systemd/catalog + +# For an explanation why we do all this, see https://xkcd.com/1024/ + +-- f77379a8490b408bbe5f6940505a777b +Subject: Journalen er blevet startet +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +System-journal processen har startet op, Ã¥bnet journal filerne for +tilskrivning og er nu klar til at modtage anmodninger. + +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: Journalen er blevet stoppet +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +System-journal processen er stoppet og har lukket alle aktive journal +filer. + +-- a596d6fe7bfa4994828e72309e95d61e +Subject: Beskeder fra en service er blevet undertrykt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +En service har logget for mange beskeder inden for en given tidsperiode. +Beskeder fra omtalte service er blevet smidt væk. + +Kun beskeder fra omtalte service er smidt væk. Beskeder fra andre +services er ikke pÃ¥virket. + +Grænsen for hvornÃ¥r beskeder bliver smidt væk kan konfigureres +med RateLimitInterval= og RateLimitBurst= i +/etc/systemd/journald.conf. Se journald.conf(5) for detaljer herom. + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: Journal beskeder er gÃ¥et tabt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Kernel beskeder er gÃ¥et tabt da journal systemet ikke har været i stand +til at hÃ¥ndtere dem hurtigt nok. + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: Fejl-fil genereret for process @COREDUMP_PID@ (@COREDUMP_COMM@) +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Process @COREDUMP_PID@ (@COREDUMP_COMM@) har lukket ned og genereret en +fejl-fil. + +Dette indikerer som regel en programmeringsfejl i det nedlukkede program +og burde blive reporteret som en bug til folkene bag + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: En ny session @SESSION_ID@ er blevet lavet for bruger @USER_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +En ny session med ID @SESSION_ID@ er blevet lavet for brugeren @USER_ID@. + +Den ledende process for sessionen er @LEADER@. + +-- 3354939424b4456d9802ca8333ed424a +Subject: Session @SESSION_ID@ er blevet lukket ned +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +En session med ID @SESSION_ID@ er blevet lukket ned. + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: En ny arbejdsstation $SEAT_ID@ er nu tilgængelig +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +En ny arbejdsstation @SEAT_ID@ er blevet konfigureret og er nu tilgængelig. + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: Arbejdsstation @SEAT_ID@ er nu blevet fjernet +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +En arbejdsstation @SEAT_ID@ er blevet fjernet og er ikke længere tilgængelig. + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: Tidsændring +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Systemtiden er blevet ændret til @REALTIME@ mikrosekunder efter d. 1. Januar 1970. + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: Tidszoneændring til @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Tidszonen for systemet er blevet ændret til @TIMEZONE@. + +-- b07a249cd024414a82dd00cd181378ff +Subject: Opstart af systemet er nu fuldført +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Alle system services i kø til at køre ved opstart, er blevet startet +med success. Bemærk at dette ikke betyder at maskinen er i dvale, da +services stadig kan være i gang med at færdiggøre deres opstart. + +Opstart af kernel tog @KERNEL_USEC@ mikrosekunder. + +Opstart af initrd tog @INITRD_USEC@ mikrosekunder. + +Opstart af userspace tog @USERSPACE_USEC@ mikrosekunder. + +-- 6bbd95ee977941e497c48be27c254128 +Subject: System slumretilstand @SLEEP@ trÃ¥dt i kraft +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +System er nu gÃ¥et i @SLEEP@ slumretilstand. + +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: System slumretilstand @SLEEP@ forladt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Systemet har nu forladt @SLEEP@ slumretilstand. + +-- 98268866d1d54a499c4e98921d93bc40 +Subject: Systemnedlukning pÃ¥begyndt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Systemnedlukning er blevet pÃ¥begyndt. Nedlukningen er nu begyndt og +alle system services er blevet afbrudt og alle filsystemer afmonteret. + +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: Enhed @UNIT@ har pÃ¥begyndt opstart +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Enhed @UNIT@ er begyndt at starte op. + +-- 39f53479d3a045ac8e11786248231fbf +Subject: Enhed @UNIT har færdiggjort opstart +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Enhed @UNIT@ er færdig med at starte op. + +Resultat for opstart er @RESULT@. + +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: Enhed @UNIT@ har pÃ¥begyndt nedlukning +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Enhed @UNIT@ har pÃ¥begyndt nedlukning. + +-- 9d1aaa27d60140bd96365438aad20286 +Subject: Enhed @UNIT@ har færdiggjort nedlukning +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Enhed @UNIT@ har færdiggjort nedlukning. + +-- be02cf6855d2428ba40df7e9d022f03d +Subject: Enhed @UNIT@ har fejlet +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Enhed @UNIT@ har fejlet. + +Resultatet er @RESULT@ + +-- d34d037fff1847e6ae669a370e694725 +Subject: Enhed @UNIT@ har pÃ¥begyndt genindlæsning af sin konfiguration +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Enhed @UNIT@ er begyndt at genindlæse sin konfiguration + +-- 7b05ebc668384222baa8881179cfda54 +Subject: Enhed @UNIT@ har færdiggjort genindlæsning af sin konfiguration +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Enhed @UNIT@ er færdig med at genindlæse sin konfiguration + +Resultatet er: @RESULT@. + +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: Process @EXECUTABLE@ kunne ikke eksekveres +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Processen @EXECUTABLE@ kunne ikke eksekveres og fejlede. + +Processens returnerede fejlkode er @ERRNO@. + +-- 0027229ca0644181a76c4e92458afa2e +Subject: Èn eller flere beskeder kunne ikke videresendes til syslog +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Èn eller flere beskeder kunne ikke videresendes til syslog servicen +der kører side-om-side med journald. Dette indikerer typisk at syslog +implementationen ikke har kunnet følge med mængden af ventende beskeder. + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: Monteringspunkt er ikke tomt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Folderen @WHERE@ er specificeret som monteringspunkt (andet felt i +/etc/fstab eller Where= feltet i systemd enhedsfil) men er ikke tom. +Dette forstyrrer ikke monteringen, men de pre-eksisterende filer i folderen +bliver utilgængelige. For at se de over-monterede filer; montér det +underlæggende filsystem til en anden lokation. + +-- 24d8d4452573402496068381a6312df2 +Subject: En virtuel maskine eller container er blevet startet +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet +startet og er klar til brug. + +-- 58432bd3bace477cb514b56381b8a758 +Subject: En virtuel maskine eller container er blevet afbrudt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Den virtuelle maskine @NAME@ med dens leder PID @LEADER@ er blevet +nedlukket. diff --git a/catalog/systemd.ko.catalog b/catalog/systemd.ko.catalog new file mode 100644 index 0000000000..3c3535a94c --- /dev/null +++ b/catalog/systemd.ko.catalog @@ -0,0 +1,264 @@ +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +# Message catalog for systemd's own messages +# Korean translation + +# The catalog format is documented on +# http://www.freedesktop.org/wiki/Software/systemd/catalog + +# For an explanation why we do all this, see https://xkcd.com/1024/ +# +# Translator : +# Seong-ho Cho <darkcircle.0426@gmail.com>, 2015. + +-- f77379a8490b408bbe5f6940505a777b +Subject: ì €ë„ ì‹œìž‘ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +시스템 ì €ë„ í”„ë¡œì„¸ìŠ¤ë¥¼ ì‹œìž‘í–ˆê³ ê¸°ë¡ëª©ì 으로 ì €ë„ íŒŒì¼ì„ 열었으며, +프로세스 ìš”ì²ì„ ê¸°ë‹¤ë¦¬ê³ ìžˆìŠµë‹ˆë‹¤. + +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: ì €ë„ ë©ˆì¶¤ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +시스템 ì €ë„ í”„ë¡œì„¸ìŠ¤ë¥¼ ê»ê³ 현재 활성화 ì¤‘ì¸ ì €ë„ íŒŒì¼ì„ ëª¨ë‘ +닫았습니다. + +-- a596d6fe7bfa4994828e72309e95d61e +Subject: ì„œë¹„ìŠ¤ì˜ ë©”ì‹œì§€ë¥¼ ê±°ì ˆí•¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +ì¼ì • 시간ë™ì•ˆ 서비스ì—ì„œ 너무 ë§Žì€ ë©”ì‹œì§€ë¥¼ 기ë¡í–ˆìŠµë‹ˆë‹¤. +서비스ì—ì„œ 오는 메시지를 ê±°ì ˆí–ˆìŠµë‹ˆë‹¤. + +ì˜ë¬¸ì ì´ ìžˆëŠ” 서비스로부터 오는 메시지만 ê±°ì ˆí–ˆìŒì„ ì°¸ê³ í•˜ì‹ì‹œì˜¤ +다른 ì„œë¹„ìŠ¤ì˜ ë©”ì‹œì§€ì—는 ì˜í–¥ì„ 주지 않습니다. + +메시지 ê±°ì ˆ ì œì–´ ì œí•œ ê°’ì€ /etc/systemd/journald.conf ì˜ +RateLimitInterval= 변수와 RateLimitBurst= 변수로 ì„¤ì •í•©ë‹ˆë‹¤. +ìžì„¸í•œ ë‚´ìš©ì€ ournald.conf(5)를 살펴보ì‹ì‹œì˜¤. + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: ì €ë„ ë©”ì‹œì§€ 놓침 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +ì €ë„ ì‹œìŠ¤í…œì—ì„œ ì»¤ë„ ë©”ì‹œì§€ë¥¼ 충분히 ë¹ ë¥´ê²Œ ì²˜ë¦¬í• ìˆ˜ 없어 ì»¤ë„ + 메시지를 잃었습니다. + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: 프로세스 @COREDUMP_PID@번 코어 ë¤í”„(@COREDUMP_COMM@) ìƒì„±í•¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +프로세스 @COREDUMP_PID@번 (@COREDUMP_COMM@)ì´ ë¹„ì •ìƒì 으로 ë나 +코어 ë¤í”„를 ìƒì„±í–ˆìŠµë‹ˆë‹¤. + +보통 ë¹„ì •ìƒ ì¢…ë£Œ 관리 프로그램ì—ì„œ í”„ë¡œê·¸ëž˜ë° ì˜¤ë¥˜ë¥¼ 나타내며, +ì œìž‘ìžì—게 버그로 ë³´ê³ í•´ì•¼í•©ë‹ˆë‹¤. + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: @USER_ID@ 사용ìžì˜ 새 @SESSION_ID@ 세션 만듦 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +@USER_ID@ 사용ìžì˜ 새 @SESSION_ID@ ì„¸ì…˜ì„ ë§Œë“¤ì—ˆìŠµë‹ˆë‹¤. + +ì´ ì„¸ì…˜ì˜ ê´€ë¦¬ 프로세스는 @LEADER@ 입니다. + +-- 3354939424b4456d9802ca8333ed424a +Subject: @SESSION_ID@ 세션 마침 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +@SESSION_ID@ ì„¸ì…˜ì„ ë냈습니다. + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: 새 @SEAT_ID@ 시트 ì‚¬ìš©í• ìˆ˜ ìžˆìŒ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +새 @SEAT_ID@ 시트를 ì„¤ì •í–ˆê³ ì‚¬ìš©í• ìˆ˜ 있습니다. + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: @SEAT_ID@ 시트 ì œê±°í•¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +@SEAT_ID@ 시트를 ì œê±°í–ˆìœ¼ë©° ë”ì´ìƒ ì‚¬ìš©í• ìˆ˜ 없습니다. + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: 시간 바꿈 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +시스템 시계를 1970ë…„ 1ì›” 1ì¼ ì´í›„ë¡œ @REALTIME@ 마ì´í¬ë¡œì´ˆ 지난 값으로 +ì„¤ì •í–ˆìŠµë‹ˆë‹¤. + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: @TIMEZONE@ 시간대로 시간대 바꿈 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +시스템 시간대를 @TIMEZONE@ 시간대로 바꾸었습니다. + +-- b07a249cd024414a82dd00cd181378ff +Subject: 시스템 ì‹œë™ ë§ˆì¹¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +부팅 ê³¼ì •ì— ì‹œìž‘í•˜ë ¤ê³ ì¤€ë¹„í•œ ëª¨ë“ ì‹œìŠ¤í…œ 서비스를 성공ì 으로 + 시작했습니다. ë¨¸ì‹ ì´ ì„œë¹„ìŠ¤ì²˜ëŸ¼ 대기중ì´ë¼ëŠ” ì˜ë¯¸ëŠ” 아니며 +지ë™ì„ ì™„ì „ížˆ ë§ˆì¹ ë•Œê¹Œì§€ ì‚¬ìš©ì¤‘ì¼ ìˆ˜ë„ ìžˆëŠ” ì ì°¸ê³ í•˜ì‹ì‹œì˜¤. + +ì»¤ë„ ì‹œë™ì— @KERNEL_USEC@ 마ì´í¬ë¡œì´ˆê°€ 걸립니다. + +초기 램 ë””ìŠ¤í¬ ì‹œë™ì— @INITRD_USEC@ 마ì´í¬ë¡œì´ˆê°€ 걸립니다. + +ì‚¬ìš©ìž ì˜ì— ì‹œë™ì— @USERSPACE_USEC@ 마ì´í¬ë¡œì´ˆê°€ 걸립니다. + +-- 6bbd95ee977941e497c48be27c254128 +Subject: @SLEEP@ 대기 ìƒíƒœ 진입 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@SLEEP@ 대기 ìƒíƒœë¡œ 진입했습니다. + +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: @SLEEP@ 대기 ìƒíƒœ 마침 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@SLEEP@ 대기 ìƒíƒœë¥¼ 마쳤습니다. + +-- 98268866d1d54a499c4e98921d93bc40 +Subject: 컴퓨터 ë„기 시작 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +컴퓨터 ë„기 ë™ìž‘ì„ ì‹œìž‘í–ˆìŠµë‹ˆë‹¤. ëª¨ë“ ì‹œìŠ¤í…œ ë™ìž‘ì„ ë©ˆì¶”ê³ +ëª¨ë“ íŒŒì¼ ì‹œìŠ¤í…œì˜ ë§ˆìš´íŠ¸ë¥¼ í•´ì œí•©ë‹ˆë‹¤. + +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: @UNIT@ ìœ ë‹› 시작 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ ìœ ë‹›ì„ ì‹œìž‘í–ˆìŠµë‹ˆë‹¤. + +-- 39f53479d3a045ac8e11786248231fbf +Subject: @UNIT@ ìœ ë‹› ì‹œë™ ë§ˆì¹¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ ìœ ë‹› ì‹œë™ì„ 마쳤습니다. + +ì‹œë™ ê²°ê³¼ëŠ” @RESULT@ 입니다. + +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: @UNIT@ ìœ ë‹› ë내기 ë™ìž‘ 시작 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ ìœ ë‹› ë내기 ë™ìž‘ì„ ì‹œìž‘í–ˆìŠµë‹ˆë‹¤. + +-- 9d1aaa27d60140bd96365438aad20286 +Subject: @UNIT@ ìœ ë‹› ë내기 ë™ìž‘ 마침 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ ìœ ë‹› ë내기 ë™ìž‘ì„ ë§ˆì³¤ìŠµë‹ˆë‹¤. + +-- be02cf6855d2428ba40df7e9d022f03d +Subject: @UNIT@ ìœ ë‹› ë™ìž‘ 실패 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ ìœ ë‹› ë™ìž‘ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤. + +결과는 @RESULT@ 입니다. + +-- d34d037fff1847e6ae669a370e694725 +Subject: @UNIT@ ìœ ë‹› ì„¤ì • 다시 ì½ê¸° 시작 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ ìœ ë‹›ì˜ ì„¤ì • 다시 ì½ê¸°ë¥¼ 시작했습니다 + +-- 7b05ebc668384222baa8881179cfda54 +Subject: @UNIT@ ìœ ë‹› ì„¤ì • 다시 ì½ê¸° 완료 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ ìœ ë‹›ì˜ ì„¤ì • 다시 ì½ê¸° ë™ìž‘ì„ ë냈습니다. + +결과는 @RESULT@ 입니다. + +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: @EXECUTABLE@ 프로세스 ì‹œìž‘í• ìˆ˜ ì—†ìŒ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@EXECUTABLE@ 프로세스를 ì‹œìž‘í• ìˆ˜ 없어 ì‹¤í–‰ì— ì‹¤íŒ¨í–ˆìŠµë‹ˆë‹¤. + +ì´ í”„ë¡œì„¸ìŠ¤ì—ì„œ 반환한 오류 번호는 @ERRNO@번 입니다. + +-- 0027229ca0644181a76c4e92458afa2e +Subject: 하나 ì´ìƒì˜ 메시지를 syslogì— ì „ë‹¬í• ìˆ˜ ì—†ìŒ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +journald 서비스와 ë™ì‹œì— ì‹¤í–‰ì¤‘ì¸ syslog ì„œë¹„ìŠ¤ì— í•˜ë‚˜ ì´ìƒì˜ 메시지를 +ì „ë‹¬í• ìˆ˜ 없습니다. 보통 순차ì 으로 오는 ë©”ì‹œì§€ì˜ ì†ë„를 syslog 구현체가 +ë”°ë¼ê°€ì§€ ëª»í•¨ì„ ì˜ë¯¸í•©ë‹ˆë‹¤. + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: 마운트 지ì 비어있지 ì•ŠìŒ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@WHERE@ ë””ë ‰í„°ë¦¬ë¥¼ 마운트 지ì 으로 ì§€ì •í–ˆìœ¼ë©° (/etc/fstab 파ì¼ì˜ + ë‘번째 í•„ë“œ ë˜ëŠ” systemd ìœ ë‹› 파ì¼ì˜ Where= í•„ë“œ) 비어있지 않습니다. +마운트 ê³¼ì •ì— ë°©í•´ê°€ ë˜ì§„ 않지만 ì´ì „ì— ì´ ë””ë ‰í„°ë¦¬ì— ì¡´ìž¬í•˜ëŠ” 파ì¼ì— + ì ‘ê·¼í• ìˆ˜ 없게 ë©ë‹ˆë‹¤. 중복으로 마운트한 파ì¼ì„ ë³´ë ¤ë©´, 근본 íŒŒì¼ +ì‹œìŠ¤í…œì˜ ë‹¤ìŒ ìœ„ì¹˜ì— ì§ì ‘ 마운트하ì‹ì‹œì˜¤. + +-- 24d8d4452573402496068381a6312df2 +Subject: ê°€ìƒ ë¨¸ì‹ ë˜ëŠ” 컨테ì´ë„ˆ 시작 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@LEADER@ 프로세스 IDë¡œ ë™ìž‘하는 @NAME@ ê°€ìƒ ë¨¸ì‹ ì„ ì‹œìž‘í–ˆìœ¼ë©°, +ì´ì œë¶€í„° ì‚¬ìš©í• ìˆ˜ 있습니다. + +-- 58432bd3bace477cb514b56381b8a758 +Subject: ê°€ìƒ ë¨¸ì‹ ë˜ëŠ” 컨테ì´ë„ˆ 마침 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@LEADER@ 프로세스 IDë¡œ ë™ìž‘하는 @NAME@ ê°€ìƒ ë¨¸ì‹ ì„ ê»ìŠµë‹ˆë‹¤. diff --git a/catalog/systemd.zh_CN.catalog b/catalog/systemd.zh_CN.catalog new file mode 100644 index 0000000000..38639109e4 --- /dev/null +++ b/catalog/systemd.zh_CN.catalog @@ -0,0 +1,253 @@ +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# Copyright 2015 Boyuan Yang +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see <http://www.gnu.org/licenses/>. + +# Message catalog for systemd's own messages +# Simplified Chinese translation + +# 本 catalog æ–‡æ¡£æ ¼å¼è¢«è®°è½½åœ¨ +# http://www.freedesktop.org/wiki/Software/systemd/catalog + +# 如需了解我们为什么åšè¿™äº›å·¥ä½œï¼Œè¯·è§ https://xkcd.com/1024/ + +-- f77379a8490b408bbe5f6940505a777b +Subject: 日志已开始 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +系统日志进程已å¯åŠ¨ï¼Œå·²æ‰“开供写入的日志文件并准备好处ç†è¯·æ±‚。 + +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: 日志已åœæ¢ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +系统日志进程已终æ¢ï¼Œå¹¶å·²å…³é—所有当å‰æ´»åŠ¨çš„日志文件。 + +-- a596d6fe7bfa4994828e72309e95d61e +Subject: ç”±æŸä¸ªæœåŠ¡è€Œæ¥çš„消æ¯å·²è¢«æŠ‘制 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +æŸä¸ªæœåŠ¡åœ¨ä¸€ä¸ªæ—¶é—´å‘¨æœŸå†…记录了太多消æ¯ã€‚ +从该æœåŠ¡è€Œæ¥çš„消æ¯å·²è¢«ä¸¢å¼ƒã€‚ + +请注æ„åªæœ‰ç”±æœ‰é—®é¢˜çš„æœåŠ¡ä¼ æ¥çš„消æ¯è¢«ä¸¢å¼ƒï¼Œ +其它æœåŠ¡çš„消æ¯ä¸å—å½±å“。 + +å¯ä»¥åœ¨ /etc/systemd/journald.conf ä¸è®¾å®š RateLimitInterval= +ä»¥åŠ RateLimitBurst = 的值以控制丢弃信æ¯çš„é™åˆ¶ã€‚ +请å‚è§ journald.conf(5) 以了解详情。 + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: 日志消æ¯å·²é—失 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +å› æ—¥å¿—ç³»ç»Ÿå¯¹å†…æ ¸æ¶ˆæ¯çš„处ç†é€Ÿåº¦ä¸å¤Ÿå¿«ï¼Œ +部分信æ¯å·²ç»é—失。 + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: 进程 @COREDUMP_PID@ (@COREDUMP_COMM@) æ ¸å¿ƒå·²è½¬å‚¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +进程 @COREDUMP_PID@ (@COREDUMP_COMM@) å·²å´©æºƒå¹¶è¿›è¡Œæ ¸å¿ƒè½¬å‚¨ã€‚ + +这通常æ„味ç€å´©æºƒç¨‹åºä¸å˜åœ¨ç¼–程错误,并应当将æ¤é”™è¯¯å‘其开å‘者报告。 + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: ä¸€ä¸ªæ–°ä¼šè¯ @SESSION_ID@ 已为用户 @USER_ID@ 建立 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +一个 ID 为 @SESSION_ID@ 的新会è¯å·²ä¸ºç”¨æˆ· @USER_ID@ 建立。 + +该会è¯çš„首进程为 @LEADER@。 + +-- 3354939424b4456d9802ca8333ed424a +Subject: ä¼šè¯ @SESSION_ID@ å·²ç»ˆæ¢ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +一个 ID 为 @SESSION_ID@ 的会è¯å·²ç»ˆæ¢ã€‚ + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: ä¸€ä¸ªæ–°çš„åº§ä½ @SEAT_ID@ å¯ç”¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +ä¸€ä¸ªæ–°çš„åº§ä½ @SEAT_ID@ 已被é…置并已å¯ç”¨ã€‚ + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: åº§ä½ @SEAT_ID@ 已被移除 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +åº§ä½ @SEAT_ID@ 已被移除并ä¸å†å¯ç”¨ã€‚ + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: 时间已å˜æ›´ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +系统时钟已å˜æ›´ä¸º1970å¹´1月1æ—¥åŽ @REALTIME@ 微秒。 + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: 时区å˜æ›´ä¸º @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +系统时区已å˜æ›´ä¸º @TIMEZONE@。 + +-- b07a249cd024414a82dd00cd181378ff +Subject: 系统å¯åŠ¨å·²å®Œæˆ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +所有系统å¯åŠ¨æ—¶éœ€è¦çš„系统æœåŠ¡å‡å·²æˆåŠŸå¯åŠ¨ã€‚ +请注æ„这并ä¸ä»£è¡¨çŽ°åœ¨æœºå™¨å·²ç»ç©ºé—²ï¼Œå› 为æŸäº›æœåŠ¡å¯èƒ½ä»å¤„于完æˆå¯åŠ¨çš„过程ä¸ã€‚ + +å†…æ ¸å¯åŠ¨ä½¿ç”¨äº† @KERNEL_USEC@ 毫秒。 + +åˆå§‹å†…å˜ç›˜å¯åŠ¨ä½¿ç”¨äº† @INITRD_USEC@ 毫秒。 + +用户空间å¯åŠ¨ä½¿ç”¨äº† @USERSPACE_USEC@ 毫秒。 + +-- 6bbd95ee977941e497c48be27c254128 +Subject: 系统已进入 @SLEEP@ ç¡çœ çŠ¶æ€ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-deve + +系统现已进入 @SLEEP@ ç¡çœ 状æ€ã€‚ + +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: 系统已离开 @SLEEP@ ç¡çœ çŠ¶æ€ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +系统现已离开 @SLEEP@ ç¡çœ 状æ€ã€‚ + +-- 98268866d1d54a499c4e98921d93bc40 +Subject: 系统关机已开始 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +系统关机æ“作已åˆå§‹åŒ–。 +关机已开始,所有系统æœåŠ¡å‡å·²ç»“æŸï¼Œæ‰€æœ‰æ–‡ä»¶ç³»ç»Ÿå·²å¸è½½ã€‚ + +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: @UNIT@ å•å…ƒå·²å¼€å§‹å¯åŠ¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ å•å…ƒå·²å¼€å§‹å¯åŠ¨ã€‚ + +-- 39f53479d3a045ac8e11786248231fbf +Subject: @UNIT@ å•å…ƒå·²ç»“æŸå¯åŠ¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ å•å…ƒå·²ç»“æŸå¯åŠ¨ã€‚ + +å¯åŠ¨ç»“果为“@RESULT@â€ã€‚ + +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: @UNIT@ å•å…ƒå·²å¼€å§‹åœæ¢æ“作 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ å•å…ƒå·²å¼€å§‹åœæ¢æ“作。 + +-- 9d1aaa27d60140bd96365438aad20286 +Subject: @UNIT@ å•å…ƒå·²ç»“æŸåœæ¢æ“作 +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ å•å…ƒå·²ç»“æŸåœæ¢æ“作。 + +-- be02cf6855d2428ba40df7e9d022f03d +Subject: @UNIT@ å•å…ƒå·²å¤±è´¥ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ å•å…ƒå·²å¤±è´¥ã€‚ + +结果为“@RESULT@â€ã€‚ + +-- d34d037fff1847e6ae669a370e694725 +Subject: @UNIT@ å•å…ƒå·²å¼€å§‹é‡æ–°è½½å…¥å…¶é…ç½® +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ å•å…ƒå·²å¼€å§‹é‡æ–°è½½å…¥å…¶é…置。 + +-- 7b05ebc668384222baa8881179cfda54 +Subject: @UNIT@ å•å…ƒå·²ç»“æŸé…ç½®é‡è½½å…¥ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@UNIT@ å•å…ƒå·²ç»“æŸé…ç½®é‡è½½å…¥æ“作。 + +结果为“@RESULT@â€ã€‚ + +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: 进程 @EXECUTABLE@ æ— æ³•æ‰§è¡Œ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +进程 @EXECUTABLE@ æ— æ³•è¢«æ‰§è¡Œå¹¶å·²å¤±è´¥ã€‚ + +该进程返回的错误代ç 为 @ERRNO@。 + +-- 0027229ca0644181a76c4e92458afa2e +Subject: 一个或更多消æ¯æ— 法被转å‘至 syslog +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +有一æ¡æˆ–更多的消æ¯æ— 法被转å‘至与 journald åŒæ—¶è¿è¡Œçš„ syslog æœåŠ¡ã€‚ +这通常æ„å‘³ç€ syslog å®žçŽ°æ— æ³•è·Ÿä¸Šé˜Ÿåˆ—ä¸æ¶ˆæ¯è¿›å…¥çš„速度。 + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: 挂载点ä¸ä¸ºç©º +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +目录 @WHERE@ è¢«æŒ‡å®šä¸ºæŒ‚è½½ç‚¹ï¼ˆå³ /etc/fstab 文件的第二æ ,或 systemd å•å…ƒ +文件的 Where= å—段),且该目录éžç©ºã€‚ +这并ä¸ä¼šå½±å“挂载行为,但该目录ä¸å…ˆå‰å·²å˜åœ¨çš„æ–‡ä»¶å°†æ— æ³•è¢«è®¿é—®ã€‚ +如需查看这些文件,请手动将其下的文件系统挂载到å¦ä¸€ä¸ªä½ç½®ã€‚ + +-- 24d8d4452573402496068381a6312df2 +Subject: 一个虚拟机或容器已å¯åŠ¨ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +虚拟机 @NAME@,以åŠå…¶é¦–进程 PID @LEADER@,已被å¯åŠ¨å¹¶å¯è¢«ä½¿ç”¨ã€‚ + +-- 58432bd3bace477cb514b56381b8a758 +Subject: ä¸€ä¸ªè™šæ‹Ÿæœºæˆ–å®¹å™¨å·²è¢«ç»ˆæ¢ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +虚拟机 @NAME@,以åŠå…¶é¦–进程 PID @LEADER@,已被关é—并åœæ¢ã€‚ diff --git a/coccinelle/errno.cocci b/coccinelle/errno.cocci index 45f2b6e9d5..ed74c0a98a 100644 --- a/coccinelle/errno.cocci +++ b/coccinelle/errno.cocci @@ -1,48 +1,32 @@ @@ -identifier r; +identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; expression e; @@ - r = -e; -- log_error_errno(e, -+ r = log_error_errno(e, - ...); ++ r = + log_LEVEL_errno(e, ...); @@ -identifier r; +identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; expression e; @@ -- log_error_errno(e, -+ r = log_error_errno(e, - ...); ++ r = + log_LEVEL_errno(e, ...); - r = -e; @@ -identifier r; +identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; expression e; @@ -- r = log_error_errno(e, -+ return log_error_errno(e, - ...); +- r = ++ return + log_LEVEL_errno(e, ...); - return r; @@ -identifier r; +identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$"; expression e; @@ -- r = -e; -- log_warning_errno(e, -+ r = log_warning_errno(e, - ...); -@@ -identifier r; -expression e; -@@ -- log_warning_errno(e, -+ r = log_warning_errno(e, - ...); -- r = -e; -@@ -identifier r; -expression e; -@@ -- r = log_warning_errno(e, -+ return log_warning_errno(e, - ...); -- return r; ++ return + log_LEVEL_errno(e, ...); +- return -e; diff --git a/configure.ac b/configure.ac index 5e3cdd6d2b..c96b9fb1d9 100644 --- a/configure.ac +++ b/configure.ac @@ -93,7 +93,6 @@ AC_PROG_GREP AC_PROG_AWK AC_PATH_PROG([M4], [m4]) -AC_PATH_PROG([XSLTPROC], [xsltproc]) AC_PATH_PROG([QUOTAON], [quotaon], [/usr/sbin/quotaon], [$PATH:/usr/sbin:/sbin]) AC_PATH_PROG([QUOTACHECK], [quotacheck], [/usr/sbin/quotacheck], [$PATH:/usr/sbin:/sbin]) @@ -282,7 +281,6 @@ AM_CONDITIONAL([HAVE_PYTHON], [test "x$have_python" = "xyes"]) # ------------------------------------------------------------------------------ -AC_SEARCH_LIBS([dlsym], [dl], [], [AC_MSG_ERROR([*** Dynamic linking loader library not found])]) AC_CHECK_HEADERS([sys/capability.h], [], [AC_MSG_ERROR([*** POSIX caps headers not found])]) AC_CHECK_HEADERS([linux/btrfs.h], [], []) AC_CHECK_HEADERS([linux/memfd.h], [], []) @@ -294,6 +292,7 @@ save_LIBS="$LIBS" LIBS= AC_SEARCH_LIBS([cap_init], [cap], [], [AC_MSG_ERROR([*** POSIX caps library not found])]) CAP_LIBS="$LIBS" +LIBS="$save_LIBS" AC_SUBST(CAP_LIBS) AC_CHECK_FUNCS([memfd_create]) @@ -531,25 +530,27 @@ AC_SUBST(CERTIFICATEROOT) # ------------------------------------------------------------------------------ have_xz=no AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support])) -if test "x$enable_xz" != "xno"; then +AS_IF([test "x$enable_xz" != "xno"], [ PKG_CHECK_MODULES(XZ, [ liblzma ], - [AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available]) have_xz=yes], have_xz=no) - if test "x$have_xz" = xno -a "x$enable_xz" = xyes; then - AC_MSG_ERROR([*** XZ support requested but libraries not found]) - fi -fi + [AC_DEFINE(HAVE_XZ, 1, [Define if XZ is available]) + have_xz=yes], + have_xz=no) + AS_IF([test "x$have_xz" = xno -a "x$enable_xz" = xyes], + [AC_MSG_ERROR([*** XZ support requested but libraries not found])]) +]) AM_CONDITIONAL(HAVE_XZ, [test "$have_xz" = "yes"]) # ------------------------------------------------------------------------------ have_zlib=no AC_ARG_ENABLE(zlib, AS_HELP_STRING([--disable-zlib], [Disable optional ZLIB support])) -if test "x$enable_zlib" != "xno"; then +AS_IF([test "x$enable_zlib" != "xno"], [ PKG_CHECK_MODULES(ZLIB, [ zlib ], - [AC_DEFINE(HAVE_ZLIB, 1, [Define if ZLIB is available]) have_zlib=yes], have_zlib=no) - if test "x$have_zlib" = xno -a "x$enable_zlib" = xyes; then - AC_MSG_ERROR([*** ZLIB support requested but libraries not found]) - fi -fi + [AC_DEFINE(HAVE_ZLIB, 1, [Define if ZLIB is available]) + have_zlib=yes], + have_zlib=no) + AS_IF([test "x$have_zlib" = xno -a "x$enable_zlib" = xyes], + [AC_MSG_ERROR([*** ZLIB support requested but libraries not found])]) +]) AM_CONDITIONAL(HAVE_ZLIB, [test "$have_zlib" = "yes"]) # ------------------------------------------------------------------------------ @@ -557,20 +558,24 @@ have_bzip2=no AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Disable optional BZIP2 support])) AS_IF([test "x$enable_bzip2" != "xno"], [ AC_CHECK_HEADERS(bzlib.h, - [AC_DEFINE(HAVE_BZIP2, 1, [Define in BZIP2 is available]) + [AC_DEFINE(HAVE_BZIP2, 1, [Define if BZIP2 is available]) have_bzip2=yes], - [AS_IF([test "x$have_bzip2" = xyes], [AC_MSG_ERROR([*** BZIP2 support requested but headers not found])]) - ]) + [AS_IF([test "x$enable_bzip2" = xyes], + [AC_MSG_ERROR([*** BZIP2 support requested but headers not found])])] + ) ]) AM_CONDITIONAL(HAVE_BZIP2, [test "$have_bzip2" = "yes"]) # ------------------------------------------------------------------------------ have_lz4=no -AC_ARG_ENABLE(lz4, AS_HELP_STRING([--enable-lz4], [Enable optional LZ4 support])) -AS_IF([test "x$enable_lz4" = "xyes"], [ - AC_CHECK_HEADERS(lz4.h, - [AC_DEFINE(HAVE_LZ4, 1, [Define in LZ4 is available]) have_lz4=yes], - [AC_MSG_ERROR([*** LZ4 support requested but headers not found])]) +AC_ARG_ENABLE(lz4, AS_HELP_STRING([--disable-lz4], [Disable optional LZ4 support])) +AS_IF([test "x$enable_lz4" != "xno"], [ + PKG_CHECK_MODULES(LZ4, [ liblz4 >= 125 ], + [AC_DEFINE(HAVE_LZ4, 1, [Define in LZ4 is available]) + have_lz4=yes], + have_lz4=no) + AS_IF([test "x$have_lz4" = xno -a "x$enable_lz4" = xyes], + [AC_MSG_ERROR([*** LZ4 support requested but libraries not found])]) ]) AM_CONDITIONAL(HAVE_LZ4, [test "$have_lz4" = "yes"]) @@ -791,14 +796,6 @@ if test "x${have_elfutils}" != xno ; then AC_CHECK_LIB( [dw], - [dwfl_begin], - [], - [if test "x$have_elfutils" = xyes ; then - AC_MSG_ERROR([*** ELFUTILS libs not found.]) - fi]) - - AC_CHECK_LIB( - [dw], [dwfl_core_file_attach], [have_elfutils=yes], [if test "x$have_elfutils" = xyes ; then @@ -1107,10 +1104,12 @@ AM_CONDITIONAL(ENABLE_POLKIT, [test "x$have_polkit" = "xyes"]) # ------------------------------------------------------------------------------ have_resolved=no AC_ARG_ENABLE(resolved, AS_HELP_STRING([--disable-resolved], [disable resolve daemon])) -if test "x$enable_resolved" != "xno"; then +AS_IF([test "x$enable_resolved" != "xno"], [ + AC_CHECK_LIB([dl], [dlsym], [true], [AC_MSG_ERROR([*** Dynamic linking loader library not found])]) + have_resolved=yes M4_DEFINES="$M4_DEFINES -DENABLE_RESOLVED" -fi +]) AM_CONDITIONAL(ENABLE_RESOLVED, [test "$have_resolved" = "yes"]) AC_ARG_WITH(dns-servers, @@ -1286,7 +1285,12 @@ AM_CONDITIONAL(ENABLE_HWDB, [test x$enable_hwdb = xyes]) # ------------------------------------------------------------------------------ have_manpages=no AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages], [disable manpages])) -AS_IF([test "x$enable_manpages" != xno], [have_manpages=yes]) +AS_IF([test "x$enable_manpages" != xno], [ + have_manpages=yes + AC_PATH_PROG([XSLTPROC], [xsltproc]) + AS_IF([test -z "$XSLTPROC"], + AC_MSG_ERROR([*** xsltproc is required for man pages])) +]) AM_CONDITIONAL(ENABLE_MANPAGES, [test "x$have_manpages" = "xyes"]) # ------------------------------------------------------------------------------ diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb index 1dd642678d..a825e744e1 100644 --- a/hwdb/20-bluetooth-vendor-product.hwdb +++ b/hwdb/20-bluetooth-vendor-product.hwdb @@ -1982,3 +1982,87 @@ bluetooth:v0291* bluetooth:v0292* ID_VENDOR_FROM_DATABASE=SwiftSensors + +bluetooth:v0293* + ID_VENDOR_FROM_DATABASE=Blue Bite + +bluetooth:v0294* + ID_VENDOR_FROM_DATABASE=ELIAS GmbH + +bluetooth:v0295* + ID_VENDOR_FROM_DATABASE=Sivantos GmbH + +bluetooth:v0296* + ID_VENDOR_FROM_DATABASE=Petzl + +bluetooth:v0297* + ID_VENDOR_FROM_DATABASE=storm power ltd + +bluetooth:v0298* + ID_VENDOR_FROM_DATABASE=EISST Ltd + +bluetooth:v0299* + ID_VENDOR_FROM_DATABASE=Inexess Technology Simma KG + +bluetooth:v029A* + ID_VENDOR_FROM_DATABASE=Currant, Inc. + +bluetooth:v029B* + ID_VENDOR_FROM_DATABASE=C2 Development, Inc. + +bluetooth:v029C* + ID_VENDOR_FROM_DATABASE=Blue Sky Scientific, LLC + +bluetooth:v029D* + ID_VENDOR_FROM_DATABASE=ALOTTAZS LABS, LLC + +bluetooth:v029E* + ID_VENDOR_FROM_DATABASE=Kupson spol. s r.o. + +bluetooth:v029F* + ID_VENDOR_FROM_DATABASE=Areus Engineering GmbH + +bluetooth:v02A0* + ID_VENDOR_FROM_DATABASE=Impossible Camera GmbH + +bluetooth:v02A1* + ID_VENDOR_FROM_DATABASE=InventureTrack Systems + +bluetooth:v02A2* + ID_VENDOR_FROM_DATABASE=LockedUp + +bluetooth:v02A3* + ID_VENDOR_FROM_DATABASE=Itude + +bluetooth:v02A4* + ID_VENDOR_FROM_DATABASE=Pacific Lock Company + +bluetooth:v02A5* + ID_VENDOR_FROM_DATABASE=Tendyron Corporation ( 天地èžç§‘技股份有é™å…¬å¸ ) + +bluetooth:v02A6* + ID_VENDOR_FROM_DATABASE=Robert Bosch GmbH + +bluetooth:v02A7* + ID_VENDOR_FROM_DATABASE=Illuxtron international B.V. + +bluetooth:v02A8* + ID_VENDOR_FROM_DATABASE=miSport Ltd. + +bluetooth:v02A9* + ID_VENDOR_FROM_DATABASE=Chargelib + +bluetooth:v02AA* + ID_VENDOR_FROM_DATABASE=Doppler Lab + +bluetooth:v02AB* + ID_VENDOR_FROM_DATABASE=BBPOS Limited + +bluetooth:v02AC* + ID_VENDOR_FROM_DATABASE=RTB Elektronik GmbH & Co. KG + +bluetooth:v02AD* + ID_VENDOR_FROM_DATABASE=Rx Networks, Inc. + +bluetooth:v02AE* + ID_VENDOR_FROM_DATABASE=WeatherFlow, Inc. diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb index 58d7337a1d..f7a82ee26c 100644 --- a/hwdb/60-evdev.hwdb +++ b/hwdb/60-evdev.hwdb @@ -100,6 +100,22 @@ evdev:name:ETPS/2 Elantech Touchpad:dmi:bvn*:bvr*:bd*:svnASUSTeKComputerInc.:pnK EVDEV_ABS_36=::16 ######################################### +# Dell +######################################### + +# Dell Vostro 1510 +evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510* + EVDEV_ABS_00=::14 + EVDEV_ABS_01=::18 + +# Dell Inspiron N5040 +evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInspironN5040* + EVDEV_ABS_00=25:2000:22 + EVDEV_ABS_01=0:1351:28 + EVDEV_ABS_35=25:2000:22 + EVDEV_ABS_36=0:1351:28 + +######################################### # Google ######################################### @@ -119,11 +135,9 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*X230* EVDEV_ABS_01=::100 EVDEV_ABS_36=::100 -######################################### -# Dell -######################################### - -# Dell Vostro 1510 -evdev:name:AlpsPS/2 ALPS GlidePoint*:dmi:bvn*:bvr*:bd*:svnDellInc.:pnVostro1510* - EVDEV_ABS_00=::14 - EVDEV_ABS_01=::18 +# Lenovo T510 +evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T510* + EVDEV_ABS_00=778:6239:72 + EVDEV_ABS_01=841:5330:100 + EVDEV_ABS_35=778:6239:72 + EVDEV_ABS_36=841:5330:100 diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb index 24db0d2ba6..94906abcbf 100644 --- a/hwdb/60-keyboard.hwdb +++ b/hwdb/60-keyboard.hwdb @@ -495,6 +495,10 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook445G1NotebookPC:pvr evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook450G0:pvr* KEYBOARD_KEY_81=f20 # Fn+F8; Microphone mute button, should be micmute +# HP ProBook 6555b +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard:pnHPProBook6555b:* + KEYBOARD_KEY_b2=www # Earth + ########################################################### # IBM ########################################################### @@ -648,11 +652,6 @@ evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr* KEYBOARD_KEY_f1=f21 -# Thinkpad Yoga 12 (2015) -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*:pvrThinkPadS1Yoga12* - KEYBOARD_KEY_d8=direction - KEYBOARD_KEY_d9=direction - # enhanced USB keyboard evdev:input:b0003v04B3p301B* KEYBOARD_KEY_90001=prog1 # ThinkVantage diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb index 55e68a9138..2383d586a3 100644 --- a/hwdb/70-mouse.hwdb +++ b/hwdb/70-mouse.hwdb @@ -311,6 +311,9 @@ mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse: mouse:usb:v046dpc065:name:Logitech USB Laser Mouse: # Logitech V500 Cordless Notebook Mouse mouse:usb:v046dpc510:name:Logitech USB Receiver: +# Logitech M560 Wireless Mouse +mouse:usb:v046dp402d:name:Logitech M560: +mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:402d: MOUSE_DPI=1000@125 # Logitech V220 Cordless Optical Mouse diff --git a/man/bootchart.conf.xml b/man/bootchart.conf.xml index bf6ca0bf9e..f6ac7e6ae2 100644 --- a/man/bootchart.conf.xml +++ b/man/bootchart.conf.xml @@ -86,7 +86,7 @@ <term><varname>Frequency=25</varname></term> <listitem><para>Configure the sample log frequency. This can be a fractional number, but must be larger than 0.0. Most - systems can cope with values under 25-50 without impacting + systems can cope with values under 25–50 without impacting boot time severely.</para></listitem> </varlistentry> diff --git a/man/bootctl.xml b/man/bootctl.xml index 63ad9392eb..ebd58750d3 100644 --- a/man/bootctl.xml +++ b/man/bootctl.xml @@ -68,14 +68,14 @@ system.</para> <para><command>bootctl status</command> checks and prints the - currently installed versions of the boot loader binaries and the + currently installed versions of the boot loader binaries and all current EFI boot variables.</para> <para><command>bootctl update</command> updates all installed versions of systemd-boot, if the current version is newer than the version installed in the EFI system partition. This also includes the EFI default/fallback loader at /EFI/Boot/boot*.efi. A - systemd-boot entry in the EFI boot variables is created, if there + systemd-boot entry in the EFI boot variables is created if there is no current entry. The created entry will be added to the end of the boot order list.</para> @@ -89,7 +89,7 @@ versions of systemd-boot from the EFI system partition, and removes systemd-boot from the EFI boot variables.</para> - <para>If no command is passed <command>status</command> is + <para>If no command is passed, <command>status</command> is implied.</para> </refsect1> @@ -114,7 +114,7 @@ <refsect1> <title>Exit status</title> - <para>On success 0 is returned, a non-zero failure + <para>On success, 0 is returned, a non-zero failure code otherwise.</para> </refsect1> diff --git a/man/busctl.xml b/man/busctl.xml index 4f0b2a7051..d8c1085021 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -127,7 +127,7 @@ <term><option>--size=</option></term> <listitem> - <para>When used with the <command>capture</command> command + <para>When used with the <command>capture</command> command, specifies the maximum bus message size to capture ("snaplen"). Defaults to 4096 bytes.</para> </listitem> @@ -137,7 +137,7 @@ <term><option>--list</option></term> <listitem> - <para>When used with the <command>tree</command> command shows a + <para>When used with the <command>tree</command> command, shows a flat list of object paths instead of a tree.</para> </listitem> </varlistentry> @@ -146,9 +146,9 @@ <term><option>--quiet</option></term> <listitem> - <para>When used with the <command>call</command> command + <para>When used with the <command>call</command> command, suppresses display of the response message payload. Note that even - if this option is specified errors returned will still be + if this option is specified, errors returned will still be printed and the tool will indicate success or failure with the process exit code.</para> </listitem> @@ -159,7 +159,7 @@ <listitem> <para>When used with the <command>call</command> or - <command>get-property</command> command shows output in a + <command>get-property</command> command, shows output in a more verbose format.</para> </listitem> </varlistentry> @@ -168,15 +168,15 @@ <term><option>--expect-reply=</option><replaceable>BOOL</replaceable></term> <listitem> - <para>When used with the <command>call</command> command + <para>When used with the <command>call</command> command, specifies whether <command>busctl</command> shall wait for completion of the method call, output the returned method response data, and return success or failure via the process - exit code. If this is set to <literal>no</literal> the + exit code. If this is set to <literal>no</literal>, the method call will be issued but no response is expected, the tool terminates immediately, and thus no response can be shown, and no success or failure is returned via the exit - code. To only suppress output of the reply message payload + code. To only suppress output of the reply message payload, use <option>--quiet</option> above. Defaults to <literal>yes</literal>.</para> </listitem> @@ -186,9 +186,9 @@ <term><option>--auto-start=</option><replaceable>BOOL</replaceable></term> <listitem> - <para>When used with the <command>call</command> command specifies + <para>When used with the <command>call</command> command, specifies whether the method call should implicitly activate the - called service should it not be running yet but is + called service, should it not be running yet but is configured to be auto-started. Defaults to <literal>yes</literal>.</para> </listitem> @@ -198,7 +198,7 @@ <term><option>--allow-interactive-authorization=</option><replaceable>BOOL</replaceable></term> <listitem> - <para>When used with the <command>call</command> command + <para>When used with the <command>call</command> command, specifies whether the services may enforce interactive authorization while executing the operation, if the security policy is configured for this. Defaults to @@ -210,14 +210,14 @@ <term><option>--timeout=</option><replaceable>SECS</replaceable></term> <listitem> - <para>When used with the <command>call</command> command + <para>When used with the <command>call</command> command, specifies the maximum time to wait for method call - completion. If no time unit is specified assumes + completion. If no time unit is specified, assumes seconds. The usual other units are understood, too (ms, us, s, min, h, d, w, month, y). Note that this timeout does not - apply if <option>--expect-reply=no</option> is used as the + apply if <option>--expect-reply=no</option> is used, as the tool does not wait for any reply message then. When not - specified or when set to 0 the default of + specified or when set to 0, the default of <literal>25s</literal> is assumed.</para> </listitem> </varlistentry> @@ -229,9 +229,9 @@ <para>Controls whether credential data reported by <command>list</command> or <command>status</command> shall be augmented with data from - <filename>/proc</filename>. When this is turned on the data + <filename>/proc</filename>. When this is turned on, the data shown is possibly inconsistent, as the data read from - <filename>/proc</filename> might be more recent than rest of + <filename>/proc</filename> might be more recent than the rest of the credential information. Defaults to <literal>yes</literal>.</para> </listitem> </varlistentry> @@ -258,7 +258,7 @@ <term><command>list</command></term> <listitem><para>Show all peers on the bus, by their service - names. By default shows both unique and well-known names, but + names. By default, shows both unique and well-known names, but this may be changed with the <option>--unique</option> and <option>--acquired</option> switches. This is the default operation if no command is specified.</para></listitem> @@ -281,14 +281,14 @@ <replaceable>SERVICE</replaceable> is specified, show messages to or from this peer, identified by its well-known or unique name. Otherwise, show all messages on the bus. Use Ctrl-C to - terminate dump.</para></listitem> + terminate the dump.</para></listitem> </varlistentry> <varlistentry> <term><command>capture</command> <arg choice="opt" rep="repeat"><replaceable>SERVICE</replaceable></arg></term> <listitem><para>Similar to <command>monitor</command> but - writes the output in pcap format (for details see the <ulink + writes the output in pcap format (for details, see the <ulink url="http://wiki.wireshark.org/Development/LibpcapFileFormat">Libpcap File Format</ulink> description. Make sure to redirect the output to STDOUT to a file. Tools like @@ -312,7 +312,7 @@ <listitem><para>Show interfaces, methods, properties and signals of the specified object (identified by its path) on - the specified service. If the interface argument is passed the + the specified service. If the interface argument is passed, the output is limited to members of the specified interface.</para></listitem> </varlistentry> @@ -322,10 +322,10 @@ <listitem><para>Invoke a method and show the response. Takes a service name, object path, interface name and method name. If - parameters shall be passed to the method call a signature + parameters shall be passed to the method call, a signature string is required, followed by the arguments, individually formatted as strings. For details on the formatting used, see - below. To suppress output of the returned data use the + below. To suppress output of the returned data, use the <option>--quiet</option> option.</para></listitem> </varlistentry> @@ -335,16 +335,16 @@ <listitem><para>Retrieve the current value of one or more object properties. Takes a service name, object path, interface name and property name. Multiple properties may be - specified at once in which case their values will be shown one - after the other, separated by newlines. The output is by - default in terse format. Use <option>--verbose</option> for a + specified at once, in which case their values will be shown one + after the other, separated by newlines. The output is, by + default, in terse format. Use <option>--verbose</option> for a more elaborate output format.</para></listitem> </varlistentry> <varlistentry> <term><command>set-property</command> <arg choice="plain"><replaceable>SERVICE</replaceable></arg> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="plain"><replaceable>INTERFACE</replaceable></arg> <arg choice="plain"><replaceable>PROPERTY</replaceable></arg> <arg choice="plain"><replaceable>SIGNATURE</replaceable></arg> <arg choice="plain" rep="repeat"><replaceable>ARGUMENT</replaceable></arg></term> - <listitem><para>Set the current value an object + <listitem><para>Set the current value of an object property. Takes a service name, object path, interface name, property name, property signature, followed by a list of parameters formatted as strings.</para></listitem> @@ -364,19 +364,19 @@ <para>The <command>call</command> and <command>set-property</command> commands take a signature string followed by a list of parameters formatted as string (for details - on D-Bus signature strings see the <ulink + on D-Bus signature strings, see the <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#type-system">Type system chapter of the D-Bus specification</ulink>). For simple - types each parameter following the signature should simply be the + types, each parameter following the signature should simply be the parameter's value formatted as string. Positive boolean values may be formatted as <literal>true</literal>, <literal>yes</literal>, - <literal>on</literal>, <literal>1</literal>; negative boolean + <literal>on</literal>, or <literal>1</literal>; negative boolean values may be specified as <literal>false</literal>, - <literal>no</literal>, <literal>off</literal>, + <literal>no</literal>, <literal>off</literal>, or <literal>0</literal>. For arrays, a numeric argument for the number of entries followed by the entries shall be specified. For - variants the signature of the contents shall be specified, - followed by the contents. For dictionaries and structs the + variants, the signature of the contents shall be specified, + followed by the contents. For dictionaries and structs, the contents of them shall be directly specified.</para> <para>For example, @@ -395,7 +395,7 @@ array that maps strings to variants, consisting of three entries. The string <literal>One</literal> is assigned the string <literal>Eins</literal>. The string - <literal>Two</literal> is assigned the 32bit unsigned + <literal>Two</literal> is assigned the 32-bit unsigned integer 2. The string <literal>Yes</literal> is assigned a positive boolean.</para> @@ -456,8 +456,8 @@ ARRAY "s" { of the <literal>org.freedesktop.systemd1</literal> service, and passes it two strings <literal>cups.service</literal> and - <literal>replace</literal>. As result of the method - call a single object path parameter is received and + <literal>replace</literal>. As a result of the method + call, a single object path parameter is received and shown:</para> <programlisting># busctl call org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager StartUnit ss "cups.service" "replace" diff --git a/man/coredump.conf.xml b/man/coredump.conf.xml index 8e71f7d4ec..a0a497b467 100644 --- a/man/coredump.conf.xml +++ b/man/coredump.conf.xml @@ -98,7 +98,7 @@ <term><varname>Compress=</varname></term> <listitem><para>Controls compression for external - storage. Takes a boolean argument, defaults to + storage. Takes a boolean argument, which defaults to <literal>yes</literal>.</para> </listitem> </varlistentry> @@ -135,7 +135,7 @@ coredumps are processed. Note that old coredumps are also removed based on time via <citerefentry><refentrytitle>systemd-tmpfiles</refentrytitle><manvolnum>8</manvolnum></citerefentry>. Set - either value to 0 to turn off size based + either value to 0 to turn off size-based clean-up.</para></listitem> </varlistentry> </variablelist> diff --git a/man/crypttab.xml b/man/crypttab.xml index d4ff760adc..1de834a045 100644 --- a/man/crypttab.xml +++ b/man/crypttab.xml @@ -160,10 +160,10 @@ at the beginning. This is different from the <option>--offset</option> option with respect to the sector numbers used in initialization vector (IV) calculation. Using <option>--offset</option> will shift the IV - calculation by the same negative amount. Hence, if <option>--offset n</option>, + calculation by the same negative amount. Hence, if <option>--offset n</option> is given, sector n will get a sector number of 0 for the IV calculation. Using <option>--skip</option> causes sector n to also be the first - sector of the mapped device, but with its number for IV generation is n.</para> + sector of the mapped device, but with its number for IV generation being n.</para> <para>This option is only relevant for plain devices.</para> </listitem> diff --git a/man/custom-html.xsl b/man/custom-html.xsl index 3e266e4a7f..84c23014e4 100644 --- a/man/custom-html.xsl +++ b/man/custom-html.xsl @@ -125,7 +125,7 @@ <!-- - helper template to do conflict resolution between various headings with the same inferred ID attribute/tag from the headerlink template - - this conflict resolution is necessary to prevent malformed HTML output (multiple id attributes with the same value) + - this conflict resolution is necessary to prevent malformed HTML output (multiple ID attributes with the same value) - and it fixes xsltproc warnings during compilation of HTML man pages - - A simple top-to-bottom numbering scheme is implemented for nodes with the same ID value to derive unique ID values for HTML output. @@ -171,7 +171,7 @@ <!-- - If stable URLs with fragment markers (references to the ID) turn out not to be important: - generatedID could simply take the value of generate-id(), and various other helper templates may be dropped entirely. - - Alternatively if xsltproc is patched to generate reproducible generate-id() output the same simplifications can be + - Alternatively, if xsltproc is patched to generate reproducible generate-id() output, the same simplifications can be - applied at the cost of breaking compatibility with URLs generated from output of previous versions of this stylesheet. --> <xsl:variable name="generatedID"> diff --git a/man/daemon.xml b/man/daemon.xml index a8bbfc055b..b6125cb5c7 100644 --- a/man/daemon.xml +++ b/man/daemon.xml @@ -490,13 +490,13 @@ configured address redundant. Another often suggested trigger for service activation is low system load. However, here too, a more convincing approach might be to make proper use of features - of the operating system, in particular, the CPU or IO scheduler + of the operating system, in particular, the CPU or I/O scheduler of Linux. Instead of scheduling jobs from userspace based on monitoring the OS scheduler, it is advisable to leave the scheduling of processes to the OS scheduler itself. systemd - provides fine-grained access to the CPU and IO schedulers. If a + provides fine-grained access to the CPU and I/O schedulers. If a process executed by the init system shall not negatively impact - the amount of CPU or IO bandwidth available to other processes, + the amount of CPU or I/O bandwidth available to other processes, it should be configured with <varname>CPUSchedulingPolicy=idle</varname> and/or <varname>IOSchedulingClass=idle</varname>. Optionally, this may diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml index 058998b51f..345c56cefa 100644 --- a/man/file-hierarchy.xml +++ b/man/file-hierarchy.xml @@ -84,7 +84,7 @@ <varlistentry> <term><filename>/boot</filename></term> <listitem><para>The boot partition used for bringing up the - system. On EFI systems this is possibly the EFI System + system. On EFI systems, this is possibly the EFI System Partition, also see <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>. This directory is usually strictly local to the host, and @@ -147,14 +147,14 @@ directory is usually mounted as a <literal>tmpfs</literal> instance, and should hence not be used for larger files. (Use <filename>/var/tmp</filename> for larger files.) Since the - directory is accessible to other users of the system it is + directory is accessible to other users of the system, it is essential that this directory is only written to with the <citerefentry project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry> and related calls. This directory is usually flushed at boot-up. Also, files that are not accessed within a certain time are usually automatically deleted. If applications find - the environment variable <varname>$TMPDIR</varname> set they + the environment variable <varname>$TMPDIR</varname> set, they should prefer using the directory specified in it over directly referencing <filename>/tmp</filename> (see <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> @@ -217,7 +217,7 @@ <varlistentry> <term><filename>/usr/bin</filename></term> - <listitem><para>Binaries and executables for user commands, + <listitem><para>Binaries and executables for user commands that shall appear in the <varname>$PATH</varname> search path. It is recommended not to place binaries in this directory that are not useful for invocation from a shell (such as daemon @@ -245,7 +245,7 @@ <varlistentry> <term><filename>/usr/lib/<replaceable>arch-id</replaceable></filename></term> - <listitem><para>Location for placing dynamic libraries, also + <listitem><para>Location for placing dynamic libraries into, also called <varname>$libdir</varname>. The architecture identifier to use is defined on <ulink url="https://wiki.debian.org/Multiarch/Tuples">Multiarch @@ -291,7 +291,7 @@ <term><filename>/usr/share/factory/var</filename></term> <listitem><para>Similar to - <filename>/usr/share/factory/etc</filename> but for vendor + <filename>/usr/share/factory/etc</filename>, but for vendor versions of files in the variable, persistent data directory <filename>/var</filename>.</para></listitem> @@ -353,7 +353,7 @@ <varlistentry> <term><filename>/var/tmp</filename></term> <listitem><para>The place for larger and persistent temporary - files. In contrast to <filename>/tmp</filename> this directory + files. In contrast to <filename>/tmp</filename>, this directory is usually mounted from a persistent physical file system and can thus accept larger files. (Use <filename>/tmp</filename> for smaller files.) This directory is generally not flushed at @@ -365,7 +365,7 @@ <citerefentry project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry> or similar calls should be used to make use of this directory. If applications find the environment variable - <varname>$TMPDIR</varname> set they should prefer using the + <varname>$TMPDIR</varname> set, they should prefer using the directory specified in it over directly referencing <filename>/var/tmp</filename> (see <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> @@ -381,7 +381,7 @@ <variablelist> <varlistentry> <term><filename>/dev</filename></term> - <listitem><para>The root directory for device nodes. Usually + <listitem><para>The root directory for device nodes. Usually, this directory is mounted as a <literal>devtmpfs</literal> instance, but might be of a different type in sandboxed/containerized setups. This directory is managed @@ -402,10 +402,10 @@ write access to this directory, special care should be taken to avoid name clashes and vulnerabilities. For normal users, shared memory segments in this directory are usually deleted - when the user logs out. Usually it is a better idea to use + when the user logs out. Usually, it is a better idea to use memory mapped files in <filename>/run</filename> (for system programs) or <varname>$XDG_RUNTIME_DIR</varname> (for user - programs) instead of POSIX shared memory segments, since those + programs) instead of POSIX shared memory segments, since these directories are not world-writable and hence not vulnerable to security-sensitive name clashes.</para></listitem> </varlistentry> @@ -427,7 +427,7 @@ that exposes a number of kernel tunables. The primary way to configure the settings in this API file tree is via <citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> - files. In sandboxed/containerized setups this directory is + files. In sandboxed/containerized setups, this directory is generally mounted read-only.</para></listitem> </varlistentry> @@ -437,7 +437,7 @@ discovered devices and other functionality. This file system is mostly an API to interface with the kernel and not a place where normal files may be stored. In sandboxed/containerized - setups this directory is generally mounted read-only. A number + setups, this directory is generally mounted read-only. A number of special purpose virtual file systems might be mounted below this directory.</para></listitem> </varlistentry> @@ -472,7 +472,7 @@ <varlistentry> <term><filename>/lib64</filename></term> - <listitem><para>On some architecture ABIs this compatibility + <listitem><para>On some architecture ABIs, this compatibility symlink points to <varname>$libdir</varname>, ensuring that binaries referencing this legacy path correctly find their dynamic loader. This symlink only exists on architectures @@ -513,7 +513,7 @@ directory should have no effect on operation of programs, except for increased runtimes necessary to rebuild these caches. If an application finds - <varname>$XDG_CACHE_HOME</varname> set is should use the + <varname>$XDG_CACHE_HOME</varname> set, it should use the directory specified in it instead of this directory.</para></listitem> </varlistentry> @@ -522,10 +522,10 @@ <term><filename>~/.config</filename></term> <listitem><para>Application configuration and state. When a - new user is created this directory will be empty or not exist + new user is created, this directory will be empty or not exist at all. Applications should fall back to defaults should their configuration or state in this directory be missing. If an - application finds <varname>$XDG_CONFIG_HOME</varname> set is + application finds <varname>$XDG_CONFIG_HOME</varname> set, it should use the directory specified in it instead of this directory.</para></listitem> </varlistentry> @@ -539,7 +539,7 @@ invocation from a shell; these should be placed in a subdirectory of <filename>~/.local/lib</filename> instead. Care should be taken when placing architecture-dependent - binaries in this place which might be problematic if the home + binaries in this place, which might be problematic if the home directory is shared between multiple hosts with different architectures.</para></listitem> </varlistentry> @@ -555,7 +555,7 @@ <term><filename>~/.local/lib/<replaceable>arch-id</replaceable></filename></term> <listitem><para>Location for placing public dynamic libraries. - The architecture identifier to use, is defined on <ulink + The architecture identifier to use is defined on <ulink url="https://wiki.debian.org/Multiarch/Tuples">Multiarch Architecture Specifiers (Tuples)</ulink> list.</para></listitem> @@ -568,7 +568,7 @@ such as fonts or artwork. Usually, the precise location and format of files stored below this directory is subject to specifications that ensure interoperability. If an application - finds <varname>$XDG_DATA_HOME</varname> set is should use the + finds <varname>$XDG_DATA_HOME</varname> set, it should use the directory specified in it instead of this directory.</para></listitem> </varlistentry> @@ -593,11 +593,11 @@ <filename>/run/user</filename>) of the user, which are all writable.</para> - <para>For unprivileged system processes only + <para>For unprivileged system processes, only <filename>/tmp</filename>, <filename>/var/tmp</filename> and <filename>/dev/shm</filename> are writable. If an - unprivileged system process needs a private, writable directory in + unprivileged system process needs a private writable directory in <filename>/var</filename> or <filename>/run</filename>, it is recommended to either create it before dropping privileges in the daemon code, to create it via @@ -618,7 +618,7 @@ <para>It is strongly recommended that <filename>/dev</filename> is the only location below which device nodes shall be placed. - Similar, <filename>/run</filename> shall be the only location to + Similarly, <filename>/run</filename> shall be the only location to place sockets and FIFOs. Regular files, directories and symlinks may be used in all directories.</para> </refsect1> @@ -645,7 +645,7 @@ <tbody> <row> <entry><filename>/usr/bin</filename></entry> - <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path, compiled for any of the supported architectures compatible with the operating system. It is not recommended to place internal binaries or binaries that are not commonly invoked from the shell in this directory, such as daemon binaries. As this directory is shared with most other packages of the system special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry> + <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path, compiled for any of the supported architectures compatible with the operating system. It is not recommended to place internal binaries or binaries that are not commonly invoked from the shell in this directory, such as daemon binaries. As this directory is shared with most other packages of the system, special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry> </row> <row> <entry><filename>/usr/lib/<replaceable>arch-id</replaceable></filename></entry> @@ -653,7 +653,7 @@ </row> <row> <entry><filename>/usr/lib/<replaceable>package</replaceable></filename></entry> - <entry>Private, static vendor resources of the package, including private binaries and libraries, or any other kind of read-only vendor data.</entry> + <entry>Private static vendor resources of the package, including private binaries and libraries, or any other kind of read-only vendor data.</entry> </row> <row> <entry><filename>/usr/lib/<replaceable>arch-id</replaceable>/<replaceable>package</replaceable></filename></entry> @@ -668,10 +668,10 @@ </table> <para>Additional static vendor files may be installed in the - <filename>/usr/share</filename> hierarchy, to the locations + <filename>/usr/share</filename> hierarchy to the locations defined by the various relevant specifications.</para> - <para>During runtime and for local configuration and state + <para>During runtime, and for local configuration and state, additional directories are defined:</para> <table> @@ -700,7 +700,7 @@ </row> <row> <entry><filename>/var/cache/<replaceable>package</replaceable></filename></entry> - <entry>Persistent cache data of the package. If this directory is flushed the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry> + <entry>Persistent cache data of the package. If this directory is flushed, the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry> </row> <row> <entry><filename>/var/lib/<replaceable>package</replaceable></filename></entry> @@ -726,7 +726,7 @@ when placing their own files in the user's home directory. The following table lists recommended locations in the home directory for specific types of files supplied by the vendor if the - application is installed in the home directory. (Note however, + application is installed in the home directory. (Note, however, that user applications installed system-wide should follow the rules outlined above regarding placing vendor files.)</para> @@ -744,7 +744,7 @@ <tbody> <row> <entry><filename>~/.local/bin</filename></entry> - <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path. It is not recommended to place internal executables or executables that are not commonly invoked from the shell in this directory, such as daemon executables. As this directory is shared with most other packages of the user special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry> + <entry>Package executables that shall appear in the <varname>$PATH</varname> executable search path. It is not recommended to place internal executables or executables that are not commonly invoked from the shell in this directory, such as daemon executables. As this directory is shared with most other packages of the user, special care should be taken to pick unique names for files placed here, that are unlikely to clash with other package's files.</entry> </row> <row> <entry><filename>~/.local/lib/<replaceable>arch-id</replaceable></filename></entry> @@ -763,10 +763,10 @@ </table> <para>Additional static vendor files may be installed in the - <filename>~/.local/share</filename> hierarchy, to the locations + <filename>~/.local/share</filename> hierarchy to the locations defined by the various relevant specifications.</para> - <para>During runtime and for local configuration and state + <para>During runtime, and for local configuration and state, additional directories are defined:</para> <table> @@ -791,7 +791,7 @@ </row> <row> <entry><filename>~/.cache/<replaceable>package</replaceable></filename></entry> - <entry>Persistent cache data of the package. If this directory is flushed the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry> + <entry>Persistent cache data of the package. If this directory is flushed, the application should work correctly on next invocation, though possibly slowed down due to the need to rebuild any local cache files. The application must be capable of recreating this directory should it be missing and necessary.</entry> </row> </tbody> </tgroup> diff --git a/man/hwdb.xml b/man/hwdb.xml index 80939dd95d..2b1e60fb22 100644 --- a/man/hwdb.xml +++ b/man/hwdb.xml @@ -34,7 +34,7 @@ <refsect1><title>Description</title> <para>The hardware database is a key-value store for associating modalias-like keys to - udev-properties-like values. It is used primarily by udev to add the relevant properties + udev-property-like values. It is used primarily by udev to add the relevant properties to matching devices, but it can also be queried directly.</para> </refsect1> @@ -55,9 +55,9 @@ <para>The hwdb file contains data records consisting of matches and associated key-value pairs. Every record in the hwdb starts with one or - more match string, specifying a shell glob to compare the database + more match strings, specifying a shell glob to compare the database lookup string against. Multiple match lines are specified in additional - consecutive lines. Every match line is compared individually, they are + consecutive lines. Every match line is compared individually, and they are combined by OR. Every match line must start at the first character of the line.</para> @@ -71,7 +71,7 @@ and compiled to a binary database located at <filename>/etc/udev/hwdb.bin</filename>, or alternatively <filename>/usr/lib/udev/hwdb.bin</filename> if you want ship the compiled database in an immutable image. - During runtime only the binary database is used.</para> + During runtime, only the binary database is used.</para> </refsect1> <refsect1> diff --git a/man/journalctl.xml b/man/journalctl.xml index db3f166e65..b57afb6ebf 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -82,7 +82,7 @@ matches apply to the same field, then they are automatically matched as alternatives, i.e. the resulting output will show entries matching any of the specified matches for the same - field. Finally, the character <literal>+</literal> may appears + field. Finally, the character <literal>+</literal> may appear as a separate word between other terms on the command line. This causes all matches before and after to be combined in a disjunction (i.e. logical OR).</para> @@ -95,7 +95,7 @@ <literal>_KERNEL_DEVICE=</literal> match for the device.</para> <para>Additional constraints may be added using options - <option>--boot</option>, <option>--unit=</option>, etc, to + <option>--boot</option>, <option>--unit=</option>, etc., to further limit what entries will be shown (logical AND).</para> <para>Output is interleaved from all accessible journal files, @@ -181,7 +181,7 @@ <option>-n1000</option> to guarantee that the pager will not buffer logs of unbounded size. This may be overridden with an explicit <option>-n</option> with some other numeric - value while <option>-nall</option> will disable this cap. + value, while <option>-nall</option> will disable this cap. Note that this option is only supported for the <citerefentry project='man-pages'><refentrytitle>less</refentrytitle><manvolnum>1</manvolnum></citerefentry> pager.</para></listitem> @@ -368,7 +368,9 @@ <term><option>-q</option></term> <term><option>--quiet</option></term> - <listitem><para>Suppresses any warning messages regarding + <listitem><para>Suppresses all info messages + (i.e. "-- Logs begin at ...", "-- Reboot --"), + any warning messages regarding inaccessible system journals when run as a normal user.</para></listitem> </varlistentry> @@ -393,7 +395,7 @@ <para>If the boot ID is omitted, a positive <replaceable>offset</replaceable> will look up the boots - starting from the beginning of the journal, and a + starting from the beginning of the journal, and an equal-or-less-than zero <replaceable>offset</replaceable> will look up boots starting from the end of the journal. Thus, <constant>1</constant> means the first boot found in the @@ -411,7 +413,7 @@ <replaceable>offset</replaceable> which identifies the boot relative to the one given by boot <replaceable>ID</replaceable>. Negative values mean earlier - boots and a positive values mean later boots. If + boots and positive values mean later boots. If <replaceable>offset</replaceable> is not specified, a value of zero is assumed, and the logs for the boot given by <replaceable>ID</replaceable> are shown.</para> @@ -518,7 +520,7 @@ <listitem><para>Start showing entries from the location in the journal <emphasis>after</emphasis> the location specified by - the this cursor. The cursor is shown when the + the passed cursor. The cursor is shown when the <option>--show-cursor</option> option is used.</para> </listitem> </varlistentry> @@ -534,7 +536,9 @@ </varlistentry> <varlistentry> + <term><option>-S</option></term> <term><option>--since=</option></term> + <term><option>-U</option></term> <term><option>--until=</option></term> <listitem><para>Start showing entries on or newer than the @@ -552,7 +556,10 @@ respectively. <literal>now</literal> refers to the current time. Finally, relative times may be specified, prefixed with <literal>-</literal> or <literal>+</literal>, referring to - times before or after the current time, respectively.</para> + times before or after the current time, respectively. For complete + time and date specification, see + <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>. + </para> </listitem> </varlistentry> @@ -652,18 +659,18 @@ <listitem><para>Removes archived journal files until the disk space they use falls below the specified size (specified with the usual <literal>K</literal>, <literal>M</literal>, - <literal>G</literal>, <literal>T</literal> suffixes), or all + <literal>G</literal> and <literal>T</literal> suffixes), or all journal files contain no data older than the specified timespan (specified with the usual <literal>s</literal>, <literal>min</literal>, <literal>h</literal>, <literal>days</literal>, <literal>months</literal>, - <literal>weeks</literal>, <literal>years</literal> suffixes), + <literal>weeks</literal> and <literal>years</literal> suffixes), or no more than the specified number of separate journal files remain. Note that running <option>--vacuum-size=</option> has - only indirect effect on the output shown by - <option>--disk-usage</option> as the latter includes active - journal files, while the the vacuuming operation only operates - on archived journal files. Similar, + only an indirect effect on the output shown by + <option>--disk-usage</option>, as the latter includes active + journal files, while the vacuuming operation only operates + on archived journal files. Similarly, <option>--vacuum-files=</option> might not actually reduce the number of journal files to below the specified number, as it will not remove active journal @@ -766,21 +773,41 @@ </varlistentry> <varlistentry> + <term><option>--sync</option></term> + + <listitem><para>Asks the journal daemon to write all yet + unwritten journal data to the backing file system and + synchronize all journals. This call does not return until the + synchronization operation is complete. This command guarantees + that any log messages written before its invocation are safely + stored on disk at the time it returns.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>--flush</option></term> - <listitem><para>Asks the Journal daemon to flush any log data + <listitem><para>Asks the journal daemon to flush any log data stored in <filename>/run/log/journal</filename> into - <filename>/var/log/journal</filename>, if persistent storage is - enabled. This call does not return until the operation is - complete.</para></listitem> + <filename>/var/log/journal</filename>, if persistent storage + is enabled. This call does not return until the operation is + complete. Note that this call is idempotent: the data is only + flushed from <filename>/run/log/journal</filename> into + <filename>/var/log/journal</filename> once during system + runtime, and this command exits cleanly without executing any + operation if this has already has happened. This command + effectively guarantees that all data is flushed to + <filename>/var/log/journal</filename> at the time it + returns.</para></listitem> </varlistentry> <varlistentry> <term><option>--rotate</option></term> - <listitem><para>Asks the Journal daemon to rotate journal files. - </para></listitem> + <listitem><para>Asks the journal daemon to rotate journal + files. This call does not return until the rotation operation + is complete.</para></listitem> </varlistentry> + <xi:include href="standard-options.xml" xpointer="help" /> <xi:include href="standard-options.xml" xpointer="version" /> <xi:include href="standard-options.xml" xpointer="no-pager" /> @@ -850,7 +877,8 @@ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>coredumpctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry>, - <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> + <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> </para> </refsect1> </refentry> diff --git a/man/journald.conf.xml b/man/journald.conf.xml index 4464fe53ad..a9690e8138 100644 --- a/man/journald.conf.xml +++ b/man/journald.conf.xml @@ -203,7 +203,7 @@ <para><varname>SystemMaxUse=</varname> and <varname>RuntimeMaxUse=</varname> control how much disk space - the journal may use up at maximum. + the journal may use up at most. <varname>SystemKeepFree=</varname> and <varname>RuntimeKeepFree=</varname> control how much disk space systemd-journald shall leave free for other uses. @@ -220,12 +220,12 @@ enough free space before and journal files were created, and subsequently something else causes the file system to fill up, journald will stop using more space, but it will not be - removing existing files to reduce footprint again + removing existing files to reduce the footprint again, either.</para> <para><varname>SystemMaxFileSize=</varname> and <varname>RuntimeMaxFileSize=</varname> control how large - individual journal files may grow at maximum. This influences + individual journal files may grow at most. This influences the granularity in which disk space is made available through rotation, i.e. deletion of historic data. Defaults to one eighth of the values configured with @@ -234,17 +234,17 @@ rotated journal files are kept as history.</para> <para>Specify values in bytes or use K, M, G, T, P, E as - units for the specified sizes (equal to 1024, 1024²,... bytes). + units for the specified sizes (equal to 1024, 1024², ... bytes). Note that size limits are enforced synchronously when journal files are extended, and no explicit rotation step triggered by time is needed.</para> <para><varname>SystemMaxFiles=</varname> and <varname>RuntimeMaxFiles=</varname> control how many - individual journal files to keep at maximum. Note that only + individual journal files to keep at most. Note that only archived files are deleted to reduce the number of files until this limit is reached; active files will stay around. This - means that in effect there might still be more journal files + means that, in effect, there might still be more journal files around in total than this limit after a vacuuming operation is complete. This setting defaults to 100.</para></listitem> </varlistentry> @@ -345,7 +345,7 @@ <literal>notice</literal>, <literal>info</literal>, <literal>debug</literal>, - or integer values in the range of 0..7 (corresponding to the + or integer values in the range of 0–7 (corresponding to the same levels). Messages equal or below the log level specified are stored/forwarded, messages above are dropped. Defaults to <literal>debug</literal> for <varname>MaxLevelStore=</varname> @@ -375,15 +375,15 @@ <para> Journal events can be transferred to a different logging daemon - in two different ways. In the first method, messages are + in two different ways. With the first method, messages are immediately forwarded to a socket (<filename>/run/systemd/journal/syslog</filename>), where the traditional syslog daemon can read them. This method is - controlled by <varname>ForwardToSyslog=</varname> option. In a + controlled by the <varname>ForwardToSyslog=</varname> option. With a second method, a syslog daemon behaves like a normal journal client, and reads messages from the journal files, similarly to <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. - In this method, messages do not have to be read immediately, + With this, messages do not have to be read immediately, which allows a logging daemon which is only started late in boot to access all messages since the start of the system. In addition, full structured meta-data is available to it. This diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 2f81746b5e..309220632e 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -66,7 +66,7 @@ <para>For command line parameters understood by the initial RAM disk, please see - <citerefentry project='die-net'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>, or the documentation of the specific initrd implementation of your installation.</para> </refsect1> @@ -118,7 +118,7 @@ from the previous boot. For details, see <citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> and - <citerefentry><refentrytitle>systemd-rfkill@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. + <citerefentry><refentrytitle>systemd-rfkill.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. </para> </listitem> </varlistentry> @@ -351,7 +351,7 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>bootparam</refentrytitle><manvolnum>7</manvolnum></citerefentry>, - <citerefentry project='die-net'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>dracut.cmdline</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-debug-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-fsck@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-quotacheck.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, @@ -364,7 +364,7 @@ <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-modules-load.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-backlight@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-rfkill@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd-rfkill.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-hibernate-resume-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/libudev.xml b/man/libudev.xml index 5660b9d990..7ef978463c 100644 --- a/man/libudev.xml +++ b/man/libudev.xml @@ -75,7 +75,7 @@ a udev context. Furthermore, multiple different udev contexts can be used in parallel by multiple threads. However, a single context must not be accessed by multiple threads in parallel. The caller - is responsible of providing suitable locking if they intend to use + is responsible for providing suitable locking if they intend to use it from multiple threads.</para> <para>To introspect a local device on a system, a udev device @@ -99,11 +99,11 @@ <para>Furthermore, libudev also exports legacy APIs that should not be used by new software (and as such are not documented as - part of this manual). This includes the hardware-database known + part of this manual). This includes the hardware database known as <constant>udev_hwdb</constant> (please use the new <citerefentry><refentrytitle>sd-hwdb</refentrytitle><manvolnum>3</manvolnum></citerefentry> API instead) and the <constant>udev_queue</constant> object to - query the udev-daemon (which should not be used by new software + query the udev daemon (which should not be used by new software at all).</para> </refsect1> diff --git a/man/locale.conf.xml b/man/locale.conf.xml index 2c32d16094..2fe731113a 100644 --- a/man/locale.conf.xml +++ b/man/locale.conf.xml @@ -54,7 +54,7 @@ <title>Description</title> <para>The <filename>/etc/locale.conf</filename> file configures - system-wide locale settings. It is read at early-boot by + system-wide locale settings. It is read at early boot by <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para> <para>The basic file format of <filename>locale.conf</filename> is diff --git a/man/loginctl.xml b/man/loginctl.xml index 9dda14d454..f41acc6a1b 100644 --- a/man/loginctl.xml +++ b/man/loginctl.xml @@ -186,7 +186,7 @@ <listitem><para>Show terse runtime status information about one or more sessions, followed by the most recent log data from the journal. Takes one or more session identifiers as - parameters. If no session identifiers are passed the status of + parameters. If no session identifiers are passed, the status of the caller's session is shown. This function is intended to generate human-readable output. If you are looking for computer-parsable output, use <command>show-session</command> @@ -212,9 +212,9 @@ <term><command>activate</command> <optional><replaceable>ID</replaceable></optional></term> <listitem><para>Activate a session. This brings a session into - the foreground, if another session is currently in the + the foreground if another session is currently in the foreground on the respective seat. Takes a session identifier - as argument. If no argument is specified the session of the + as argument. If no argument is specified, the session of the caller is put into foreground.</para></listitem> </varlistentry> @@ -225,7 +225,7 @@ <listitem><para>Activates/deactivates the screen lock on one or more sessions, if the session supports it. Takes one or more session identifiers as arguments. If no argument is - specified the session of the caller is locked/unlocked. + specified, the session of the caller is locked/unlocked. </para></listitem> </varlistentry> @@ -269,7 +269,7 @@ <listitem><para>Show terse runtime status information about one or more logged in users, followed by the most recent log data from the journal. Takes one or more user names or numeric - user IDs as parameters. If no parameters are passed the status + user IDs as parameters. If no parameters are passed, the status of the caller's user is shown. This function is intended to generate human-readable output. If you are looking for computer-parsable output, use <command>show-user</command> @@ -301,7 +301,7 @@ spawned for the user at boot and kept around after logouts. This allows users who are not logged in to run long-running services. Takes one or more user names or numeric UIDs as - argument. If no argument is specified enables/disables + argument. If no argument is specified, enables/disables lingering for the user of the session of the caller. </para></listitem> </varlistentry> @@ -365,7 +365,7 @@ seat. The devices should be specified via device paths in the <filename>/sys</filename> file system. To create a new seat, attach at least one graphics card to a previously unused seat - name. Seat names may consist only of a-z, A-Z, 0-9, + name. Seat names may consist only of a–z, A–Z, 0–9, <literal>-</literal> and <literal>_</literal> and must be prefixed with <literal>seat</literal>. To drop assignment of a device to a specific seat, just reassign it to a different diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 2b79547275..43d1ffbd3c 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -255,8 +255,8 @@ <listitem><para>Specifies the timeout after system startup or system resume in which systemd will hold off on reacting to - LID events. This is required for the system to properly - detect any hotplugged devices so systemd can ignore LID events + lid events. This is required for the system to properly + detect any hotplugged devices so systemd can ignore lid events if external monitors, or docks, are connected. If set to 0, systemd will always react immediately, possibly before the kernel fully probed all hotplugged devices. This is safe, as diff --git a/man/machine-info.xml b/man/machine-info.xml index 916f1dab66..351133670b 100644 --- a/man/machine-info.xml +++ b/man/machine-info.xml @@ -124,7 +124,7 @@ <literal>tablet</literal>, <literal>handset</literal>, <literal>watch</literal>, and - <literal>embedded</literal> + <literal>embedded</literal>, as well as the special chassis types <literal>vm</literal> and <literal>container</literal> for diff --git a/man/machinectl.xml b/man/machinectl.xml index e2be017427..0e18953700 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -83,9 +83,9 @@ </itemizedlist> <para>Machines are identified by names that follow the same rules - as UNIX and DNS host names, for details see below. Machines are - instantiated from disk or file system images, that frequently but not - necessarily carry the same name as machines running from + as UNIX and DNS host names, for details, see below. Machines are + instantiated from disk or file system images that frequently — but not + necessarily — carry the same name as machines running from them. Images in this sense are considered:</para> <itemizedlist> @@ -201,7 +201,7 @@ <varlistentry> <term><option>--mkdir</option></term> - <listitem><para>When used with <command>bind</command> creates + <listitem><para>When used with <command>bind</command>, creates the destination directory before applying the bind mount.</para></listitem> </varlistentry> @@ -209,7 +209,7 @@ <varlistentry> <term><option>--read-only</option></term> - <listitem><para>When used with <command>bind</command> applies + <listitem><para>When used with <command>bind</command>, applies a read-only bind mount.</para></listitem> </varlistentry> @@ -243,9 +243,9 @@ specify whether the image shall be verified before it is made available. Takes one of <literal>no</literal>, <literal>checksum</literal> and <literal>signature</literal>. - If <literal>no</literal> no verification is done. If - <literal>checksum</literal> is specified the download is - checked for integrity after transfer is complete, but no + If <literal>no</literal>, no verification is done. If + <literal>checksum</literal> is specified, the download is + checked for integrity after the transfer is complete, but no signatures are verified. If <literal>signature</literal> is specified, the checksum is verified and the images's signature is checked against a local keyring of trustable vendors. It is @@ -278,10 +278,10 @@ <term><option>--format=</option></term> <listitem><para>When used with the <option>export-tar</option> - or <option>export-raw</option> commands specifies the + or <option>export-raw</option> commands, specifies the compression format to use for the resulting file. Takes one of <literal>uncompressed</literal>, <literal>xz</literal>, - <literal>gzip</literal>, <literal>bzip2</literal>. By default + <literal>gzip</literal>, <literal>bzip2</literal>. By default, the format is determined automatically from the image file name passed.</para></listitem> </varlistentry> @@ -317,7 +317,7 @@ <varlistentry> <term><command>status</command> <replaceable>NAME</replaceable>...</term> - <listitem><para>Show terse runtime status information about + <listitem><para>Show runtime status information about one or more virtual machines and containers, followed by the most recent log data from the journal. This function is intended to generate human-readable output. If you are looking @@ -339,7 +339,8 @@ are suppressed. Use <option>--all</option> to show those too. To select specific properties to show, use <option>--property=</option>. This command is intended to be - used whenever computer-parsable output is required. Use + used whenever computer-parsable output is required, and does + not print the cgroup tree or journal entries. Use <command>status</command> if you are looking for formatted human-readable output.</para></listitem> </varlistentry> @@ -356,7 +357,7 @@ image by the specified name in <filename>/var/lib/machines/</filename> (and other search paths, see below) and runs it. Use - <command>list-images</command> (see below), for listing + <command>list-images</command> (see below) for listing available container images to start.</para> <para>Note that @@ -381,7 +382,7 @@ <term><command>login</command> [<replaceable>NAME</replaceable>]</term> <listitem><para>Open an interactive terminal login session in - a container or on the local host. If an argument is supplied + a container or on the local host. If an argument is supplied, it refers to the container machine to connect to. If none is specified, or the container name is specified as the empty string, or the special machine name <literal>.host</literal> @@ -414,7 +415,7 @@ instead. This works similar to <command>login</command> but immediately invokes a user process. This command runs the specified executable with the specified arguments, or - <filename>/bin/sh</filename> if none is specified. By default + <filename>/bin/sh</filename> if none is specified. By default, opens a <literal>root</literal> shell, but by using <option>--uid=</option>, or by prefixing the machine name with a username and an <literal>@</literal> character, a different @@ -422,10 +423,10 @@ environment variables for the executed process.</para> <para>When using the <command>shell</command> command without - arguments (thus invoking the executed shell or command on the - local host) it is similar in many ways to a <citerefentry + arguments, (thus invoking the executed shell or command on the + local host), it is in many ways similar to a <citerefentry project='die-net'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry> - session, but unlike <command>su</command> completely isolates + session, but, unlike <command>su</command>, completely isolates the new session from the originating session, so that it shares no process or session properties, and is in a clean and well-defined state. It will be tracked in a new utmp, login, @@ -433,7 +434,7 @@ environment variables or resource limits, among other properties.</para> - <para>Note that the + <para>Note that <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry> may be used in place of the <command>shell</command> command, and allows more detailed, low-level configuration of the @@ -509,11 +510,11 @@ specified container. The first directory argument is the source directory on the host, the second directory argument is the destination directory in the container. When the - latter is omitted the destination path in the container is + latter is omitted, the destination path in the container is the same as the source path on the host. When combined with - the <option>--read-only</option> switch a ready-only bind + the <option>--read-only</option> switch, a ready-only bind mount is created. When combined with the - <option>--mkdir</option> switch the destination path is first + <option>--mkdir</option> switch, the destination path is first created before the mount is applied. Note that this option is currently only supported for <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> @@ -526,7 +527,7 @@ <listitem><para>Copies files or directories from the host system into a running container. Takes a container name, followed by the source path on the host and the destination - path in the container. If the destination path is omitted the + path in the container. If the destination path is omitted, the same as the source path is used.</para></listitem> </varlistentry> @@ -537,7 +538,7 @@ <listitem><para>Copies files or directories from a container into the host system. Takes a container name, followed by the source path in the container the destination path on the host. - If the destination path is omitted the same as the source path + If the destination path is omitted, the same as the source path is used.</para></listitem> </varlistentry> </variablelist></refsect2> @@ -552,8 +553,8 @@ directories and subvolumes in <filename>/var/lib/machines/</filename> (and other search paths, see below). Use <command>start</command> (see above) to - run a container off one of the listed images. Note that by - default containers whose name begins with a dot + run a container off one of the listed images. Note that, by + default, containers whose name begins with a dot (<literal>.</literal>) are not shown. To show these too, specify <option>--all</option>. Note that a special image <literal>.host</literal> always implicitly exists and refers @@ -626,27 +627,27 @@ <listitem><para>Removes one or more container or VM images. The special image <literal>.host</literal>, which refers to - the host's own directory tree may not be + the host's own directory tree, may not be removed.</para></listitem> </varlistentry> <varlistentry> <term><command>set-limit</command> [<replaceable>NAME</replaceable>] <replaceable>BYTES</replaceable></term> - <listitem><para>Sets the maximum size in bytes a specific - container or VM image, or all images may grow up to on disk + <listitem><para>Sets the maximum size in bytes that a specific + container or VM image, or all images, may grow up to on disk (disk quota). Takes either one or two parameters. The first, optional parameter refers to a container or VM image name. If - specified the size limit of the specified image is changed. If - omitted the overall size limit of the sum of all images stored + specified, the size limit of the specified image is changed. If + omitted, the overall size limit of the sum of all images stored locally is changed. The final argument specifies the size limit in bytes, possibly suffixed by the usual K, M, G, T units. If the size limit shall be disabled, specify <literal>-</literal> as size.</para> <para>Note that per-container size limits are only supported - on btrfs file systems. Also note that if - <command>set-limit</command> is invoked without image + on btrfs file systems. Also note that, if + <command>set-limit</command> is invoked without an image parameter, and <filename>/var/lib/machines</filename> is empty, and the directory is not located on btrfs, a btrfs loopback file is implicitly created as @@ -656,7 +657,7 @@ loopback may later be readjusted with <command>set-limit</command>, as well. If such a loopback-mounted <filename>/var/lib/machines</filename> - directory is used <command>set-limit</command> without image + directory is used, <command>set-limit</command> without an image name alters both the quota setting within the file system as well as the loopback file and file system size itself.</para></listitem> @@ -676,20 +677,20 @@ <literal>https://</literal>, and must refer to a <filename>.tar</filename>, <filename>.tar.gz</filename>, <filename>.tar.xz</filename> or <filename>.tar.bz2</filename> - archive file. If the local machine name is omitted it + archive file. If the local machine name is omitted, it is automatically derived from the last component of the URL, with its suffix removed.</para> <para>The image is verified before it is made available, unless <option>--verify=no</option> is specified. Verification - is done via SHA256SUMS and SHA256SUMS.gpg files, that need to + is done via SHA256SUMS and SHA256SUMS.gpg files that need to be made available on the same web server, under the same URL as the <filename>.tar</filename> file, but with the last component (the filename) of the URL replaced. With - <option>--verify=checksum</option> only the SHA256 checksum + <option>--verify=checksum</option>, only the SHA256 checksum for the file is verified, based on the <filename>SHA256SUMS</filename> file. With - <option>--verify=signature</option> the SHA256SUMS file is + <option>--verify=signature</option>, the SHA256SUMS file is first verified with detached GPG signature file <filename>SHA256SUMS.gpg</filename>. The public key for this verification step needs to be available in @@ -698,7 +699,7 @@ <para>The container image will be downloaded and stored in a read-only subvolume in - <filename>/var/lib/machines/</filename>, that is named after + <filename>/var/lib/machines/</filename> that is named after the specified URL and its HTTP etag. A writable snapshot is then taken from this subvolume, and named after the specified local name. This behavior ensures that creating multiple @@ -729,7 +730,7 @@ be a <filename>.qcow2</filename> or raw disk image, optionally compressed as <filename>.gz</filename>, <filename>.xz</filename>, or <filename>.bz2</filename>. If the - local machine name is omitted it is automatically + local machine name is omitted, it is automatically derived from the last component of the URL, with its suffix removed.</para> @@ -801,22 +802,22 @@ <listitem><para>Imports a TAR or RAW container or VM image, and places it under the specified name in <filename>/var/lib/machines/</filename>. When - <command>import-tar</command> is used the file specified as - first argument should be a tar archive, possibly compressed + <command>import-tar</command> is used, the file specified as + the first argument should be a tar archive, possibly compressed with xz, gzip or bzip2. It will then be unpacked into its own subvolume in <filename>/var/lib/machines</filename>. When - <command>import-raw</command> is used the file should be a + <command>import-raw</command> is used, the file should be a qcow2 or raw disk image, possibly compressed with xz, gzip or bzip2. If the second argument (the resulting image name) is - not specified it is automatically derived from the file - name. If the file name is passed as <literal>-</literal> the + not specified, it is automatically derived from the file + name. If the file name is passed as <literal>-</literal>, the image is read from standard input, in which case the second argument is mandatory.</para> <para>Similar as with <command>pull-tar</command>, <command>pull-raw</command> the file system <filename>/var/lib/machines.raw</filename> is increased in - size of necessary and appropriate. Optionally the + size of necessary and appropriate. Optionally, the <option>--read-only</option> switch may be used to create a read-only container or VM image. No cryptographic validation is done when importing the images.</para> @@ -833,11 +834,11 @@ stores it in the specified file. The first parameter should be a VM or container image name. The second parameter should be a file path the TAR or RAW image is written to. If the path ends - in <literal>.gz</literal> the file is compressed with gzip, if - it ends in <literal>.xz</literal> with xz, and if it ends in - <literal>.bz2</literal> with bzip2. If the path ends in - neither the file is left uncompressed. If the second argument - is missing the image is written to standard output. The + in <literal>.gz</literal>, the file is compressed with gzip, if + it ends in <literal>.xz</literal>, with xz, and if it ends in + <literal>.bz2</literal>, with bzip2. If the path ends in + neither, the file is left uncompressed. If the second argument + is missing, the image is written to standard output. The compression may also be explicitly selected with the <option>--format=</option> switch. This is in particular useful if the second parameter is left unspecified.</para> @@ -847,7 +848,7 @@ aborted with <command>cancel-transfer</command>.</para> - <para>Note that currently only directory and subvolume images + <para>Note that, currently, only directory and subvolume images may be exported as TAR images, and only raw disk images as RAW images.</para></listitem> </varlistentry> @@ -877,34 +878,34 @@ <title>Machine and Image Names</title> <para>The <command>machinectl</command> tool operates on machines - and images, whose names must be chosen following strict + and images whose names must be chosen following strict rules. Machine names must be suitable for use as host names following a conservative subset of DNS and UNIX/Linux semantics. Specifically, they must consist of one or more non-empty label strings, separated by dots. No leading or trailing dots are allowed. No sequences of multiple dots are allowed. The - label strings may only consists of alphanumeric characters as well + label strings may only consist of alphanumeric characters as well as the dash and underscore. The maximum length of a machine name is 64 characters.</para> <para>A special machine with the name <literal>.host</literal> refers to the running host system itself. This is useful for execution - operations or inspecting the host system as well. Not that + operations or inspecting the host system as well. Note that <command>machinectl list</command> will not show this special machine unless the <option>--all</option> switch is specified.</para> - <para>Requirements on image names are less strict, however must be + <para>Requirements on image names are less strict, however, they must be valid UTF-8, must be suitable as file names (hence not be the single or double dot, and not include a slash), and may not contain control characters. Since many operations search for an - image by the name of a requested machine it is recommended to name + image by the name of a requested machine, it is recommended to name images in the same strict fashion as machines.</para> <para>A special image with the name <literal>.host</literal> - refers to the image of the running host system. It is hence + refers to the image of the running host system. It hence conceptually maps to the special <literal>.host</literal> machine name described above. Note that <command>machinectl - list-images</command> won't show this special image either, unless + list-images</command> will not show this special image either, unless <option>--all</option> is specified.</para> </refsect1> @@ -914,7 +915,7 @@ <para>Machine images are preferably stored in <filename>/var/lib/machines/</filename>, but are also searched for in <filename>/usr/local/lib/machines/</filename> and - <filename>/usr/lib/machines/</filename>. For compatibility reasons + <filename>/usr/lib/machines/</filename>. For compatibility reasons, the directory <filename>/var/lib/container/</filename> is searched, too. Note that images stored below <filename>/usr</filename> are always considered read-only. It is @@ -943,7 +944,7 @@ <listitem><para>A simple directory tree, containing the files and directories of the container to boot.</para></listitem> - <listitem><para>A subvolume (on btrfs file systems), which are + <listitem><para>Subvolumes (on btrfs file systems), which are similar to the simple directories, described above. However, they have additional benefits, such as efficient cloning and quota reporting.</para></listitem> @@ -956,7 +957,7 @@ <para>See <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> - for more information on image formats, in particular it's + for more information on image formats, in particular its <option>--directory=</option> and <option>--image=</option> options.</para> </refsect1> @@ -987,7 +988,7 @@ # machinectl login Fedora-Cloud-Base-20141203-21</programlisting> <para>This downloads the specified <filename>.raw</filename> - image with verification disabled. Then a shell is opened in it + image with verification disabled. Then, a shell is opened in it and a root password is set. Afterwards the shell is left, and the machine started as system service. With the last command a login prompt into the container is requested.</para> @@ -1010,8 +1011,8 @@ <programlisting># machinectl export-tar fedora myfedora.tar.xz</programlisting> - <para>Exports the container <literal>fedora</literal> in an - xz-compress tar file <filename>myfedora.tar.xz</filename> in the + <para>Exports the container <literal>fedora</literal> as an + xz-compressed tar file <filename>myfedora.tar.xz</filename> into the current directory.</para> </example> @@ -1020,7 +1021,7 @@ <programlisting># machinectl shell --uid=lennart</programlisting> - <para>This creates a new shell session on the local host, for + <para>This creates a new shell session on the local host for the user ID <literal>lennart</literal>, in a <citerefentry project='die-net'><refentrytitle>su</refentrytitle><manvolnum>1</manvolnum></citerefentry>-like fashion.</para> diff --git a/man/networkctl.xml b/man/networkctl.xml index 46dab58d61..c688714b30 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -129,7 +129,7 @@ IDX LINK TYPE OPERATIONAL SETUP configured DNS servers, etc.</para> <para>When no links are specified, routable links are - shown. See also option <option>--all</option>.</para> + shown. Also see the option <option>--all</option>.</para> <para>Produces output similar to <programlisting> diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml index 4481fdf8cb..859bec29e3 100644 --- a/man/nss-myhostname.xml +++ b/man/nss-myhostname.xml @@ -59,7 +59,7 @@ <para><command>nss-myhostname</command> is a plugin for the GNU Name Service Switch (NSS) functionality of the GNU C Library - (<command>glibc</command>) primarily providing hostname resolution + (<command>glibc</command>), primarily providing hostname resolution for the locally configured system hostname as returned by <citerefentry><refentrytitle>gethostname</refentrytitle><manvolnum>2</manvolnum></citerefentry>. The precise hostnames resolved by this module are:</para> @@ -89,9 +89,9 @@ time as changing the hostname. This is problematic since it requires a writable <filename>/etc</filename> file system and is fragile because the file might be edited by the administrator at - the same time. With <command>nss-myhostname</command> enabled + the same time. With <command>nss-myhostname</command> enabled, changing <filename>/etc/hosts</filename> is unnecessary, and on - many systems the file becomes entirely optional.</para> + many systems, the file becomes entirely optional.</para> <para>To activate the NSS modules, <literal>myhostname</literal> has to be added to the line starting with @@ -100,7 +100,7 @@ <para>It is recommended to place <literal>myhostname</literal> last in the <filename>nsswitch.conf</filename> line to make sure - that this mapping is only used as fallback, and any DNS or + that this mapping is only used as fallback, and that any DNS or <filename>/etc/hosts</filename> based mapping takes precedence.</para> </refsect1> @@ -108,8 +108,8 @@ <refsect1> <title>Example</title> - <para>Here's an example <filename>/etc/nsswitch.conf</filename> - file, that enables <command>myhostname</command> correctly:</para> + <para>Here is an example <filename>/etc/nsswitch.conf</filename> + file that enables <command>myhostname</command> correctly:</para> <programlisting>passwd: compat mymachines group: compat mymachines @@ -135,7 +135,7 @@ netgroup: nis</programlisting> 127.0.0.2 DGRAM 127.0.0.2 RAW</programlisting> - <para>In this case the local hostname is <varname>omega</varname>.</para> + <para>In this case, the local hostname is <varname>omega</varname>.</para> </refsect1> diff --git a/man/nss-mymachines.xml b/man/nss-mymachines.xml index 92c72846c1..d2bec763bb 100644 --- a/man/nss-mymachines.xml +++ b/man/nss-mymachines.xml @@ -58,8 +58,8 @@ <para><command>nss-mymachines</command> is a plugin for the GNU Name Service Switch (NSS) functionality of the GNU C Library - (<command>glibc</command>) providing hostname resolution for - container names of containers running locally, that are registered + (<command>glibc</command>), providing hostname resolution for + container names of containers running locally that are registered with <citerefentry><refentrytitle>systemd-machined.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. The container names are resolved to the IP addresses of the @@ -76,16 +76,16 @@ <para>It is recommended to place <literal>mymachines</literal> near the end of the <filename>nsswitch.conf</filename> lines to - make sure that its mappings are only used as fallback, and any + make sure that its mappings are only used as fallback, and that any other mappings, such as DNS or <filename>/etc/hosts</filename> - based mappings take precedence.</para> + based mappings, take precedence.</para> </refsect1> <refsect1> <title>Example</title> - <para>Here's an example <filename>/etc/nsswitch.conf</filename> - file, that enables <command>mymachines</command> correctly:</para> + <para>Here is an example <filename>/etc/nsswitch.conf</filename> + file that enables <command>mymachines</command> correctly:</para> <programlisting>passwd: compat <command>mymachines</command> group: compat <command>mymachines</command> diff --git a/man/nss-resolve.xml b/man/nss-resolve.xml index 7d291b83c1..8b0928145f 100644 --- a/man/nss-resolve.xml +++ b/man/nss-resolve.xml @@ -79,8 +79,8 @@ <refsect1> <title>Example</title> - <para>Here's an example <filename>/etc/nsswitch.conf</filename> - file, that enables <command>resolve</command> correctly:</para> + <para>Here is an example <filename>/etc/nsswitch.conf</filename> + file that enables <command>resolve</command> correctly:</para> <programlisting>passwd: compat mymachines group: compat mymachines diff --git a/man/os-release.xml b/man/os-release.xml index d2e2598204..4557abc4a3 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -67,7 +67,7 @@ without implementing a shell compatible execution engine. Variable assignment values must be enclosed in double or single quotes if they include spaces, semicolons or other special characters - outside of A-Z, a-z, 0-9. Shell special characters ("$", quotes, + outside of A–Z, a–z, 0–9. Shell special characters ("$", quotes, backslash, backtick) must be escaped with backslashes, following shell style. All strings should be in UTF-8 format, and non-printable characters should not be used. It is not supported @@ -141,7 +141,7 @@ <term><varname>ID=</varname></term> <listitem><para>A lower-case string (no spaces or other - characters outside of 0-9, a-z, ".", "_" and "-") identifying + characters outside of 0–9, a–z, ".", "_" and "-") identifying the operating system, excluding any version information and suitable for processing by scripts or usage in generated filenames. If not set, defaults to @@ -179,7 +179,7 @@ <term><varname>VERSION_ID=</varname></term> <listitem><para>A lower-case string (mostly numeric, no spaces - or other characters outside of 0-9, a-z, ".", "_" and "-") + or other characters outside of 0–9, a–z, ".", "_" and "-") identifying the operating system version, excluding any OS name information or release code name, and suitable for processing by scripts or usage in generated filenames. This @@ -298,7 +298,7 @@ <listitem><para> A lower-case string (no spaces or other characters outside of - 0-9, a-z, ".", "_" and "-"), identifying a specific variant or + 0–9, a–z, ".", "_" and "-"), identifying a specific variant or edition of the operating system. This may be interpreted by other packages in order to determine a divergent default configuration. This field is optional and may not be diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml index b4a3f502b4..ddda81bc90 100644 --- a/man/pam_systemd.xml +++ b/man/pam_systemd.xml @@ -197,7 +197,7 @@ as <constant>AF_UNIX</constant> sockets, FIFOs, PID files and similar. It is guaranteed that this directory is local and offers the greatest possible file system feature set the - operating system provides. For further details see the <ulink + operating system provides. For further details, see the <ulink url="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG Base Directory Specification</ulink>.</para></listitem> </varlistentry> diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 8047a4ea75..811e33f4fa 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -59,7 +59,7 @@ <title>Description</title> <para>These configuration files control local DNS and LLMNR - name resolving.</para> + name resolution.</para> </refsect1> @@ -72,12 +72,12 @@ <varlistentry> <term><varname>DNS=</varname></term> - <listitem><para>A space separated list of IPv4 and IPv6 + <listitem><para>A space-separated list of IPv4 and IPv6 addresses to be used as system DNS servers. DNS requests are sent to one of the listed DNS servers in parallel to any per-interface DNS servers acquired from <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. - For compatibility reasons, if set to the empty list the DNS + For compatibility reasons, if set to the empty list, the DNS servers listed in <filename>/etc/resolv.conf</filename> are used, if any are configured there. This setting defaults to the empty list.</para></listitem> @@ -85,7 +85,7 @@ <varlistentry> <term><varname>FallbackDNS=</varname></term> - <listitem><para>A space separated list of IPv4 and IPv6 + <listitem><para>A space-separated list of IPv4 and IPv6 addresses to be used as the fallback DNS servers. Any per-interface DNS servers obtained from <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> @@ -103,9 +103,9 @@ <literal>resolve</literal>. Controls Link-Local Multicast Name Resolution support (<ulink url="https://tools.ietf.org/html/rfc4795">RFC 4794</ulink>) on - the local host. If true enables full LLMNR responder and - resolver support. If false disable both. If set to - <literal>resolve</literal> only resolving support is enabled, + the local host. If true, enables full LLMNR responder and + resolver support. If false, disables both. If set to + <literal>resolve</literal>, only resolution support is enabled, but responding is disabled. Note that <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> also maintains per-interface LLMNR settings. LLMNR will be diff --git a/man/runlevel.xml b/man/runlevel.xml index fc1f523855..ca29c7c22c 100644 --- a/man/runlevel.xml +++ b/man/runlevel.xml @@ -51,11 +51,62 @@ <refsynopsisdiv> <cmdsynopsis> - <command>runlevel <arg choice="opt" rep="repeat">options</arg></command> + <command>runlevel</command> + <arg choice="opt" rep="repeat">options</arg> </cmdsynopsis> </refsynopsisdiv> <refsect1> + <title>Overview</title> + + <para>"Runlevels" are an obsolete way to start and stop groups of + services used in SysV init. systemd provides a compatibility layer + that maps runlevels to targets, and associated binaries like + <command>runlevel</command>. Nevertheless, only one runlevel can + be "active" at a given time, while systemd can activate multiple + targets concurrently, so the mapping to runlevels is confusing + and only approximate. Runlevels should not be used in new code, + and are mostly useful as a shorthand way to refer the matching + systemd targets in kernel boot parameters.</para> + + <table> + <title>Mapping between runlevels and systemd targets</title> + <tgroup cols='2' align='left' colsep='1' rowsep='1'> + <colspec colname="runlevel" /> + <colspec colname="target" /> + <thead> + <row> + <entry>Runlevel</entry> + <entry>Target</entry> + </row> + </thead> + <tbody> + <row> + <entry>0</entry> + <entry><filename>poweroff.target</filename></entry> + </row> + <row> + <entry>1</entry> + <entry><filename>rescue.target</filename></entry> + </row> + <row> + <entry>2, 3, 4</entry> + <entry><filename>multi-user.target</filename></entry> + </row> + <row> + <entry>5</entry> + <entry><filename>graphical.target</filename></entry> + </row> + <row> + <entry>6</entry> + <entry><filename>reboot.target</filename></entry> + </row> + </tbody> + </tgroup> + </table> + </refsect1> + + <refsect1> <title>Description</title> <para><command>runlevel</command> prints the previous and current @@ -130,17 +181,10 @@ </refsect1> <refsect1> - <title>Notes</title> - - <para>This is a legacy command available for compatibility only. - It should not be used anymore, as the concept of runlevels is - obsolete.</para> - </refsect1> - - <refsect1> <title>See Also</title> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd-bus-errors.xml b/man/sd-bus-errors.xml index a1e8462858..055af7a682 100644 --- a/man/sd-bus-errors.xml +++ b/man/sd-bus-errors.xml @@ -121,10 +121,10 @@ <title>Description</title> <para>In addition to the error names user programs define, D-Bus - knows a number of generic, standardized error names, that are + knows a number of generic, standardized error names that are listed below.</para> - <para>In addition to this list, in sd-bus the special error + <para>In addition to this list, in sd-bus, the special error namespace <literal>System.Error.</literal> is used to map arbitrary Linux system errors (as defined by <citerefentry project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>) @@ -167,7 +167,7 @@ <varlistentry> <term><varname>SD_BUS_ERROR_IO_ERROR</varname></term> <listitem><para>Generic input/output error, for example when - accessing a socket or other IO context.</para></listitem> + accessing a socket or other I/O context.</para></listitem> </varlistentry> <varlistentry> <term><varname>SD_BUS_ERROR_BAD_ADDRESS</varname></term> @@ -186,7 +186,7 @@ </varlistentry> <varlistentry> <term><varname>SD_BUS_ERROR_ACCESS_DENIED</varname></term> - <listitem><para>Access to a resource has been denied, due to security restrictions.</para></listitem> + <listitem><para>Access to a resource has been denied due to security restrictions.</para></listitem> </varlistentry> <varlistentry> <term><varname>SD_BUS_ERROR_AUTH_FAILED</varname></term> @@ -224,7 +224,7 @@ </varlistentry> <varlistentry> <term><varname>SD_BUS_ERROR_FILE_EXISTS</varname></term> - <listitem><para>The requested file exists already.</para></listitem> + <listitem><para>The requested file already exists.</para></listitem> </varlistentry> <varlistentry> <term><varname>SD_BUS_ERROR_UNKNOWN_METHOD</varname></term> @@ -272,7 +272,7 @@ <varlistentry> <term><varname>SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED</varname></term> <listitem><para>Access to the requested operation is not - permitted, however, it might be available after interactive + permitted. However, it might be available after interactive authentication. This is usually returned by method calls supporting a framework for additional interactive authorization, when interactive authorization was not enabled diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml index 4162fab065..aec12bda16 100644 --- a/man/sd_bus_creds_get_pid.xml +++ b/man/sd_bus_creds_get_pid.xml @@ -317,7 +317,7 @@ to determine the mask of fields available.</para> <para><function>sd_bus_creds_get_pid()</function> will retrieve - the PID (process identifier). Similar, + the PID (process identifier). Similarly, <function>sd_bus_creds_get_ppid()</function> will retrieve the parent PID. Note that PID 1 has no parent process, in which case -ENXIO is returned.</para> @@ -326,14 +326,14 @@ TID (thread identifier).</para> <para><function>sd_bus_creds_get_uid()</function> will retrieve - the numeric UID (user identifier). Similar, + the numeric UID (user identifier). Similarly, <function>sd_bus_creds_get_euid()</function> returns the effective UID, <function>sd_bus_creds_get_suid()</function> the saved UID and <function>sd_bus_creds_get_fsuid()</function> the file system UID.</para> <para><function>sd_bus_creds_get_gid()</function> will retrieve the - numeric GID (group identifier). Similar, + numeric GID (group identifier). Similarly, <function>sd_bus_creds_get_egid()</function> returns the effective GID, <function>sd_bus_creds_get_sgid()</function> the saved GID and <function>sd_bus_creds_get_fsgid()</function> the file system @@ -355,7 +355,7 @@ <para><function>sd_bus_creds_get_exe()</function> will retrieve the path to the program executable (as stored in the <filename>/proc/<replaceable>pid</replaceable>/exe</filename> - link, but with <literal> (deleted)</literal> suffix removed). Note + link, but with the <literal> (deleted)</literal> suffix removed). Note that kernel threads do not have an executable path, in which case -ENXIO is returned.</para> @@ -372,38 +372,38 @@ <para><function>sd_bus_creds_get_unit()</function> will retrieve the systemd unit name (in the system instance of systemd) that the - process is part of. See + process is a part of. See <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For - processes that are not part of a unit returns -ENXIO. + processes that are not part of a unit, returns -ENXIO. </para> <para><function>sd_bus_creds_get_user_unit()</function> will retrieve the systemd unit name (in the user instance of systemd) - that the process is part of. See + that the process is a part of. See <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. For - processes that are not part of a user unit returns -ENXIO. + processes that are not part of a user unit, returns -ENXIO. </para> <para><function>sd_bus_creds_get_slice()</function> will retrieve the systemd slice (a unit in the system instance of systemd) that - the process is part of. See - <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Similar, + the process is a part of. See + <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Similarly, <function>sd_bus_creds_get_user_slice()</function> retrieves the systemd slice of the process, in the user instance of systemd. </para> <para><function>sd_bus_creds_get_session()</function> will retrieve the identifier of the login session that the process is - part of. See + a part of. See <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. For - processes that are not part of a session returns -ENXIO. + processes that are not part of a session, returns -ENXIO. </para> <para><function>sd_bus_creds_get_owner_uid()</function> will retrieve the numeric UID (user identifier) of the user who owns - the login session that the process is part of. See + the login session that the process is a part of. See <citerefentry><refentrytitle>systemd-logind.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. - For processes that are not part of a session returns -ENXIO. + For processes that are not part of a session, returns -ENXIO. </para> <para><function>sd_bus_creds_has_effective_cap()</function> will @@ -494,7 +494,7 @@ <varlistentry> <term><constant>-ENODATA</constant></term> - <listitem><para>Given field is not available in the + <listitem><para>The given field is not available in the credentials object <parameter>c</parameter>.</para> </listitem> </varlistentry> @@ -502,7 +502,7 @@ <varlistentry> <term><constant>-ENXIO</constant></term> - <listitem><para>Given field is not specified for the described + <listitem><para>The given field is not specified for the described process or peer. This will be returned by <function>sd_bus_get_unit()</function>, <function>sd_bus_get_slice()</function>, @@ -514,8 +514,8 @@ slice, or logind session. It will also be returned by <function>sd_bus_creds_get_exe()</function> and <function>sd_bus_creds_get_cmdline()</function> for kernel - threads (since these aren't started from an executable binary - or have a command line), + threads (since these are not started from an executable binary, + nor have a command line), and by <function>sd_bus_creds_get_audit_session_id()</function> and <function>sd_bus_creds_get_audit_login_uid()</function> when the process is not part of an audit session, and diff --git a/man/sd_bus_creds_new_from_pid.xml b/man/sd_bus_creds_new_from_pid.xml index a78d3f5717..84dd509744 100644 --- a/man/sd_bus_creds_new_from_pid.xml +++ b/man/sd_bus_creds_new_from_pid.xml @@ -130,7 +130,7 @@ <para><function>sd_bus_creds_new_from_pid()</function> creates a new credentials object and fills it with information about the process <parameter>pid</parameter>. The pointer to this object - will be stored in <parameter>ret</parameter> pointer. Note that + will be stored in the <parameter>ret</parameter> pointer. Note that credential objects may also be created and retrieved via <citerefentry><refentrytitle>sd_bus_get_name_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_get_owner_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry> @@ -171,11 +171,11 @@ <constant>SD_BUS_CREDS_AUDIT_LOGIN_UID</constant>, <constant>SD_BUS_CREDS_TTY</constant>, <constant>SD_BUS_CREDS_UNIQUE_NAME</constant>, - <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant>, + <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant>, and <constant>SD_BUS_CREDS_DESCRIPTION</constant>. Use the special value <constant>_SD_BUS_CREDS_ALL</constant> to request all supported fields. The <constant>SD_BUS_CREDS_AUGMENT</constant> - may not be ORed into the mask for invocations of + constant may not be ORed into the mask for invocations of <function>sd_bus_creds_new_from_pid()</function>.</para> <para>Fields can be retrieved from the credentials object using @@ -191,35 +191,35 @@ subset of fields requested in <parameter>creds_mask</parameter>. </para> - <para>Similar to <function>sd_bus_creds_get_mask()</function> the + <para>Similar to <function>sd_bus_creds_get_mask()</function>, the function <function>sd_bus_creds_get_augmented_mask()</function> returns a bitmask of field constants. The mask indicates which credential fields have been retrieved in a non-atomic fashion. For credential objects created via - <function>sd_bus_creds_new_from_pid()</function> this mask will be + <function>sd_bus_creds_new_from_pid()</function>, this mask will be identical to the mask returned by <function>sd_bus_creds_get_mask()</function>. However, for credential objects retrieved via - <function>sd_bus_get_name_creds()</function> this mask will be set + <function>sd_bus_get_name_creds()</function>, this mask will be set for the credential fields that could not be determined atomically at peer connection time, and which were later added by reading augmenting credential data from - <filename>/proc</filename>. Similar, for credential objects - retrieved via <function>sd_bus_get_owner_creds()</function> the + <filename>/proc</filename>. Similarly, for credential objects + retrieved via <function>sd_bus_get_owner_creds()</function>, the mask is set for the fields that could not be determined atomically - at bus creation time, but have been augmented. Similar, for + at bus creation time, but have been augmented. Similarly, for credential objects retrieved via - <function>sd_bus_message_get_creds()</function> the mask is set + <function>sd_bus_message_get_creds()</function>, the mask is set for the fields that could not be determined atomically at message - send time, but have been augmented. The mask returned by + sending time, but have been augmented. The mask returned by <function>sd_bus_creds_get_augmented_mask()</function> is always a subset of (or identical to) the mask returned by <function>sd_bus_creds_get_mask()</function> for the same object. The latter call hence returns all credential fields available in the credential object, the former then marks the subset of those that have been augmented. Note that augmented - fields are unsuitable for authorization decisions as they may be - retrieved at different times, thus being subject to races. Hence + fields are unsuitable for authorization decisions, as they may be + retrieved at different times, thus being subject to races. Hence, augmented fields should be used exclusively for informational purposes. </para> diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml index 1cf2cb8f9a..6d5a90de72 100644 --- a/man/sd_bus_default.xml +++ b/man/sd_bus_default.xml @@ -112,7 +112,7 @@ connection object to the user bus when invoked in user context, or to the system bus otherwise. The connection object is associated with the calling thread. Each time the function is invoked from - the same thread the same object is returned, but its reference + the same thread, the same object is returned, but its reference count is increased by one, as long as at least one reference is kept. When the last reference to the connection is dropped (using the @@ -120,8 +120,8 @@ call), the connection is terminated. Note that the connection is not automatically terminated when the associated thread ends. It is important to drop the last reference to the bus connection - explicitly before the thread ends or otherwise the connection will - be leaked. Also, queued but unread or unwritten messages keep the + explicitly before the thread ends, as otherwise, the connection will + leak. Also, queued but unread or unwritten messages keep the bus referenced, see below.</para> <para><function>sd_bus_default_user()</function> returns a user @@ -139,14 +139,14 @@ <function>sd_bus_open_system()</function> does the same, but connects to the system bus. In contrast to <function>sd_bus_default()</function>, - <function>sd_bus_default_user()</function>, - <function>sd_bus_default_system()</function> these calls return + <function>sd_bus_default_user()</function>, and + <function>sd_bus_default_system()</function>, these calls return new, independent connection objects that are not associated with the invoking thread and are not shared between multiple invocations. It is recommended to share connections per thread to efficiently make use the available resources. Thus, it is recommended to use <function>sd_bus_default()</function>, - <function>sd_bus_default_user()</function>, + <function>sd_bus_default_user()</function> and <function>sd_bus_default_system()</function> to connect to the user or system buses.</para> @@ -215,31 +215,31 @@ <para>Queued but unwritten/unread messages also keep a reference to their bus connection object. For this reason, even if an - application dropped all references to a bus connection it might - not get destroyed right-away. Until all incoming queued + application dropped all references to a bus connection, it might + not get destroyed right away. Until all incoming queued messages are read, and until all outgoing unwritten messages are written, the bus object will stay alive. <function>sd_bus_flush()</function> may be used to write all outgoing queued messages so they drop their references. To - flush the unread incoming messages use + flush the unread incoming messages, use <function>sd_bus_close()</function>, which will also close the bus - connection. When using the default bus logic it is a good idea to + connection. When using the default bus logic, it is a good idea to first invoke <function>sd_bus_flush()</function> followed by <function>sd_bus_close()</function> when a thread or process terminates, and thus its bus connection object should be freed.</para> - <para>The life-cycle of the default bus connection should be the + <para>The life cycle of the default bus connection should be the responsibility of the code that creates/owns the thread the default bus connection object is associated with. Library code should neither call <function>sd_bus_flush()</function> nor <function>sd_bus_close()</function> on default bus objects unless it does so in its own private, self-allocated thread. Library code should not use the default bus object in other threads unless it - is clear that the program using it will life-cycle the bus + is clear that the program using it will life cycle the bus connection object and flush and close it before exiting from the thread. In libraries where it is not clear that the calling - program will life-cycle the bus connection object it is hence + program will life cycle the bus connection object, it is hence recommended to use <function>sd_bus_open_system()</function> instead of <function>sd_bus_default_system()</function> and related calls.</para> diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml index 6dc4541eb1..c2d7ee389b 100644 --- a/man/sd_bus_error.xml +++ b/man/sd_bus_error.xml @@ -167,7 +167,7 @@ <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>, but additional domain-specific errors may be defined by applications. The <structfield>message</structfield> field usually - contains a human readable string describing the details, but might + contains a human-readable string describing the details, but might be NULL. An unset <structname>sd_bus_error</structname> structure should have both fields initialized to NULL. Set an error structure to <constant>SD_BUS_ERROR_NULL</constant> in order to @@ -189,20 +189,20 @@ for a list of well-known error names. Additional error mappings may be defined with <citerefentry><refentrytitle>sd_bus_error_add_map</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If - <parameter>e</parameter> is NULL no error structure is initialized + <parameter>e</parameter> is NULL, no error structure is initialized, but the error is still converted into an <varname>errno</varname>-style error. If <parameter>name</parameter> is <constant>NULL</constant>, it is assumed that no error occurred, and 0 is returned. This means that this function may be conveniently used in a <function>return</function> statement. If - <parameter>message</parameter> is NULL no message is set. This + <parameter>message</parameter> is NULL, no message is set. This call can fail if no memory may be allocated for the name and message strings, in which case an <constant>SD_BUS_ERROR_NO_MEMORY</constant> error might be set - instead and -ENOMEM returned. Do not use this call on error + instead and -ENOMEM be returned. Do not use this call on error structures that are already initialized. If you intend to reuse an - error structure free the old data stored in it with + error structure, free the old data stored in it with <function>sd_bus_error_free()</function> first.</para> <para><function>sd_bus_error_setf()</function> is similar to @@ -216,8 +216,8 @@ are not copied internally, and must hence remain constant and valid for the lifetime of <parameter>e</parameter>. Use this call to avoid memory allocations when setting error structures. Since - this call does not allocate memory it will not fail with an - out-of-memory condition, as + this call does not allocate memory, it will not fail with an + out-of-memory condition as <function>sd_bus_error_set()</function> can, as described above. Alternatively, the <constant>SD_BUS_ERROR_MAKE_CONST()</constant> macro may be used @@ -238,7 +238,7 @@ convenient usage in <function>return</function> statements. This call might fail due to lack of memory, in which case an <constant>SD_BUS_ERROR_NO_MEMORY</constant> error is set instead, - and -ENOMEM returned.</para> + and -ENOMEM is returned.</para> <para><function>sd_bus_error_set_errnof()</function> is similar to <function>sd_bus_error_set_errno()</function>, but in addition to @@ -249,7 +249,7 @@ <parameter>format</parameter> and the arguments.</para> <para><function>sd_bus_error_set_errnofv()</function> is similar to - <function>sd_bus_error_set_errnof()</function> but takes the + <function>sd_bus_error_set_errnof()</function>, but takes the format string parameters as <citerefentry project='man-pages'><refentrytitle>va_arg</refentrytitle><manvolnum>3</manvolnum></citerefentry> parameter list.</para> @@ -295,10 +295,10 @@ <title>Return Value</title> <para>The functions <function>sd_bus_error_set()</function>, - <function>sd_bus_error_setf()</function>, + <function>sd_bus_error_setf()</function>, and <function>sd_bus_error_set_const()</function>, when successful, return the negative errno value corresponding to the - <parameter>name</parameter> parameter. Functions + <parameter>name</parameter> parameter. The functions <function>sd_bus_error_set_errno()</function>, <function>sd_bus_error_set_errnof()</function> and <function>sd_bus_error_set_errnofv()</function>, when successful, @@ -331,7 +331,7 @@ <title>Reference ownership</title> <para><structname>sd_bus_error</structname> is not reference counted. Users should destroy resources held by it by calling - <function>sd_bus_error_free()</function>. Usually error structures + <function>sd_bus_error_free()</function>. Usually, error structures are allocated on the stack or passed in as function parameters, but they may also be allocated dynamically, in which case it is the duty of the caller to <citerefentry diff --git a/man/sd_bus_error_add_map.xml b/man/sd_bus_error_add_map.xml index 3fca63be4a..139bd77d8c 100644 --- a/man/sd_bus_error_add_map.xml +++ b/man/sd_bus_error_add_map.xml @@ -87,7 +87,7 @@ <citerefentry><refentrytitle>sd_bus_error_set</refentrytitle><manvolnum>3</manvolnum></citerefentry> or <citerefentry><refentrytitle>sd_bus_error_get_errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>. By - default a number of generic, standardized mappings are known, as + default, a number of generic, standardized mappings are known, as documented in <citerefentry><refentrytitle>sd-bus-errors</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Use this call to add further, application-specific mappings.</para> @@ -95,12 +95,12 @@ <para>The function takes a pointer to an array of <structname>sd_bus_error_map</structname> structures. A reference to the specified array is added to the lookup tables for error - mappings. Note that the structure is not copied, it is hence + mappings. Note that the structure is not copied, and that it is hence essential that the array stays available and constant during the entire remaining runtime of the process.</para> <para>The mapping array should be put together with a series of - <constant>SD_BUS_ERROR_MAP()</constant> macro invocations, that + <constant>SD_BUS_ERROR_MAP()</constant> macro invocations that take a literal name string and a (positive) <varname>errno</varname>-style error number. The last entry of the array should be an invocation of the diff --git a/man/sd_bus_message_append.xml b/man/sd_bus_message_append.xml index 0ee849dca7..77fce02eae 100644 --- a/man/sd_bus_message_append.xml +++ b/man/sd_bus_message_append.xml @@ -70,7 +70,7 @@ appends a sequence of fields to the D-Bus message object <parameter>m</parameter>. The type string <parameter>types</parameter> describes the types of the field - arguments that follow. For each type specified in the type string + arguments that follow. For each type specified in the type string, one or more arguments need to be specified, in the same order as declared in the type string.</para> diff --git a/man/sd_bus_message_append_array.xml b/man/sd_bus_message_append_array.xml index 37cadb9d0f..27db2a96c3 100644 --- a/man/sd_bus_message_append_array.xml +++ b/man/sd_bus_message_append_array.xml @@ -131,8 +131,8 @@ <parameter>type</parameter>. However, as a special exception, if the offset is specified as zero and the size specified as UINT64_MAX the full memory file descriptor contents is used. The - memory file descriptor is sealed by this call if it hasn't been - sealed yet, and cannot be modified a after this call. See + memory file descriptor is sealed by this call if it has not been + sealed yet, and cannot be modified after this call. See <citerefentry project='man-pages'><refentrytitle>memfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details about memory file descriptors. Appending arrays with @@ -142,7 +142,7 @@ process. Not all protocol transports support passing memory file descriptors between participants, in which case this call will automatically fall back to copying. Also, as memory file - descriptor passing is inefficient for smaller amounts of data + descriptor passing is inefficient for smaller amounts of data, copying might still be enforced even where memory file descriptor passing is supported.</para> @@ -150,13 +150,13 @@ function appends an array of a trivial type to the message <parameter>m</parameter>, similar to <function>sd_bus_message_append_array()</function>. Contents of - the IO vector array <parameter>iov</parameter> are used as the + the I/O vector array <parameter>iov</parameter> are used as the contents of the array. The total size of <parameter>iov</parameter> payload (the sum of <structfield>iov_len</structfield> fields) must be a multiple of the size of the type <parameter>type</parameter>. The <parameter>iov</parameter> argument must point to - <parameter>n</parameter> IO vector structures. Each structure may + <parameter>n</parameter> I/O vector structures. Each structure may have the <structname>iov_base</structname> field set, in which case the memory pointed to will be copied into the message, or unset (set to zero), in which case a block of zeros of length @@ -171,9 +171,9 @@ copying items to the message, it returns a pointer to the destination area to the caller in pointer <parameter>p</parameter>. The caller should subsequently write the - array contents to this memory. Modifications of the memory + array contents to this memory. Modifications to the memory pointed to should only occur until the next operation on the bus - message is invoked, most importantly the memory should not be + message is invoked. Most importantly, the memory should not be altered anymore when another field has been added to the message or the message has been sealed.</para> </refsect1> diff --git a/man/sd_bus_message_get_monotonic_usec.xml b/man/sd_bus_message_get_monotonic_usec.xml index 4c2c06e903..2c0a8a5d54 100644 --- a/man/sd_bus_message_get_monotonic_usec.xml +++ b/man/sd_bus_message_get_monotonic_usec.xml @@ -83,7 +83,7 @@ <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details.</para> - <para>Similar, + <para>Similarly, <function>sd_bus_message_get_realtime_usec()</function> returns the realtime (wallclock) timestamp of the time the message was sent. This value is in microseconds since Jan 1st, 1970, i.e. in diff --git a/man/sd_bus_negotiate_fds.xml b/man/sd_bus_negotiate_fds.xml index f53ea9e41a..a538b13cf0 100644 --- a/man/sd_bus_negotiate_fds.xml +++ b/man/sd_bus_negotiate_fds.xml @@ -108,7 +108,7 @@ <citerefentry><refentrytitle>sd_bus_message_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_message_get_seqnum</refentrytitle><manvolnum>3</manvolnum></citerefentry> to query the timestamps of incoming messages. If negotiation is - disabled or not supported these calls will fail with + disabled or not supported, these calls will fail with <constant>-ENODATA</constant>. Note that not all transports support timestamping of messages. Specifically, timestamping is only available on the kdbus transport, but not on dbus1. The @@ -118,7 +118,7 @@ <para><function>sd_bus_negotiate_creds()</function> controls whether and which implicit sender credentials shall be attached - automatically to all incoming messages. Takes a bus object, a + automatically to all incoming messages. Takes a bus object and a boolean indicating whether to enable or disable the credential parts encoded in the bit mask value argument. Note that not all transports support attaching sender credentials to messages, or do @@ -140,10 +140,10 @@ <citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Both <function>sd_bus_negotiate_timestamp()</function> and <function>sd_bus_negotiate_creds()</function> may also be called - after a connection has been set up. Note that when operating on a + after a connection has been set up. Note that, when operating on a connection that is shared between multiple components of the same program (for example via - <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>) + <citerefentry><refentrytitle>sd_bus_default</refentrytitle><manvolnum>3</manvolnum></citerefentry>), it is highly recommended to only enable additional per message metadata fields, but never disable them again, in order not to disable functionality needed by other components.</para> diff --git a/man/sd_bus_new.xml b/man/sd_bus_new.xml index aff2ed2e83..e1cab6e567 100644 --- a/man/sd_bus_new.xml +++ b/man/sd_bus_new.xml @@ -84,7 +84,7 @@ or a related call, and then start the connection with <citerefentry><refentrytitle>sd_bus_start</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> - <para>In most cases it's a better idea to invoke + <para>In most cases, it is a better idea to invoke <citerefentry><refentrytitle>sd_bus_default_user</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_bus_default_system</refentrytitle><manvolnum>3</manvolnum></citerefentry> or related calls instead of the more low-level diff --git a/man/sd_bus_path_encode.xml b/man/sd_bus_path_encode.xml index 696dfd00ba..3088243e45 100644 --- a/man/sd_bus_path_encode.xml +++ b/man/sd_bus_path_encode.xml @@ -128,23 +128,23 @@ <para><function>sd_bus_path_encode_many()</function> works like its counterpart <function>sd_bus_path_encode()</function>, but - takes a path-template as argument and encodes multiple labels + takes a path template as argument and encodes multiple labels according to its embedded directives. For each <literal>%</literal> character found in the template, the caller - must provide a string via var-args, which will be encoded and + must provide a string via varargs, which will be encoded and embedded at the position of the <literal>%</literal> character. Any other character in the template is copied verbatim into the encoded path.</para> <para><function>sd_bus_path_decode_many()</function> does the reverse of <function>sd_bus_path_encode_many()</function>. It - decodes the passed object path, according to the given - path-template. For each <literal>%</literal> character in the + decodes the passed object path according to the given + path template. For each <literal>%</literal> character in the template, the caller must provide an output storage - (<literal>char **</literal>) via var-args. The decoded label + (<literal>char **</literal>) via varargs. The decoded label will be stored there. Each <literal>%</literal> character will only match the current label. It will never match across labels. - Furthermore, only a single such directive is allowed per label. + Furthermore, only a single directive is allowed per label. If <literal>NULL</literal> is passed as output storage, the label is verified but not returned to the caller.</para> </refsect1> diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml index b62d1ee5e1..77bec4e706 100644 --- a/man/sd_event_add_child.xml +++ b/man/sd_event_add_child.xml @@ -157,7 +157,7 @@ <varlistentry> <term><constant>-EBUSY</constant></term> - <listitem><para>An handler is already installed for this + <listitem><para>A handler is already installed for this child.</para></listitem> </varlistentry> diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml index 01504bf01e..826f2fd224 100644 --- a/man/sd_event_add_defer.xml +++ b/man/sd_event_add_defer.xml @@ -90,7 +90,7 @@ <refsect1> <title>Description</title> - <para>Those three functions add new event sources to an event loop + <para>These three functions add new event sources to an event loop object. The event loop is specified in <parameter>event</parameter>, the event source is returned in the <parameter>source</parameter> parameter. The event sources are diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml index 1d0942b45c..0923fe0ae7 100644 --- a/man/sd_event_add_signal.xml +++ b/man/sd_event_add_signal.xml @@ -82,7 +82,7 @@ <para><function>sd_event_add_signal()</function> adds a new signal event source to an event loop object. The event loop is specified - in <parameter>event</parameter>, the event source is returned in + in <parameter>event</parameter>, and the event source is returned in the <parameter>source</parameter> parameter. The <parameter>signal</parameter> parameter specifies the signal to be handled (see @@ -149,7 +149,7 @@ <varlistentry> <term><constant>-EBUSY</constant></term> - <listitem><para>An handler is already installed for this + <listitem><para>A handler is already installed for this signal or the signal was not blocked previously.</para></listitem> </varlistentry> diff --git a/man/sd_event_new.xml b/man/sd_event_new.xml index e5a440556e..f6c5d39814 100644 --- a/man/sd_event_new.xml +++ b/man/sd_event_new.xml @@ -114,7 +114,7 @@ <function>sd_event_default()</function>, then releasing it, and then acquiring a new one with <function>sd_event_default()</function> will result in two - distinct objects. Note that in order to free an event loop object, + distinct objects. Note that, in order to free an event loop object, all remaining event sources of the event loop also need to be freed as each keeps a reference to it.</para> </refsect1> diff --git a/man/sd_event_run.xml b/man/sd_event_run.xml index 2eab5684c5..06236fcd1a 100644 --- a/man/sd_event_run.xml +++ b/man/sd_event_run.xml @@ -46,7 +46,7 @@ <refname>sd_event_run</refname> <refname>sd_event_loop</refname> - <refpurpose>Run libsystemd event loop</refpurpose> + <refpurpose>Run the libsystemd event loop</refpurpose> </refnamediv> <refsynopsisdiv> @@ -71,8 +71,8 @@ <para><function>sd_event_run()</function> can be used to run one iteration of the event loop of libsystemd. This function waits - until an event to process is available and dispatches a handler - for it. Parameter <parameter>timeout</parameter> specifices the + until an event to process is available, and dispatches a handler + for it. The <parameter>timeout</parameter> parameter specifices the maximum time (in microseconds) to wait. <constant>(uint64_t) -1</constant> may be used to specify an infinite timeout.</para> @@ -121,7 +121,7 @@ <varlistentry> <term><constant>-EINVAL</constant></term> - <listitem><para>Parameter <parameter>event</parameter> is + <listitem><para>The <parameter>event</parameter> parameter is <constant>NULL</constant>.</para></listitem> </varlistentry> @@ -150,7 +150,7 @@ </variablelist> - <para>Other errors are possible too.</para> + <para>Other errors are possible, too.</para> </refsect1> <refsect1> @@ -176,7 +176,7 @@ <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <ulink url="https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html">GLIb Main Event Loop</ulink>. + <ulink url="https://developer.gnome.org/glib/unstable/glib-The-Main-Event-Loop.html">GLib Main Event Loop</ulink>. </para> </refsect1> diff --git a/man/sd_event_set_name.xml b/man/sd_event_set_name.xml index 72aef897c7..1471e12e59 100644 --- a/man/sd_event_set_name.xml +++ b/man/sd_event_set_name.xml @@ -77,7 +77,7 @@ <parameter>source</parameter>. This name will be used in error messages generated by <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry> - for this source. Specified <parameter>name</parameter> must point + for this source. The <parameter>name</parameter> must point to a <constant>NUL</constant>-terminated string or be <constant>NULL</constant>. In the latter case, the name will be unset. The string is copied internally, so the @@ -128,7 +128,7 @@ <refsect1> <title>Notes</title> - <para>Functions described here are available as a + <para>The functions described here are available as a shared library, which can be compiled and linked to with the <constant>libsystemd</constant> <citerefentry project='die-net'><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml index 397d52a3e4..7ca50aedf9 100644 --- a/man/sd_event_wait.xml +++ b/man/sd_event_wait.xml @@ -47,7 +47,7 @@ <refname>sd_event_prepare</refname> <refname>sd_event_dispatch</refname> - <refpurpose>Run parts of libsystemd event loop</refpurpose> + <refpurpose>Run parts of the libsystemd event loop</refpurpose> </refnamediv> <refsynopsisdiv> @@ -123,8 +123,8 @@ └──────────┘ </programlisting> - <para>All three functions as the first argument take the event - loop object <parameter>event</parameter> that is created with with + <para>All three functions take, as the first argument, the event + loop object <parameter>event</parameter> that is created with <function>sd_event_new</function>. The timeout for <function>sd_event_wait</function> is specified with <parameter>timeout</parameter> in milliseconds. @@ -138,11 +138,11 @@ <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style error code. In case of <function>sd_event_prepare</function> and - <function>sd_event_wait</function> a positive value means that + <function>sd_event_wait</function>, a positive value means that events are ready to be processed and 0 means that no events are - ready. In case of <function>sd_event_dispatch</function> a + ready. In case of <function>sd_event_dispatch</function>, a positive value means that the loop is again in the initial state - and 0 means the loop is finished. For any of those functions, a + and 0 means the loop is finished. For any of these functions, a negative return value means the loop must be aborted.</para> </refsect1> @@ -155,7 +155,7 @@ <varlistentry> <term><constant>-EINVAL</constant></term> - <listitem><para>Parameter <parameter>event</parameter> is + <listitem><para>The <parameter>event</parameter> parameter is <constant>NULL</constant>.</para></listitem> </varlistentry> @@ -182,7 +182,7 @@ </variablelist> - <para>Other errors are possible too.</para> + <para>Other errors are possible, too.</para> </refsect1> <refsect1> diff --git a/man/sd_get_seats.xml b/man/sd_get_seats.xml index f1981f7ea2..37eb3fc894 100644 --- a/man/sd_get_seats.xml +++ b/man/sd_get_seats.xml @@ -127,7 +127,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>An input parameter was invalid (out of range, - or NULL, where that's not accepted).</para></listitem> + or NULL, where that is not accepted).</para></listitem> </varlistentry> <varlistentry> diff --git a/man/sd_journal_add_match.xml b/man/sd_journal_add_match.xml index 420f56356a..3b27444f8d 100644 --- a/man/sd_journal_add_match.xml +++ b/man/sd_journal_add_match.xml @@ -89,7 +89,7 @@ and <citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Matches are of the form <literal>FIELD=value</literal>, where the - field part is a short uppercase string consisting only of 0-9, A-Z + field part is a short uppercase string consisting only of 0–9, A–Z and the underscore. It may not begin with two underscores or be the empty string. The value part may be any value, including binary. If a match is applied, only entries with this field set diff --git a/man/sd_journal_get_data.xml b/man/sd_journal_get_data.xml index 1afbd7371c..1f25d068d7 100644 --- a/man/sd_journal_get_data.xml +++ b/man/sd_journal_get_data.xml @@ -113,7 +113,7 @@ <function>sd_journal_get_data()</function> or <function>sd_journal_enumerate_data()</function>, or the read pointer is altered. Note that the data returned will be prefixed - with the field name and '='. Also note that by default data fields + with the field name and '='. Also note that, by default, data fields larger than 64K might get truncated to 64K. This threshold may be changed and turned off with <function>sd_journal_set_data_threshold()</function> (see diff --git a/man/sd_journal_get_fd.xml b/man/sd_journal_get_fd.xml index 3a38f733ab..61293f7f99 100644 --- a/man/sd_journal_get_fd.xml +++ b/man/sd_journal_get_fd.xml @@ -187,7 +187,7 @@ else { certain latency. This call will return a positive value if the journal changes are detected immediately and zero when they need to be polled for and hence might be noticed only with a certain - latency. Note that there's usually no need to invoke this function + latency. Note that there is usually no need to invoke this function directly as <function>sd_journal_get_timeout()</function> on these file systems will ask for timeouts explicitly anyway.</para> </refsect1> diff --git a/man/sd_journal_open.xml b/man/sd_journal_open.xml index fb572802a3..fef453f8dc 100644 --- a/man/sd_journal_open.xml +++ b/man/sd_journal_open.xml @@ -100,8 +100,8 @@ <para><function>sd_journal_open()</function> opens the log journal for reading. It will find all journal files automatically and interleave them automatically when reading. As first argument it - takes a pointer to a <varname>sd_journal</varname> pointer, which - on success will contain a journal context object. The second + takes a pointer to a <varname>sd_journal</varname> pointer, which, + on success, will contain a journal context object. The second argument is a flags field, which may consist of the following flags ORed together: <constant>SD_JOURNAL_LOCAL_ONLY</constant> makes sure only journal files generated on the local machine will diff --git a/man/sd_journal_print.xml b/man/sd_journal_print.xml index 0cd0b45b9a..17fdc9c1f2 100644 --- a/man/sd_journal_print.xml +++ b/man/sd_journal_print.xml @@ -134,8 +134,8 @@ be ignored.) The value can be of any size and format. It is highly recommended to submit text strings formatted in the UTF-8 character encoding only, and submit binary fields only when - formatting in UTF-8 strings is not sensible. A number of well - known fields are defined, see + formatting in UTF-8 strings is not sensible. A number of + well-known fields are defined, see <citerefentry><refentrytitle>systemd.journal-fields</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details, but additional application defined fields may be used. A variable may be assigned more than one value per @@ -156,7 +156,7 @@ <para><function>sd_journal_perror()</function> is a similar to <citerefentry project='die-net'><refentrytitle>perror</refentrytitle><manvolnum>3</manvolnum></citerefentry> and writes a message to the journal that consists of the passed - string, suffixed with ": " and a human readable representation of + string, suffixed with ": " and a human-readable representation of the current error code stored in <citerefentry project='man-pages'><refentrytitle>errno</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If the message string is passed as <constant>NULL</constant> or diff --git a/man/sd_listen_fds.xml b/man/sd_listen_fds.xml index ccd1266318..93bf8d853f 100644 --- a/man/sd_listen_fds.xml +++ b/man/sd_listen_fds.xml @@ -76,7 +76,7 @@ daemon to check for file descriptors passed by the service manager as part of the socket-based activation logic. It returns the number of received file descriptors. If no file descriptors have been - received zero is returned. The first file descriptor may be found + received, zero is returned. The first file descriptor may be found at file descriptor number 3 (i.e. <constant>SD_LISTEN_FDS_START</constant>), the remaining descriptors follow at 4, 5, 6, ..., if any.</para> @@ -104,7 +104,7 @@ passed file descriptors to avoid further inheritance to children of the calling process.</para> - <para>If multiple socket units activate the same service the order + <para>If multiple socket units activate the same service, the order of the file descriptors passed to its main process is undefined. If additional file descriptors have been passed to the service manager using @@ -123,9 +123,9 @@ variables are no longer inherited by child processes.</para> <para><function>sd_listen_fds_with_names()</function> is like - <function>sd_listen_fds()</function> but optionally also returns + <function>sd_listen_fds()</function>, but optionally also returns an array of strings with identification names for the passed file - descriptors, if that is available, and the + descriptors, if that is available and the <parameter>names</parameter> parameter is non-NULL. This information is read from the <varname>$LISTEN_FDNAMES</varname> variable, which may contain a colon-separated list of names. For @@ -134,7 +134,7 @@ files, see <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. For file descriptors pushed into the file descriptor - store (see above) the name is set via the + store (see above), the name is set via the <varname>FDNAME=</varname> field transmitted via <function>sd_pid_notify_with_fds()</function>. The primary usecase for these names are services which accept a variety of file @@ -145,14 +145,14 @@ <function>sd_is_socket()</function> and related calls is not sufficient. Note that the names used are not unique in any way. The returned array of strings has as many entries as file - descriptors has been received, plus a final NULL pointer + descriptors have been received, plus a final NULL pointer terminating the array. The caller needs to free the array itself and each of its elements with libc's <function>free()</function> call after use. If the <parameter>names</parameter> parameter is - NULL the call is entirely equivalent to + NULL, the call is entirely equivalent to <function>sd_listen_fds()</function>.</para> - <para>Under specific conditions the following automatic file + <para>Under specific conditions, the following automatic file descriptor names are returned: <table> diff --git a/man/sd_login_monitor_new.xml b/man/sd_login_monitor_new.xml index a8854dd590..db21d70252 100644 --- a/man/sd_login_monitor_new.xml +++ b/man/sd_login_monitor_new.xml @@ -214,7 +214,7 @@ else { <term><constant>-EINVAL</constant></term> <listitem><para>An input parameter was invalid (out of range, - or NULL, where that's not accepted). The specified category to + or NULL, where that is not accepted). The specified category to watch is not known.</para></listitem> </varlistentry> diff --git a/man/sd_machine_get_class.xml b/man/sd_machine_get_class.xml index 9ad7f3fc66..ef604139da 100644 --- a/man/sd_machine_get_class.xml +++ b/man/sd_machine_get_class.xml @@ -116,7 +116,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>An input parameter was invalid (out of range, - or NULL, where that's not accepted).</para></listitem> + or NULL, where that is not accepted).</para></listitem> </varlistentry> <varlistentry> diff --git a/man/sd_notify.xml b/man/sd_notify.xml index 2d73c27f62..dbf6330453 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -100,7 +100,7 @@ <para><function>sd_notify()</function> may be called by a service to notify the service manager about state changes. It can be used to send arbitrary information, encoded in an - environment-block-like string. Most importantly it can be used for + environment-block-like string. Most importantly, it can be used for start-up completion notification.</para> <para>If the <parameter>unset_environment</parameter> parameter is @@ -158,7 +158,7 @@ to the service manager that describes the service state. This is free-form and can be used for various purposes: general state feedback, fsck-like programs could pass completion - percentages and failing programs could pass a human readable + percentages and failing programs could pass a human-readable error message. Example: <literal>STATUS=Completed 66% of file system check...</literal></para></listitem> </varlistentry> @@ -233,21 +233,21 @@ <term>FDNAME=...</term> <listitem><para>When used in combination with - <varname>FDSTORE=1</varname> specifies a name for the + <varname>FDSTORE=1</varname>, specifies a name for the submitted file descriptors. This name is passed to the service during activation, and may be queried using <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>. File descriptors submitted without this field set, will implicitly - get the name <literal>stored</literal> assigned. Note that if - multiple file descriptors are submitted at once the specified + get the name <literal>stored</literal> assigned. Note that, if + multiple file descriptors are submitted at once, the specified name will be assigned to all of them. In order to assign different names to submitted file descriptors, submit them in seperate invocations of <function>sd_pid_notify_with_fds()</function>. The name may - consist of any ASCII characters, but must not contain control + consist of any ASCII character, but must not contain control characters or <literal>:</literal>. It may not be longer than 255 characters. If a submitted name does not follow these - restrictions it is ignored.</para></listitem> + restrictions, it is ignored.</para></listitem> </varlistentry> </variablelist> @@ -274,7 +274,7 @@ use as originating PID for the message as first argument. This is useful to send notification messages on behalf of other processes, provided the appropriate privileges are available. If the PID - argument is specified as 0 the process ID of the calling process + argument is specified as 0, the process ID of the calling process is used, in which case the calls are fully equivalent to <function>sd_notify()</function> and <function>sd_notifyf()</function>.</para> @@ -311,7 +311,7 @@ <xi:include href="libsystemd-pkgconfig.xml" xpointer="pkgconfig-text"/> - <para>Internally, these functions send a single datagram with the + <para>These functions send a single datagram with the state string as payload to the <constant>AF_UNIX</constant> socket referenced in the <varname>$NOTIFY_SOCKET</varname> environment variable. If the first character of @@ -377,7 +377,7 @@ <para>To store an open file descriptor in the service manager, in order to continue operation after a service restart without - losing state use <literal>FDSTORE=1</literal>:</para> + losing state, use <literal>FDSTORE=1</literal>:</para> <programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1\nFDNAME=foobar", &fd, 1);</programlisting> </example> diff --git a/man/sd_pid_get_session.xml b/man/sd_pid_get_session.xml index 035effcaa9..806cff34e4 100644 --- a/man/sd_pid_get_session.xml +++ b/man/sd_pid_get_session.xml @@ -176,7 +176,7 @@ not all processes are part of a login session (e.g. system service processes, user processes that are shared between multiple sessions of the same user, or kernel threads). For processes not - being part of a login session this function will fail with + being part of a login session, this function will fail with -ENODATA. The returned string needs to be freed with the libc <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry> @@ -188,8 +188,8 @@ unit name is a short string, suitable for usage in file system paths. Note that not all processes are part of a system unit/service (e.g. user processes, or kernel threads). For - processes not being part of a systemd system unit this function - will fail with -ENODATA (More specifically: this call will not + processes not being part of a systemd system unit, this function + will fail with -ENODATA. (More specifically, this call will not work for kernel threads.) The returned string needs to be freed with the libc <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry> @@ -198,17 +198,17 @@ <para><function>sd_pid_get_user_unit()</function> may be used to determine the systemd user unit (i.e. user service or scope unit) identifier of a process identified by the specified PID. This is - similar to <function>sd_pid_get_unit()</function> but applies to + similar to <function>sd_pid_get_unit()</function>, but applies to user units instead of system units.</para> <para><function>sd_pid_get_owner_uid()</function> may be used to determine the Unix UID (user identifier) of the owner of the session of a process identified the specified PID. Note that this function will succeed for user processes which are shared between - multiple login sessions of the same user, where + multiple login sessions of the same user, whereas <function>sd_pid_get_session()</function> will fail. For processes not being part of a login session and not being a shared process - of a user this function will fail with -ENODATA.</para> + of a user, this function will fail with -ENODATA.</para> <para><function>sd_pid_get_machine_name()</function> may be used to determine the name of the VM or container is a member of. The @@ -216,7 +216,7 @@ paths. The returned string needs to be freed with the libc <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry> - call after use. For processes not part of a VM or containers this + call after use. For processes not part of a VM or containers, this function fails with -ENODATA.</para> <para><function>sd_pid_get_slice()</function> may be used to @@ -227,7 +227,7 @@ <citerefentry project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry> call after use.</para> - <para>Similar, <function>sd_pid_get_user_slice()</function> + <para>Similarly, <function>sd_pid_get_user_slice()</function> returns the user slice (as managed by the user's systemd instance) of a process.</para> @@ -235,7 +235,7 @@ group path of the specified process, relative to the root of the hierarchy. Returns the path without trailing slash, except for processes located in the root control group, where "/" is - returned. To find the actual control group path in the file system + returned. To find the actual control group path in the file system, the returned path needs to be prefixed with <filename>/sys/fs/cgroup/</filename> (if the unified control group setup is used), or @@ -294,7 +294,7 @@ <varlistentry> <term><constant>-ENODATA</constant></term> - <listitem><para>Given field is not specified for the described + <listitem><para>The given field is not specified for the described process or peer.</para> </listitem> </varlistentry> @@ -303,7 +303,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>An input parameter was invalid (out of range, - or NULL, where that's not accepted).</para></listitem> + or NULL, where that is not accepted).</para></listitem> </varlistentry> <varlistentry> diff --git a/man/sd_seat_get_active.xml b/man/sd_seat_get_active.xml index 4d3e0822e0..6e1d505dce 100644 --- a/man/sd_seat_get_active.xml +++ b/man/sd_seat_get_active.xml @@ -158,7 +158,7 @@ <varlistentry> <term><constant>-ENODATA</constant></term> - <listitem><para>Given field is not specified for the described + <listitem><para>The given field is not specified for the described seat.</para> </listitem> </varlistentry> @@ -174,7 +174,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>An input parameter was invalid (out of range, - or NULL, where that's not accepted).</para></listitem> + or NULL, where that is not accepted).</para></listitem> </varlistentry> <varlistentry> diff --git a/man/sd_session_is_active.xml b/man/sd_session_is_active.xml index 7de9523789..a6076b177a 100644 --- a/man/sd_session_is_active.xml +++ b/man/sd_session_is_active.xml @@ -306,7 +306,7 @@ <varlistentry> <term><constant>-ENODATA</constant></term> - <listitem><para>Given field is not specified for the described + <listitem><para>The given field is not specified for the described session.</para> </listitem> </varlistentry> @@ -315,7 +315,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>An input parameter was invalid (out of range, - or NULL, where that's not accepted).</para></listitem> + or NULL, where that is not accepted).</para></listitem> </varlistentry> <varlistentry> diff --git a/man/sd_uid_get_state.xml b/man/sd_uid_get_state.xml index 13ddf08c65..4cc7405dd6 100644 --- a/man/sd_uid_get_state.xml +++ b/man/sd_uid_get_state.xml @@ -179,7 +179,7 @@ <varlistentry> <term><constant>-ENODATA</constant></term> - <listitem><para>Given field is not specified for the described + <listitem><para>The given field is not specified for the described user.</para> </listitem> </varlistentry> @@ -195,7 +195,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>An input parameter was invalid (out of range, - or NULL, where that's not accepted). This is also returned if + or NULL, where that is not accepted). This is also returned if the passed user ID is 0xFFFF or 0xFFFFFFFF, which are undefined on Linux.</para></listitem> </varlistentry> diff --git a/man/sd_watchdog_enabled.xml b/man/sd_watchdog_enabled.xml index 991431f33b..144ab1db61 100644 --- a/man/sd_watchdog_enabled.xml +++ b/man/sd_watchdog_enabled.xml @@ -157,7 +157,7 @@ systemd-41.</para> <para><function>sd_watchdog_enabled()</function> function was - added in systemd-209. Since that version the + added in systemd-209. Since that version, the <varname>$WATCHDOG_PID</varname> variable is also set.</para> </refsect1> diff --git a/man/standard-conf.xml b/man/standard-conf.xml index ffc6f76294..6edbb7ff83 100644 --- a/man/standard-conf.xml +++ b/man/standard-conf.xml @@ -38,9 +38,9 @@ <refsection id='main-conf'> <title>Configuration Directories and Precedence</title> - <para>Default configuration is defined during compilation, so a + <para>The default configuration is defined during compilation, so a configuration file is only needed when it is necessary to deviate - from those defaults. By default the configuration file in + from those defaults. By default, the configuration file in <filename>/etc/systemd/</filename> contains commented out entries showing the defaults as a guide to the administrator. This file can be edited to create local overrides. diff --git a/man/sysctl.d.xml b/man/sysctl.d.xml index e5b2bc0ac9..ccf6c8e39f 100644 --- a/man/sysctl.d.xml +++ b/man/sysctl.d.xml @@ -140,10 +140,10 @@ net.bridge.bridge-nf-call-arptables = 0 </programlisting> <para>This method applies settings when the module is - loaded. Please note that unless the <filename>br_netfilter</filename> + loaded. Please note that, unless the <filename>br_netfilter</filename> module is loaded, bridged packets will not be filtered by - netfilter (starting with kernel 3.18), so simply not loading the - module is suffient to avoid filtering.</para> + Netfilter (starting with kernel 3.18), so simply not loading the + module is sufficient to avoid filtering.</para> </example> <example> @@ -162,10 +162,10 @@ net.bridge.bridge-nf-call-arptables = 0 </programlisting> <para>This method forces the module to be always loaded. Please - note that unless the <filename>br_netfilter</filename> module is - loaded, bridged packets will not be filtered with netfilter + note that, unless the <filename>br_netfilter</filename> module is + loaded, bridged packets will not be filtered with Netfilter (starting with kernel 3.18), so simply not loading the module is - suffient to avoid filtering.</para> + sufficient to avoid filtering.</para> </example> </refsect1> diff --git a/man/systemctl.xml b/man/systemctl.xml index 36edc204b7..755a74f987 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -103,7 +103,7 @@ <listitem> <para>The argument should be a comma-separated list of unit LOAD, SUB, or ACTIVE states. When listing units, show only - those in specified states. Use <option>--state=failed</option> + those in the specified states. Use <option>--state=failed</option> to show only failed units.</para> <para>As a special case, if one of the arguments is @@ -134,7 +134,7 @@ <para>Properties for units vary by unit type, so showing any unit (even a non-existent one) is a way to list properties - pertaining to this type. Similarly showing any job will list + pertaining to this type. Similarly, showing any job will list properties pertaining to all jobs. Properties for units are documented in <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>, @@ -179,7 +179,6 @@ <command>list-dependencies</command>, i.e. follow dependencies of type <varname>WantedBy=</varname>, <varname>RequiredBy=</varname>, - <varname>RequiredByOverridable=</varname>, <varname>PartOf=</varname>, <varname>BoundBy=</varname>, instead of <varname>Wants=</varname> and similar. </para> @@ -359,7 +358,7 @@ <!-- we do not document -failed here, as it has been made redundant by -state=failed, which it predates. To keep - things simple we only document the new switch, while + things simple, we only document the new switch, while keeping the old one around for compatibility only. --> <varlistentry> @@ -458,7 +457,7 @@ <listitem> <para>When used with <command>kill</command>, choose which signal to send to selected processes. Must be one of the - well known signal specifiers such as <constant>SIGTERM</constant>, <constant>SIGINT</constant> or + well-known signal specifiers such as <constant>SIGTERM</constant>, <constant>SIGINT</constant> or <constant>SIGSTOP</constant>. If omitted, defaults to <option>SIGTERM</option>.</para> </listitem> @@ -518,7 +517,7 @@ <listitem> <para>When used with <command>enable</command>/<command>disable</command>/<command>is-enabled</command> - (and related commands), use alternative root path when + (and related commands), use an alternate root path when looking for unit files.</para> </listitem> @@ -600,7 +599,9 @@ <listitem> <para>When used with <command>list-dependencies</command>, - the output is printed as a list instead of a tree.</para> + <command>list-units</command> or <command>list-machines</command>, the + the output is printed as a list instead of a tree, and the bullet + circles are omitted.</para> </listitem> </varlistentry> @@ -829,7 +830,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <para>This function is intended to generate human-readable output. If you are looking for computer-parsable output, - use <command>show</command> instead. By default this + use <command>show</command> instead. By default, this function only shows 10 lines of output and ellipsizes lines to fit in the terminal window. This can be changes with <option>--lines</option> and <option>--full</option>, @@ -849,7 +850,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <para>Show properties of one or more units, jobs, or the manager itself. If no argument is specified, properties of the manager will be shown. If a unit name is specified, - properties of the unit is shown, and if a job id is + properties of the unit is shown, and if a job ID is specified, properties of the job is shown. By default, empty properties are suppressed. Use <option>--all</option> to show those too. To select specific properties to show, use @@ -930,9 +931,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <para>Shows units required and wanted by the specified unit. This recursively lists units following the <varname>Requires=</varname>, - <varname>RequiresOverridable=</varname>, <varname>Requisite=</varname>, - <varname>RequisiteOverridable=</varname>, <varname>ConsistsOf=</varname>, <varname>Wants=</varname>, <varname>BindsTo=</varname> dependencies. If no unit is specified, @@ -959,10 +958,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <term><command>list-unit-files <optional><replaceable>PATTERN...</replaceable></optional></command></term> <listitem> - <para>List installed unit files. If one or more - <replaceable>PATTERN</replaceable>s are specified, only - units whose filename (just the last component of the path) - matches one of them are shown.</para> + <para>List installed unit files and their enablement state + (as reported by <command>is-enabled</command>). If one or + more <replaceable>PATTERN</replaceable>s are specified, + only units whose filename (just the last component of the + path) matches one of them are shown.</para> </listitem> </varlistentry> @@ -981,7 +981,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service starting any of the units being enabled. If this is desired, either <option>--now</option> should be used together with this command, or an additional <command>start</command> - command must be invoked for the unit. Also note that in case of + command must be invoked for the unit. Also note that, in case of instance enablement, symlinks named the same as instances are created in the install location, however they all point to the same template unit file.</para> @@ -1132,7 +1132,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <tbody> <row> <entry><literal>enabled</literal></entry> - <entry morerows='1'>Enabled through a symlink in <filename>.wants</filename> directory (permanently or just in <filename>/run</filename>).</entry> + <entry morerows='1'>Enabled through a symlink in a <filename>.wants/</filename> or <filename>.requires/</filename> subdirectory of <filename>/etc/systemd/system/</filename> (persistently) or <filename>/run/systemd/system/</filename> (transiently).</entry> <entry morerows='1'>0</entry> </row> <row> @@ -1140,7 +1140,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service </row> <row> <entry><literal>linked</literal></entry> - <entry morerows='1'>Made available through a symlink to the unit file (permanently or just in <filename>/run</filename>).</entry> + <entry morerows='1'>Made available through one or more symlinks to the unit file (permanently in <filename>/etc/systemd/system/</filename> or transiently in <filename>/run/systemd/system/</filename>), even though the unit file might reside outside of the unit file search path.</entry> <entry morerows='1'>> 0</entry> </row> <row> @@ -1148,7 +1148,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service </row> <row> <entry><literal>masked</literal></entry> - <entry morerows='1'>Disabled entirely (permanently or just in <filename>/run</filename>).</entry> + <entry morerows='1'>Completely disabled, so that any start operation on it fails (permanently in <filename>/etc/systemd/system/</filename> or transiently in <filename>/run/systemd/systemd/</filename>).</entry> <entry morerows='1'>> 0</entry> </row> <row> @@ -1156,17 +1156,22 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service </row> <row> <entry><literal>static</literal></entry> - <entry>Unit file is not enabled, and has no provisions for enabling in the <literal>[Install]</literal> section.</entry> + <entry>The unit file is not enabled, and has no provisions for enabling in the <literal>[Install]</literal> section.</entry> <entry>0</entry> </row> <row> <entry><literal>indirect</literal></entry> - <entry>Unit file itself is not enabled, but it has a non-empty <varname>Also=</varname> setting in the <literal>[Install]</literal> section, listing other unit files that might be enabled.</entry> + <entry>The unit file itself is not enabled, but it has a non-empty <varname>Also=</varname> setting in the <literal>[Install]</literal> section, listing other unit files that might be enabled.</entry> <entry>0</entry> </row> <row> <entry><literal>disabled</literal></entry> - <entry>Unit file is not enabled.</entry> + <entry>Unit file is not enabled, but contains an <literal>[Install]</literal> section with installation instructions.</entry> + <entry>> 0</entry> + </row> + <row> + <entry><literal>bad</literal></entry> + <entry>Unit file is invalid or another error occured. Note that <command>is-enabled</command> will not actually return this state, but print an error message instead. However the unit file listing printed by <command>list-unit-files</command> might show it.</entry> <entry>> 0</entry> </row> </tbody> @@ -1225,12 +1230,12 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <listitem> <para>Adds <literal>Wants=</literal> or <literal>Requires=</literal> - dependency, respectively, to the specified + dependencies, respectively, to the specified <replaceable>TARGET</replaceable> for one or more units. </para> <para>This command honors <option>--system</option>, <option>--user</option>, <option>--runtime</option> and - <option>--global</option> in a similar way as + <option>--global</option> in a way similar to <command>enable</command>.</para> </listitem> @@ -1246,8 +1251,8 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <para>Depending on whether <option>--system</option> (the default), <option>--user</option>, or <option>--global</option> is specified, - this creates a drop-in file for each unit either for the system, - for the calling user or for all futures logins of all users. Then, + this command creates a drop-in file for each unit either for the system, + for the calling user, or for all futures logins of all users. Then, the editor (see the "Environment" section below) is invoked on temporary files which will be written to the real location if the editor exits successfully.</para> @@ -1259,8 +1264,8 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service be made temporarily in <filename>/run</filename> and they will be lost on the next reboot.</para> - <para>If the temporary file is empty upon exit the modification of - the related unit is canceled</para> + <para>If the temporary file is empty upon exit, the modification of + the related unit is canceled.</para> <para>After the units have been edited, systemd configuration is reloaded (in a way that is equivalent to <command>daemon-reload</command>). @@ -1268,7 +1273,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <para>Note that this command cannot be used to remotely edit units and that you cannot temporarily edit units which are in - <filename>/etc</filename> since they take precedence over + <filename>/etc</filename>, since they take precedence over <filename>/run</filename>.</para> </listitem> </varlistentry> @@ -1340,46 +1345,6 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service </refsect2> <refsect2> - <title>Snapshot Commands</title> - - <variablelist> - <varlistentry> - <term><command>snapshot <optional><replaceable>NAME</replaceable></optional></command></term> - - <listitem> - <para>Create a snapshot. If a snapshot name is specified, - the new snapshot will be named after it. If none is - specified, an automatic snapshot name is generated. In - either case, the snapshot name used is printed to standard - output, unless <option>--quiet</option> is specified. - </para> - - <para>A snapshot refers to a saved state of the systemd - manager. It is implemented itself as a unit that is - generated dynamically with this command and has dependencies - on all units active at the time. At a later time, the user - may return to this state by using the - <command>isolate</command> command on the snapshot unit. - </para> - - <para>Snapshots are only useful for saving and restoring - which units are running or are stopped, they do not - save/restore any other state. Snapshots are dynamic and lost - on reboot.</para> - </listitem> - </varlistentry> - <varlistentry> - <term><command>delete <replaceable>PATTERN</replaceable>...</command></term> - - <listitem> - <para>Remove a snapshot previously created with - <command>snapshot</command>.</para> - </listitem> - </varlistentry> - </variablelist> - </refsect2> - - <refsect2> <title>Environment Commands</title> <variablelist> @@ -1440,7 +1405,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <term><command>daemon-reload</command></term> <listitem> - <para>Reload systemd manager configuration. This will + <para>Reload the systemd manager configuration. This will rerun all generators (see <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>), reload all unit files, and recreate the entire dependency @@ -1483,7 +1448,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service maintenance mode, and with no failed services. Failure is returned otherwise (exit code non-zero). In addition, the current state is printed in a short string to standard - output, see table below. Use <option>--quiet</option> to + output, see the table below. Use <option>--quiet</option> to suppress this output.</para> <table> @@ -1682,7 +1647,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <para>Switches to a different root directory and executes a new system manager process below it. This is intended for usage in initial RAM disks ("initrd"), and will transition - from the initrd's system manager process (a.k.a "init" + from the initrd's system manager process (a.k.a. "init" process) to the main system manager process. This call takes two arguments: the directory that is to become the new root directory, and the path to the new system manager binary below it to diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml index 90e974c991..5fe1a39057 100644 --- a/man/systemd-activate.xml +++ b/man/systemd-activate.xml @@ -61,7 +61,7 @@ <title>Description</title> <para><command>systemd-activate</command> can be used to - launch a socket activated daemon from the command line for + launch a socket-activated daemon from the command line for testing purposes. It can also be used to launch single instances of the daemon per connection (inetd-style). </para> @@ -164,7 +164,7 @@ </example> <example> - <title>Run a socket activated instance of <citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry></title> + <title>Run a socket-activated instance of <citerefentry><refentrytitle>systemd-journal-gatewayd</refentrytitle><manvolnum>8</manvolnum></citerefentry></title> <programlisting>$ /usr/lib/systemd/systemd-activate -l 19531 /usr/lib/systemd/systemd-journal-gatewayd</programlisting> </example> diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index d2db265f58..bc37765dff 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -178,7 +178,7 @@ <replaceable>TARGET</replaceable></command> changes the current log target of the <command>systemd</command> daemon to <replaceable>TARGET</replaceable> (accepts the same values as - <option>--log-target=</option> described in + <option>--log-target=</option>, described in <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para> <para><command>systemd-analyze verify</command> will load unit @@ -226,9 +226,7 @@ <varname>After=</varname> or <varname>Before=</varname> are shown. If <option>--require</option> is passed, only dependencies of type <varname>Requires=</varname>, - <varname>RequiresOverridable=</varname>, <varname>Requisite=</varname>, - <varname>RequisiteOverridable=</varname>, <varname>Wants=</varname> and <varname>Conflicts=</varname> are shown. If neither is passed, this shows dependencies of all these types.</para></listitem> diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml index 10bb529b81..6fb322e849 100644 --- a/man/systemd-ask-password.xml +++ b/man/systemd-ask-password.xml @@ -138,9 +138,9 @@ cache for the password. If set, then the tool will try to push any collected passwords into the kernel keyring of the root user, as a key of the specified name. If combined with - <option>--accept-cached</option> it will also try to retrieve - the such cached passwords from the key in the kernel keyring - instead of querying the user right-away. By using this option + <option>--accept-cached</option>, it will also try to retrieve + such cached passwords from the key in the kernel keyring + instead of querying the user right away. By using this option, the kernel keyring may be used as effective cache to avoid repeatedly asking users for passwords, if there are multiple objects that may be unlocked with the same password. The @@ -181,7 +181,7 @@ <term><option>--accept-cached</option></term> <listitem><para>If passed, accept cached passwords, i.e. - passwords previously typed in. </para></listitem> + passwords previously entered.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd-backlight@.service.xml b/man/systemd-backlight@.service.xml index a259f5d583..3459ed8851 100644 --- a/man/systemd-backlight@.service.xml +++ b/man/systemd-backlight@.service.xml @@ -58,8 +58,8 @@ that restores the display backlight brightness at early boot and saves it at shutdown. On disk, the backlight brightness is stored in <filename>/var/lib/systemd/backlight/</filename>. During - loading, if udev property <option>ID_BACKLIGHT_CLAMP</option> is - not set to false value, the brightness is clamped to a value of at + loading, if the udev property <option>ID_BACKLIGHT_CLAMP</option> is + not set to false, the brightness is clamped to a value of at least 1 or 5% of maximum brightness, whichever is greater. This restriction will be removed when the kernel allows user space to reliably set a brightness value which does not turn off the diff --git a/man/systemd-binfmt.service.xml b/man/systemd-binfmt.service.xml index 66d264389e..cccfb49ca9 100644 --- a/man/systemd-binfmt.service.xml +++ b/man/systemd-binfmt.service.xml @@ -54,7 +54,7 @@ <refsect1> <title>Description</title> - <para><filename>systemd-binfmt.service</filename> is an early-boot + <para><filename>systemd-binfmt.service</filename> is an early boot service that registers additional binary formats for executables in the kernel.</para> diff --git a/man/systemd-bootchart.xml b/man/systemd-bootchart.xml index 538666760a..bcee11fd0b 100644 --- a/man/systemd-bootchart.xml +++ b/man/systemd-bootchart.xml @@ -66,7 +66,7 @@ and logging startup information in the background. </para> <para> - After collecting a certain amount of data (usually 15-30 + After collecting a certain amount of data (usually 15–30 seconds, default 20 s) the logging stops and a graph is generated from the logged information. This graph contains vital clues as to which resources are being used, in which order, and @@ -114,7 +114,7 @@ <term><emphasis>Started as a standalone program</emphasis></term> <listitem><para>One can execute <command>systemd-bootchart</command> as normal application - from the command line. In this mode it is highly recommended + from the command line. In this mode, it is highly recommended to pass the <option>-r</option> flag in order to not graph the time elapsed since boot and before systemd-bootchart was started, as it may result in extremely large graphs. The time @@ -149,7 +149,7 @@ <term><option>--freq <replaceable>f</replaceable></option></term> <listitem><para>Specify the sample log frequency, a positive real <replaceable>f</replaceable>, in Hz. Most systems can - cope with values up to 25-50 without creating too much + cope with values up to 25–50 without creating too much overhead.</para></listitem> </varlistentry> diff --git a/man/systemd-cat.xml b/man/systemd-cat.xml index 9b1a8809dc..160db9fb5c 100644 --- a/man/systemd-cat.xml +++ b/man/systemd-cat.xml @@ -112,7 +112,7 @@ <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Defaults to <literal>info</literal>. Note that this simply controls the default, individual lines may be logged with - different levels if they are prefixed accordingly. For details + different levels if they are prefixed accordingly. For details, see <option>--level-prefix=</option> below.</para></listitem> </varlistentry> diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml index 1c90c0a659..c76f646984 100644 --- a/man/systemd-cgtop.xml +++ b/man/systemd-cgtop.xml @@ -154,7 +154,7 @@ <term><option>-r</option></term> <term><option>--raw</option></term> - <listitem><para>Format byte counts (as in memory usage and IO metrics) + <listitem><para>Format byte counts (as in memory usage and I/O metrics) with raw numeric values rather than human-readable numbers.</para></listitem> </varlistentry> @@ -164,7 +164,7 @@ <term><option>--cpu=time</option></term> <listitem><para>Controls whether the CPU usage is shown as - percentage or time. By default the CPU usage is shown as + percentage or time. By default, the CPU usage is shown as percentage. This setting may also be toggled at runtime by pressing the <keycap>%</keycap> key.</para></listitem> </varlistentry> @@ -173,8 +173,8 @@ <term><option>-P</option></term> <listitem><para>Count only userspace processes instead of all - tasks. By default all tasks are counted: each kernel thread - and each userspace thread individually. With this setting + tasks. By default, all tasks are counted: each kernel thread + and each userspace thread individually. With this setting, kernel threads are excluded from the counting and each userspace process only counts as one, regardless how many threads it consists of. This setting may also be toggled at @@ -187,9 +187,9 @@ <term><option>-k</option></term> <listitem><para>Count only userspace processes and kernel - threads instead of all tasks. By default all tasks are + threads instead of all tasks. By default, all tasks are counted: each kernel thread and each userspace thread - individually. With this setting kernel threads are included in + individually. With this setting, kernel threads are included in the counting and each userspace process only counts as on one, regardless how many threads it consists of. This setting may also be toggled at runtime by pressing the <keycap>k</keycap> @@ -203,9 +203,9 @@ <listitem><para>Controls whether the number of processes shown for a control group shall include all processes that are contained in any of the child control groups as well. Takes a - boolean argument, defaults to <literal>yes</literal>. If - enabled the processes in child control groups are included, if - disabled only the processes in the control group itself are + boolean argument, which defaults to <literal>yes</literal>. If + enabled, the processes in child control groups are included, if + disabled, only the processes in the control group itself are counted. This setting may also be toggled at runtime by pressing the <keycap>r</keycap> key. Note that this setting only applies to process counting, i.e. when the @@ -294,7 +294,7 @@ <term><keycap>i</keycap></term> <listitem><para>Sort the control groups by path, number of - tasks, CPU load, memory usage, or IO load, respectively. This + tasks, CPU load, memory usage, or I/O load, respectively. This setting may also be controlled using the <option>--order=</option> command line switch.</para></listitem> @@ -343,7 +343,7 @@ excluding processes in child control groups in control group process counts. This setting may also be controlled using the <option>--recursive=</option> command line switch. This key is - not available of all tasks are counted, it is only available + not available if all tasks are counted, it is only available if processes are counted, as enabled with the <keycap>P</keycap> or <keycap>k</keycap> keys.</para></listitem> diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml index cb46d41902..f1598461ef 100644 --- a/man/systemd-coredump.xml +++ b/man/systemd-coredump.xml @@ -72,7 +72,7 @@ in <citerefentry project='man-pages'><refentrytitle>core</refentrytitle><manvolnum>5</manvolnum></citerefentry>. In particular, the coredump will only be processed when the related resource limits are high enough. For programs started by - <command>systemd</command> those may be set using + <command>systemd</command>, those may be set using <varname>LimitCore=</varname> (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>). </para> diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml index b6270358ea..f036ab9744 100644 --- a/man/systemd-cryptsetup-generator.xml +++ b/man/systemd-cryptsetup-generator.xml @@ -111,7 +111,7 @@ system and the initrd.</para> <para>If /etc/crypttab contains entries with the same UUID, then the name, keyfile and options specified there will be - used. Otherwise the device will have the name + used. Otherwise, the device will have the name <literal>luks-UUID</literal>.</para> <para>If /etc/crypttab exists, only those UUIDs specified on the kernel command line diff --git a/man/systemd-delta.xml b/man/systemd-delta.xml index 6a6460ffaa..99709604aa 100644 --- a/man/systemd-delta.xml +++ b/man/systemd-delta.xml @@ -70,7 +70,7 @@ directories which contain "drop-in" files with configuration snippets which augment the main configuration file. "Drop-in" files can be overridden in the same way by placing files with the - same name in a directory of higher priority (except that in case + same name in a directory of higher priority (except that, in case of "drop-in" files, both the "drop-in" file name and the name of the containing directory, which corresponds to the name of the main configuration file, must match). For a fuller explanation, diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml index 9ea9141d4d..5d19322cdc 100644 --- a/man/systemd-detect-virt.xml +++ b/man/systemd-detect-virt.xml @@ -22,7 +22,7 @@ --> <refentry id="systemd-detect-virt" - xmlns:xi="http://www.w3.org/2001/XInclude"> + xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>systemd-detect-virt</title> @@ -62,7 +62,7 @@ technology and can distinguish full VM virtualization from container virtualization. <filename>systemd-detect-virt</filename> exits with a return value of 0 (success) if a virtualization - technology is detected, and non-zero (error) otherwise. By default + technology is detected, and non-zero (error) otherwise. By default, any type of virtualization is detected, and the options <option>--container</option> and <option>--vm</option> can be used to limit what types of virtualization are detected.</para> @@ -81,87 +81,92 @@ <colspec colname="product" /> <thead> <row> - <entry>Type</entry> - <entry>ID</entry> - <entry>Product</entry> + <entry>Type</entry> + <entry>ID</entry> + <entry>Product</entry> </row> </thead> <tbody> <row> - <entry morerows="9">VM</entry> - <entry><varname>qemu</varname></entry> - <entry>QEMU software virtualization</entry> + <entry morerows="9">VM</entry> + <entry><varname>qemu</varname></entry> + <entry>QEMU software virtualization</entry> </row> <row> - <entry><varname>kvm</varname></entry> - <entry>Linux KVM kernel virtual machine</entry> + <entry><varname>kvm</varname></entry> + <entry>Linux KVM kernel virtual machine</entry> </row> <row> - <entry><varname>zvm</varname></entry> - <entry>s390 z/VM</entry> + <entry><varname>zvm</varname></entry> + <entry>s390 z/VM</entry> </row> <row> - <entry><varname>vmware</varname></entry> - <entry>VMware Workstation or Server, and related products</entry> + <entry><varname>vmware</varname></entry> + <entry>VMware Workstation or Server, and related products</entry> </row> <row> - <entry><varname>microsoft</varname></entry> - <entry>Hyper-V, also known as Viridian or Windows Server Virtualization</entry> + <entry><varname>microsoft</varname></entry> + <entry>Hyper-V, also known as Viridian or Windows Server Virtualization</entry> </row> <row> - <entry><varname>oracle</varname></entry> - <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems)</entry> + <entry><varname>oracle</varname></entry> + <entry>Oracle VM VirtualBox (historically marketed by innotek and Sun Microsystems)</entry> </row> <row> - <entry><varname>xen</varname></entry> - <entry>Xen hypervisor (only domU, not dom0)</entry> + <entry><varname>xen</varname></entry> + <entry>Xen hypervisor (only domU, not dom0)</entry> </row> <row> - <entry><varname>bochs</varname></entry> - <entry>Bochs Emulator</entry> + <entry><varname>bochs</varname></entry> + <entry>Bochs Emulator</entry> </row> <row> - <entry><varname>uml</varname></entry> - <entry>User-mode Linux</entry> + <entry><varname>uml</varname></entry> + <entry>User-mode Linux</entry> </row> <row> - <entry><varname>parallels</varname></entry> - <entry>Parallels Desktop, Parallels Server</entry> + <entry><varname>parallels</varname></entry> + <entry>Parallels Desktop, Parallels Server</entry> </row> <row> - <entry morerows="5">container</entry> - <entry><varname>openvz</varname></entry> - <entry>OpenVZ/Virtuozzo</entry> + <entry morerows="5">Container</entry> + <entry><varname>openvz</varname></entry> + <entry>OpenVZ/Virtuozzo</entry> </row> <row> - <entry><varname>lxc</varname></entry> - <entry>Linux container implementation by LXC</entry> + <entry><varname>lxc</varname></entry> + <entry>Linux container implementation by LXC</entry> </row> <row> - <entry><varname>lxc-libvirt</varname></entry> - <entry>Linux container implementation by libvirt</entry> + <entry><varname>lxc-libvirt</varname></entry> + <entry>Linux container implementation by libvirt</entry> </row> <row> - <entry><varname>systemd-nspawn</varname></entry> - <entry>systemd's minimal container implementation, see <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></entry> + <entry><varname>systemd-nspawn</varname></entry> + <entry>systemd's minimal container implementation, see <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry></entry> </row> <row> - <entry><varname>docker</varname></entry> - <entry>Docker container manager</entry> + <entry><varname>docker</varname></entry> + <entry>Docker container manager</entry> + </row> + + <row> + <entry><varname>rkt</varname></entry> + <entry>rkt app container runtime</entry> </row> </tbody> </tgroup> @@ -197,6 +202,18 @@ </varlistentry> <varlistentry> + <term><option>-r</option></term> + <term><option>--chroot</option></term> + + <listitem><para>Detect whether invoked in a + <citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry> + environment. In this mode, no output is written, but the return + value indicates whether the process was invoked in a + <function>chroot()</function> + environment or not.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>-q</option></term> <term><option>--quiet</option></term> @@ -221,7 +238,8 @@ <title>See Also</title> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/systemd-escape.xml b/man/systemd-escape.xml index 0c3b230526..5407773f23 100644 --- a/man/systemd-escape.xml +++ b/man/systemd-escape.xml @@ -67,11 +67,11 @@ and will process them individually, one after the other. It will output them separated by spaces to stdout.</para> - <para>By default this command will escape the strings passed, + <para>By default, this command will escape the strings passed, unless <option>--unescape</option> is passed which results in the - inverse operation being applied. If <option>--mangle</option> a - special mode of escaping is applied instead, which assumes a - string to be already escaped but will escape everything that + inverse operation being applied. If <option>--mangle</option> is given, a + special mode of escaping is applied instead, which assumes the + string is already escaped but will escape everything that appears obviously non-escaped.</para> </refsect1> diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml index 67289daa26..b269e48113 100644 --- a/man/systemd-firstboot.xml +++ b/man/systemd-firstboot.xml @@ -80,12 +80,12 @@ <listitem><para>The root user's password</para></listitem> </itemizedlist> - <para>Each of the fields may either be queried interactively from - the users, set non-interactively on the tool's command line, or be + <para>Each of the fields may either be queried interactively by + users, set non-interactively on the tool's command line, or be copied from a host system that is used to set up the system image.</para> - <para>If a setting is already initialized it will not be + <para>If a setting is already initialized, it will not be overwritten and the user will not be prompted for the setting.</para> @@ -166,10 +166,10 @@ <citerefentry project='die-net'><refentrytitle>shadow</refentrytitle><manvolnum>5</manvolnum></citerefentry> file. This setting exists in two forms: <option>--root-password=</option> accepts the password to set - directly on the command line, + directly on the command line, and <option>--root-password-file=</option> reads it from a file. - Note that it is not recommended specifying passwords on the - command line as other users might be able to see them simply + Note that it is not recommended to specify passwords on the + command line, as other users might be able to see them simply by invoking <citerefentry project='die-net'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para></listitem> </varlistentry> diff --git a/man/systemd-fsck@.service.xml b/man/systemd-fsck@.service.xml index 6d05e90e7b..933c3247ad 100644 --- a/man/systemd-fsck@.service.xml +++ b/man/systemd-fsck@.service.xml @@ -62,15 +62,15 @@ device that is configured for file system checking. <filename>systemd-fsck-root.service</filename> is responsible for file system checks on the root file system, but only if the - root filesystem wasn't checked in the initramfs. + root filesystem was not checked in the initramfs. <filename>systemd-fsck@.service</filename> is used for all other file systems and for the root file system in the initramfs.</para> - <para>Those services are started at boot if + <para>These services are started at boot if <option>passno</option> in <filename>/etc/fstab</filename> for the file system is set to a value greater than zero. The file system check for root is performed before the other file systems. Other - file systems may be checked in parallel, except when they are one + file systems may be checked in parallel, except when they are on the same rotating disk.</para> <para><filename>systemd-fsck</filename> does not know any details diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml index c09ed4b4da..a971cb3675 100644 --- a/man/systemd-fstab-generator.xml +++ b/man/systemd-fstab-generator.xml @@ -126,7 +126,7 @@ <varname>mount.usr=</varname> will default to the value set in <varname>root=</varname>.</para> - <para>Otherwise this parameter defaults to the + <para>Otherwise, this parameter defaults to the <filename>/usr</filename> entry found in <filename>/etc/fstab</filename> on the root filesystem.</para> @@ -143,7 +143,7 @@ <varname>mount.usrfstype=</varname> will default to the value set in <varname>rootfstype=</varname>.</para> - <para>Otherwise this value will be read from the + <para>Otherwise, this value will be read from the <filename>/usr</filename> entry in <filename>/etc/fstab</filename> on the root filesystem.</para> @@ -159,7 +159,7 @@ <varname>mount.usrflags=</varname> will default to the value set in <varname>rootflags=</varname>.</para> - <para>Otherwise this value will be read from the + <para>Otherwise, this value will be read from the <filename>/usr</filename> entry in <filename>/etc/fstab</filename> on the root filesystem.</para> diff --git a/man/systemd-gpt-auto-generator.xml b/man/systemd-gpt-auto-generator.xml index f569ea3cde..e890c4dce2 100644 --- a/man/systemd-gpt-auto-generator.xml +++ b/man/systemd-gpt-auto-generator.xml @@ -142,7 +142,7 @@ </table> <para>The <filename>/home</filename> and <filename>/srv</filename> - partitions may be encrypted in LUKS format. In this case a device + partitions may be encrypted in LUKS format. In this case, a device mapper device is set up under the names <filename>/dev/mapper/home</filename> and <filename>/dev/mapper/srv</filename>. Note that this might create @@ -151,8 +151,8 @@ device name.</para> <para>Mount and automount units for the EFI System Partition (ESP), - mounting it to <filename>/boot</filename> are generated on EFI - systems, where the boot loader communicates the used ESP to the operating + mounting it to <filename>/boot</filename>, are generated on EFI + systems where the boot loader communicates the used ESP to the operating system. Since this generator creates an automount unit, the mount will only be activated on-demand, when accessed. On systems where <filename>/boot</filename> is an explicitly configured mount diff --git a/man/systemd-hwdb.xml b/man/systemd-hwdb.xml index f1a14025b0..2b363c77f2 100644 --- a/man/systemd-hwdb.xml +++ b/man/systemd-hwdb.xml @@ -64,7 +64,7 @@ <term><option>-r</option></term> <term><option>--root=<replaceable>PATH</replaceable></option></term> <listitem> - <para>Alternative root path in the filesystem.</para> + <para>Alternate root path in the filesystem.</para> </listitem> </varlistentry> </variablelist> diff --git a/man/systemd-journal-upload.xml b/man/systemd-journal-upload.xml index 597f2a2d3e..f9723dea89 100644 --- a/man/systemd-journal-upload.xml +++ b/man/systemd-journal-upload.xml @@ -196,7 +196,7 @@ <programlisting>openssl req -newkey rsa:2048 -days 3650 -x509 -nodes \ -out ca.pem -keyout ca.key -subj '/CN=Certificate authority/' -cat >ca.conf <<EOF +cat >ca.conf <<EOF [ ca ] default_ca = this @@ -221,7 +221,7 @@ emailAddress = optional EOF touch index -echo 0001 > serial +echo 0001 >serial SERVER=server CLIENT=client @@ -244,7 +244,7 @@ openssl ca -batch -config ca.conf -notext -in $CLIENT.csr -out $CLIENT.pem <varname>ServerCertificateFile=</varname>, <varname>ServerKeyFile=</varname>, in <filename>/etc/systemd/journal-remote.conf</filename> and - <filename>/etc/systemd/journal-upload.conf</filename> + <filename>/etc/systemd/journal-upload.conf</filename>, respectively. The default locations can be queried by using <command>systemd-journal-remote --help</command> and <command>systemd-journal-upload --help</command>.</para> diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml index bd0082712e..f1054b03bb 100644 --- a/man/systemd-journald.service.xml +++ b/man/systemd-journald.service.xml @@ -46,6 +46,7 @@ <refname>systemd-journald.service</refname> <refname>systemd-journald.socket</refname> <refname>systemd-journald-dev-log.socket</refname> + <refname>systemd-journald-audit.socket</refname> <refname>systemd-journald</refname> <refpurpose>Journal service</refpurpose> </refnamediv> @@ -54,6 +55,7 @@ <para><filename>systemd-journald.service</filename></para> <para><filename>systemd-journald.socket</filename></para> <para><filename>systemd-journald-dev-log.socket</filename></para> + <para><filename>systemd-journald-audit.socket</filename></para> <para><filename>/usr/lib/systemd/systemd-journald</filename></para> </refsynopsisdiv> @@ -129,15 +131,30 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting> this is enabled). This must be used after <filename>/var/</filename> is mounted, as otherwise log data from <filename>/run</filename> is never flushed to - <filename>/var</filename> regardless of the - configuration.</para></listitem> + <filename>/var</filename> regardless of the configuration. The + <command>journalctl --flush</command> command uses this signal + to request flushing of the journal files, and then waits for + the operation to complete. See + <citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> + for details.</para></listitem> </varlistentry> <varlistentry> <term>SIGUSR2</term> <listitem><para>Request immediate rotation of the journal - files.</para></listitem> + files. The <command>journalctl --rotate</command> command uses + this signal to request journal file + rotation.</para></listitem> + </varlistentry> + + <varlistentry> + <term>SIGRTMIN+1</term> + + <listitem><para>Request that all unwritten log data is written + to disk. The <command>journalctl --sync</command> command uses + this signal to trigger journal synchronization, and then waits + for the operation to complete.</para></listitem> </varlistentry> </variablelist> </refsect1> @@ -230,7 +247,20 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting> <filename>/var/log/journal</filename> is not available, or when <option>Storage=volatile</option> is set in the <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> - configuration file. </para></listitem> + configuration file.</para></listitem> + </varlistentry> + + <varlistentry> + <term><filename>/dev/kmsg</filename></term> + <term><filename>/dev/log</filename></term> + <term><filename>/run/systemd/journal/dev-log</filename></term> + <term><filename>/run/systemd/journal/socket</filename></term> + <term><filename>/run/systemd/journal/stdout</filename></term> + + <listitem><para>Sockets and other paths that + <command>systemd-journald</command> will listen on that are + visible in the file system. In addition to these, journald can + listen for audit events using netlink.</para></listitem> </varlistentry> </variablelist> </refsect1> @@ -246,7 +276,7 @@ systemd-tmpfiles --create --prefix /var/log/journal</programlisting> <citerefentry><refentrytitle>systemd-coredump</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry project='die-net'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>4</manvolnum></citerefentry>, - <command>pydoc systemd.journal</command>. + <command>pydoc systemd.journal</command> </para> </refsect1> diff --git a/man/systemd-machine-id-commit.service.xml b/man/systemd-machine-id-commit.service.xml index 10f36b3008..39da1922cc 100644 --- a/man/systemd-machine-id-commit.service.xml +++ b/man/systemd-machine-id-commit.service.xml @@ -42,7 +42,7 @@ <refnamediv> <refname>systemd-machine-id-commit.service</refname> - <refpurpose>Commit a transient machine-id to disk</refpurpose> + <refpurpose>Commit a transient machine ID to disk</refpurpose> </refnamediv> <refsynopsisdiv> @@ -53,7 +53,7 @@ <title>Description</title> <para><filename>systemd-machine-id-commit.service</filename> is an - early-boot service responsible for committing transient + early boot service responsible for committing transient <filename>/etc/machine-id</filename> files to a writable disk file system. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> @@ -74,7 +74,7 @@ <para>The main use case of this service are systems where <filename>/etc/machine-id</filename> is read-only and initially - not initialized. In this case the system manager will generate a + not initialized. In this case, the system manager will generate a transient machine ID file on a memory file system, and mount it over <filename>/etc/machine-id</filename>, during the early boot phase. This service is then invoked in a later boot phase, as soon diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml index efcf408332..bfcd74f436 100644 --- a/man/systemd-machine-id-setup.xml +++ b/man/systemd-machine-id-setup.xml @@ -71,7 +71,7 @@ for more information about this file.</para> <para>If the tool is invoked without the <option>--commit</option> - switch <filename>/etc/machine-id</filename> is initialized with a + switch, <filename>/etc/machine-id</filename> is initialized with a valid, new machined ID if it is missing or empty. The new machine ID will be acquired in the following fashion:</para> @@ -88,14 +88,14 @@ and is different for every booted instance of the VM.</para></listitem> - <listitem><para>Similar, if run inside a Linux container - environment and a UUID is configured for the container this is - used to initialize the machine ID. For details see the + <listitem><para>Similarly, if run inside a Linux container + environment and a UUID is configured for the container, this is + used to initialize the machine ID. For details, see the documentation of the <ulink url="http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface">Container Interface</ulink>.</para></listitem> - <listitem><para>Otherwise a new ID is randomly + <listitem><para>Otherwise, a new ID is randomly generated.</para></listitem> </orderedlist> @@ -148,7 +148,7 @@ <para>This command is primarily used by the <citerefentry><refentrytitle>systemd-machine-id-commit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> - early-boot service.</para></listitem> + early boot service.</para></listitem> </varlistentry> <xi:include href="standard-options.xml" xpointer="help" /> diff --git a/man/systemd-modules-load.service.xml b/man/systemd-modules-load.service.xml index dacd083bad..b25929b2e4 100644 --- a/man/systemd-modules-load.service.xml +++ b/man/systemd-modules-load.service.xml @@ -55,7 +55,7 @@ <title>Description</title> <para><filename>systemd-modules-load.service</filename> is an - early-boot service that loads kernel modules based on static + early boot service that loads kernel modules based on static configuration.</para> <para>See diff --git a/man/systemd-networkd-wait-online.service.xml b/man/systemd-networkd-wait-online.service.xml index bcc5776a8d..e21c805342 100644 --- a/man/systemd-networkd-wait-online.service.xml +++ b/man/systemd-networkd-wait-online.service.xml @@ -86,7 +86,7 @@ <varlistentry> <term><option>--ignore=</option></term> <listitem><para>Network interfaces to be ignored when deciding - if the system is online. By default only the loopback + if the system is online. By default, only the loopback interface is ignored. This option may be used more than once to ignore multiple network interfaces. </para></listitem> </varlistentry> diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml index 71d501f435..a5f4077166 100644 --- a/man/systemd-notify.xml +++ b/man/systemd-notify.xml @@ -60,7 +60,7 @@ <para><command>systemd-notify</command> may be called by daemon scripts to notify the init system about status changes. It can be used to send arbitrary information, encoded in an - environment-block-like list of strings. Most importantly it can be + environment-block-like list of strings. Most importantly, it can be used for start-up completion notification.</para> <para>This is mostly just a wrapper around @@ -125,7 +125,7 @@ message is sent. This option is hence unrelated to the other options. For details about the semantics of this option, see <citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>. An - alternative way to check for this state is to call + alternate way to check for this state is to call <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> with the <command>is-system-running</command> command. It will return <literal>offline</literal> if the system was not booted diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 4b0e72113e..a97b7c44eb 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -325,7 +325,7 @@ <varlistentry> <term><option>--private-users=</option></term> - <listitem><para>Enables user namespacing. If enabled the + <listitem><para>Enables user namespacing. If enabled, the container will run with its own private set of Unix user and group ids (UIDs and GIDs). Takes none, one or two colon-separated parameters: the first parameter specifies the @@ -335,7 +335,7 @@ assigned. If the first parameter is also omitted (and hence no parameter passed at all), the first UID assigned to the container is read from the owner of the root directory of the - container's directory tree. By default no user namespacing is + container's directory tree. By default, no user namespacing is applied.</para> <para>Note that user namespacing currently requires OS trees @@ -344,15 +344,15 @@ must be shifted to the container UID base that is used during container runtime.</para> - <para>It is recommended to assign as least 65536 UIDs to each + <para>It is recommended to assign at least 65536 UIDs to each container, so that the usable UID range in the container - covers 16bit. For best security do not assign overlapping UID + covers 16 bit. For best security, do not assign overlapping UID ranges to multiple containers. It is hence a good idea to use - the upper 16bit of the host 32bit UIDs as container - identifier, while the lower 16bit encode the container UID + the upper 16 bit of the host 32-bit UIDs as container + identifier, while the lower 16 bit encode the container UID used.</para> - <para>When user namespaces are used the GID range assigned to + <para>When user namespaces are used, the GID range assigned to each container is always chosen identical to the UID range.</para></listitem> </varlistentry> @@ -433,6 +433,21 @@ </varlistentry> <varlistentry> + <term><option>--network-veth-extra=</option></term> + + <listitem><para>Adds an additional virtual Ethernet link + between host and container. Takes a colon-separated pair of + host interface name and container interface name. The latter + may be omitted in which case the container and host sides will + be assigned the same name. This switch is independent of + <option>--network-veth</option>, and -- in contrast -- may be + used multiple times, and allows configuration of the network + interface names. Note that <option>--network-bridge=</option> + has no effect on interfaces created with + <option>--network-veth-extra=</option>.</para></listitem> + </varlistentry> + + <varlistentry> <term><option>--network-bridge=</option></term> <listitem><para>Adds the host side of the Ethernet link @@ -458,7 +473,7 @@ which case <literal>tcp</literal> is assumed. The container port number and its colon may be omitted, in which case the same port as the host port is implied. This option is only - supported if private networking is used, such as + supported if private networking is used, such as with <option>--network-veth</option> or <option>--network-bridge=</option>.</para></listitem> </varlistentry> @@ -575,15 +590,15 @@ <term><option>--bind-ro=</option></term> <listitem><para>Bind mount a file or directory from the host - into the container. Takes one of: a path argument -- in which + into the container. Takes one of: a path argument — in which case the specified path will be mounted from the host to the - same path in the container --, or a colon-separated pair of - paths -- in which case the first specified path is the source + same path in the container —, or a colon-separated pair of + paths — in which case the first specified path is the source in the host, and the second path is the destination in the - container --, or a colon-separated triple of source path, - destination path and mount options. Mount options are comma - separated and currently only "rbind" and "norbind" - are allowed. Defaults to "rbind". Backslash escapes are interpreted so + container —, or a colon-separated triple of source path, + destination path and mount options. Mount options are + comma-separated and currently, only "rbind" and "norbind" + are allowed. Defaults to "rbind". Backslash escapes are interpreted, so <literal>\:</literal> may be used to embed colons in either path. This option may be specified multiple times for creating multiple independent bind mount points. The @@ -599,13 +614,13 @@ mount the tmpfs instance to (in which case the directory access mode will be chosen as 0755, owned by root/root), or optionally a colon-separated pair of path and mount option - string, that is used for mounting (in which case the kernel + string that is used for mounting (in which case the kernel default for access mode and owner will be chosen, unless otherwise specified). This option is particularly useful for mounting directories such as <filename>/var</filename> as tmpfs, to allow state-less systems, in particular when combined with <option>--read-only</option>. - Backslash escapes are interpreted in the path so + Backslash escapes are interpreted in the path, so <literal>\:</literal> may be used to embed colons in the path. </para></listitem> </varlistentry> @@ -630,9 +645,9 @@ overlay file system. The left-most path is hence the lowest directory tree, the second-to-last path the highest directory tree in the stacking order. If <option>--overlay-ro=</option> - is used instead of <option>--overlay=</option> a read-only + is used instead of <option>--overlay=</option>, a read-only overlay file system is created. If a writable overlay file - system is created all changes made to it are written to the + system is created, all changes made to it are written to the highest directory tree in the stacking order, i.e. the second-to-last specified.</para> @@ -693,7 +708,7 @@ <listitem><para>Controls whether the container is registered with <citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>. - Takes a boolean argument, defaults to <literal>yes</literal>. + Takes a boolean argument, which defaults to <literal>yes</literal>. This option should be enabled when the container runs a full Operating System (more specifically: an init system), and is useful to ensure that the container is accessible via @@ -752,20 +767,20 @@ <listitem><para>Boots the container in volatile mode. When no mode parameter is passed or when mode is specified as - <option>yes</option> full volatile mode is enabled. This - means the root directory is mounted as mostly unpopulated + <option>yes</option>, full volatile mode is enabled. This + means the root directory is mounted as a mostly unpopulated <literal>tmpfs</literal> instance, and <filename>/usr</filename> from the OS tree is mounted into it, read-only (the system thus starts up with read-only OS resources, but pristine state and configuration, any changes to the either are lost on shutdown). When the mode parameter - is specified as <option>state</option> the OS tree is + is specified as <option>state</option>, the OS tree is mounted read-only, but <filename>/var</filename> is mounted as - <literal>tmpfs</literal> instance into it (the system thus + a <literal>tmpfs</literal> instance into it (the system thus starts up with read-only OS resources and configuration, but - pristine state, any changes to the latter are lost on + pristine state, and any changes to the latter are lost on shutdown). When the mode parameter is specified as - <option>no</option> (the default) the whole OS tree is made + <option>no</option> (the default), the whole OS tree is made available writable.</para> <para>Note that setting this to <option>yes</option> or @@ -786,43 +801,43 @@ special values <option>override</option> or <option>trusted</option>.</para> - <para>If enabled (the default) a settings file named after the + <para>If enabled (the default), a settings file named after the machine (as specified with the <option>--machine=</option> setting, or derived from the directory or image file name) with the suffix <filename>.nspawn</filename> is searched in <filename>/etc/systemd/nspawn/</filename> and <filename>/run/systemd/nspawn/</filename>. If it is found there, its settings are read and used. If it is not found - there it is subsequently searched in the same directory as the + there, it is subsequently searched in the same directory as the image file or in the immediate parent of the root directory of - the container. In this case, if the file is found its settings + the container. In this case, if the file is found, its settings will be also read and used, but potentially unsafe settings - are ignored. Note that in both these cases settings on the + are ignored. Note that in both these cases, settings on the command line take precedence over the corresponding settings from loaded <filename>.nspawn</filename> files, if both are specified. Unsafe settings are considered all settings that elevate the container's privileges or grant access to additional resources such as files or directories of the host. For details about the format and contents of - <filename>.nspawn</filename> files consult + <filename>.nspawn</filename> files, consult <citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> - <para>If this option is set to <option>override</option> the - file is searched, read and used the same way, however the order of + <para>If this option is set to <option>override</option>, the + file is searched, read and used the same way, however, the order of precedence is reversed: settings read from the <filename>.nspawn</filename> file will take precedence over the corresponding command line options, if both are specified.</para> - <para>If this option is set to <option>trusted</option> the + <para>If this option is set to <option>trusted</option>, the file is searched, read and used the same way, but regardless - if found in <filename>/etc/systemd/nspawn/</filename>, + of being found in <filename>/etc/systemd/nspawn/</filename>, <filename>/run/systemd/nspawn/</filename> or next to the image file or container root directory, all settings will take - effect, however command line arguments still take precedence + effect, however, command line arguments still take precedence over corresponding settings.</para> - <para>If disabled no <filename>.nspawn</filename> file is read + <para>If disabled, no <filename>.nspawn</filename> file is read and no settings except the ones on the command line are in effect.</para></listitem> </varlistentry> @@ -850,7 +865,7 @@ <example> <title>Build and boot a minimal Fedora distribution in a container</title> - <programlisting># dnf -y --releasever=21 --nogpg --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora install systemd passwd dnf fedora-release vim-minimal + <programlisting># dnf -y --releasever=23 --installroot=/srv/mycontainer --disablerepo='*' --enablerepo=fedora --enablerepo=updates install systemd passwd dnf fedora-release vim-minimal # systemd-nspawn -bD /srv/mycontainer</programlisting> <para>This installs a minimal Fedora distribution into the diff --git a/man/systemd-path.xml b/man/systemd-path.xml index 4f790d2cda..da6026e3b3 100644 --- a/man/systemd-path.xml +++ b/man/systemd-path.xml @@ -62,11 +62,11 @@ <citerefentry><refentrytitle>file-hierarchy</refentrytitle><manvolnum>7</manvolnum></citerefentry> queriable.</para> - <para>When invoked without arguments a list of known paths and + <para>When invoked without arguments, a list of known paths and their current values is shown. When at least one argument is - passed the path with this name is queried and its value shown. + passed, the path with this name is queried and its value shown. The variables whose name begins with <literal>search-</literal> - don't refer to individual paths, but instead to a list of + do not refer to individual paths, but instead to a list of colon-separated search paths, in their order of precedence.</para> </refsect1> diff --git a/man/systemd-random-seed.service.xml b/man/systemd-random-seed.service.xml index 8c836688fe..f3b5a947da 100644 --- a/man/systemd-random-seed.service.xml +++ b/man/systemd-random-seed.service.xml @@ -55,7 +55,7 @@ <title>Description</title> <para><filename>systemd-random-seed.service</filename> is a - service that restores the random seed of the system at early-boot + service that restores the random seed of the system at early boot and saves it at shutdown. See <citerefentry><refentrytitle>random</refentrytitle><manvolnum>4</manvolnum></citerefentry> for details. Saving/restoring the random seed across boots diff --git a/man/systemd-remount-fs.service.xml b/man/systemd-remount-fs.service.xml index 9bc07fcdda..176f2b2d20 100644 --- a/man/systemd-remount-fs.service.xml +++ b/man/systemd-remount-fs.service.xml @@ -55,7 +55,7 @@ <title>Description</title> <para><filename>systemd-remount-fs.service</filename> is an - early-boot service that applies mount options listed in + early boot service that applies mount options listed in <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry> to the root file system, the <filename>/usr</filename> file system, and the kernel API file systems. This is required so that the diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 96dc4f6620..43d568c6f7 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -73,9 +73,9 @@ <citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> and <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> - for details. To improve compatibility + for details. To improve compatibility, <filename>/etc/resolv.conf</filename> is read in order to discover - configured system DNS servers, however only if it is not a symlink + configured system DNS servers, but only if it is not a symlink to <filename>/run/systemd/resolve/resolv.conf</filename> (see above).</para> <para><command>systemd-resolved</command> synthesizes DNS RRs for the following cases:</para> @@ -124,10 +124,10 @@ <para>If lookups are routed to multiple interfaces, the first successful response is returned (thus effectively merging the lookup zones on all matching interfaces). If the lookup failed on - all interfaces the last failing response is returned.</para> + all interfaces, the last failing response is returned.</para> <para>Routing of lookups may be influenced by configuring - per-interface domain names, see + per-interface domain names. See <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details. Lookups for a hostname ending in one of the per-interface domains are exclusively routed to the matching diff --git a/man/systemd-run.xml b/man/systemd-run.xml index 8850735a34..414e1c8335 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -80,7 +80,7 @@ and thus shows up in the output of <command>systemctl list-units</command> like any other unit. It will run in a clean and detached execution environment, with the service manager as - its parent process. In this mode <command>systemd-run</command> + its parent process. In this mode, <command>systemd-run</command> will start the service asynchronously in the background and return after the command has begun execution.</para> @@ -239,7 +239,7 @@ <term><option>--pty</option></term> <term><option>-t</option></term> - <listitem><para>When invoking a command as service connects + <listitem><para>When invoking a command, the service connects its standard input and output to the invoking tty via a pseudo TTY device. This allows invoking binaries as services that expect interactive user input, such as interactive @@ -355,7 +355,7 @@ Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20. <para>The following command invokes the <citerefentry project='man-pages'><refentrytitle>updatedb</refentrytitle><manvolnum>8</manvolnum></citerefentry> - tool, but lowers the block IO weight for it to 10. See + tool, but lowers the block I/O weight for it to 10. See <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information on the <varname>BlockIOWeight=</varname> property.</para> diff --git a/man/systemd-sysctl.service.xml b/man/systemd-sysctl.service.xml index 2a2c7b2a13..9027ff0f3f 100644 --- a/man/systemd-sysctl.service.xml +++ b/man/systemd-sysctl.service.xml @@ -59,7 +59,7 @@ <refsect1> <title>Description</title> - <para><filename>systemd-sysctl.service</filename> is an early-boot + <para><filename>systemd-sysctl.service</filename> is an early boot service that configures <citerefentry project='man-pages'><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry> kernel parameters.</para> diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index 56db9ff17e..54ce992b85 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -109,8 +109,10 @@ <term><varname>CPUAffinity=</varname></term> <listitem><para>Configures the initial CPU affinity for the - init process. Takes a space-separated list of CPU - indices.</para></listitem> + init process. Takes a list of CPU indices or ranges separated + by either whitespace or commas. CPU ranges are specified by + the lower and upper CPU indices separated by a + dash.</para></listitem> </varlistentry> <varlistentry> @@ -340,8 +342,10 @@ resource limits for units. See <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details. Use the string <varname>infinity</varname> to - configure no limit on a specific resource. These settings may - be overridden in individual units using the corresponding + configure no limit on a specific resource. The multiplicative suffixes + K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for + resource limits measured in bytes (e.g. DefaultLimitAS=16G). These + settings may be overridden in individual units using the corresponding LimitXXX= directives. Note that these resource limits are only defaults for units, they are not applied to PID 1 itself.</para></listitem> diff --git a/man/systemd-sysusers.xml b/man/systemd-sysusers.xml index a0c0f996ac..4892caad12 100644 --- a/man/systemd-sysusers.xml +++ b/man/systemd-sysusers.xml @@ -74,7 +74,7 @@ specified in <citerefentry><refentrytitle>sysusers.d</refentrytitle><manvolnum>5</manvolnum></citerefentry> are searched for a matching file. If the string - <filename>-</filename> is specified as filenames entries from the + <filename>-</filename> is specified as filename, entries from the standard input of the process are read.</para> </refsect1> diff --git a/man/systemd-sysv-generator.xml b/man/systemd-sysv-generator.xml index f2d56cbcd2..bb5cc55e9f 100644 --- a/man/systemd-sysv-generator.xml +++ b/man/systemd-sysv-generator.xml @@ -63,7 +63,7 @@ <para><ulink url="http://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/iniscrptact.html">LSB headers</ulink> in SysV init scripts are interpreted, and the ordering specified in the header is turned into dependencies between the generated - unit and other units. LSB facilities + unit and other units. The LSB facilities <literal>$remote_fs</literal>, <literal>$network</literal>, <literal>$named</literal>, <literal>$portmap</literal>, <literal>$time</literal> are supported and will be turned into @@ -73,7 +73,7 @@ <para>SysV runlevels have corresponding systemd targets (<filename>runlevel<replaceable>X</replaceable>.target</filename>). - Wrapper unit that is generated will be wanted by those targets + The wrapper unit that is generated will be wanted by those targets which correspond to runlevels for which the script is enabled.</para> diff --git a/man/systemd-timesyncd.service.xml b/man/systemd-timesyncd.service.xml index 01ed0b8149..6ec384313b 100644 --- a/man/systemd-timesyncd.service.xml +++ b/man/systemd-timesyncd.service.xml @@ -85,7 +85,7 @@ <term><filename>/var/lib/systemd/clock</filename></term> <listitem> - <para>This file contains the timestamp of last successful + <para>This file contains the timestamp of the last successful synchronization.</para> </listitem> </varlistentry> diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml index ceec06f840..447a7eaa17 100644 --- a/man/systemd-tmpfiles.xml +++ b/man/systemd-tmpfiles.xml @@ -76,7 +76,7 @@ </para> <para>If invoked with no arguments, it applies all directives from - all configuration files. If one or more filenames are passed on + all configuration files. If one or more absolute filenames are passed on the command line, only the directives in these files are applied. If only the basename of a configuration file is specified, all configuration directories as specified in diff --git a/man/systemd-udevd.service.xml b/man/systemd-udevd.service.xml index b19b04d7cb..243fd06471 100644 --- a/man/systemd-udevd.service.xml +++ b/man/systemd-udevd.service.xml @@ -103,7 +103,7 @@ <term><option>--event-timeout=</option></term> <listitem> <para>Set the number of seconds to wait for events to finish. After - this time the event will be terminated. The default is 180 seconds.</para> + this time, the event will be terminated. The default is 180 seconds.</para> </listitem> </varlistentry> diff --git a/man/systemd-update-done.service.xml b/man/systemd-update-done.service.xml index d65f175418..a2dad39f01 100644 --- a/man/systemd-update-done.service.xml +++ b/man/systemd-update-done.service.xml @@ -58,7 +58,7 @@ service that is invoked as part of the first boot after the vendor operating system resources in <filename>/usr</filename> have been updated. This is useful to implement offline updates of - <filename>/usr</filename> which might requires updates to + <filename>/usr</filename> which might require updates to <filename>/etc</filename> or <filename>/var</filename> on the following boot.</para> diff --git a/man/systemd-user-sessions.service.xml b/man/systemd-user-sessions.service.xml index e75ef11c4e..67aba54119 100644 --- a/man/systemd-user-sessions.service.xml +++ b/man/systemd-user-sessions.service.xml @@ -57,9 +57,9 @@ <para><filename>systemd-user-sessions.service</filename> is a service that controls user logins through <citerefentry project='man-pages'><refentrytitle>pam_nologin</refentrytitle><manvolnum>8</manvolnum></citerefentry>. - After basic system initialization is complete it removes + After basic system initialization is complete, it removes <filename>/run/nologin</filename>, thus permitting logins. Before - system shutdown it creates <filename>/run/nologin</filename>, thus + system shutdown, it creates <filename>/run/nologin</filename>, thus prohibiting further logins.</para> </refsect1> diff --git a/man/systemd-vconsole-setup.service.xml b/man/systemd-vconsole-setup.service.xml index 7c6ed08997..ff079761c1 100644 --- a/man/systemd-vconsole-setup.service.xml +++ b/man/systemd-vconsole-setup.service.xml @@ -55,7 +55,7 @@ <title>Description</title> <para><filename>systemd-vconsole-setup.service</filename> is an - early-boot service that configures the virtual console font and + early boot service that configures the virtual console font and console keymap. Internally it calls <citerefentry project='mankier'><refentrytitle>loadkeys</refentrytitle><manvolnum>1</manvolnum></citerefentry> and diff --git a/man/systemd.automount.xml b/man/systemd.automount.xml index 9561590c5c..1b0ae832da 100644 --- a/man/systemd.automount.xml +++ b/man/systemd.automount.xml @@ -85,10 +85,24 @@ <para>Automount units may be used to implement on-demand mounting as well as parallelized mounting of file systems.</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> + + <para>If an automount unit is beneath another mount unit in the + file system hierarchy, both a requirement and an ordering + dependency between both units are created automatically.</para> + + <para>An implicit <varname>Before=</varname> dependency is created + between an automount unit and the mount unit it activates.</para> + + <para>Automount units acquire automatic <varname>Before=</varname> + and <varname>Conflicts=</varname> on + <filename>umount.target</filename> in order to be stopped during + shutdown, unless <varname>DefaultDependencies=no</varname> is + set.</para> - <para>If an automount point is beneath another mount point in the - file system hierarchy, a dependency between both units is created - automatically.</para> </refsect1> <refsect1> @@ -137,7 +151,7 @@ </varlistentry> <varlistentry> <term><varname>TimeoutIdleSec=</varname></term> - <listitem><para>Configures an idleness timeout. Once the mount has been + <listitem><para>Configures an idle timeout. Once the mount has been idle for the specified time, systemd will attempt to unmount. Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass 0 to disable the timeout logic. The timeout is disabled by diff --git a/man/systemd.device.xml b/man/systemd.device.xml index ac6deafb18..effed098dd 100644 --- a/man/systemd.device.xml +++ b/man/systemd.device.xml @@ -83,7 +83,18 @@ the escaping logic used to convert a file system path to a unit name see <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + </refsect1> + <refsect1> + <title>Automatic Dependencies</title> + + <para>Many unit types automatically acquire dependencies on device + units of devices they require. For example, + <filename>.socket</filename> unit acquire dependencies on the + device units of the network interface specified in + <varname>BindToDevice=</varname>. Similar, swap and mount units + acquire dependencies on the units encapsulating their backing + block devices.</para> </refsect1> <refsect1> diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index d3f56fee40..6dda6c5e69 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -77,6 +77,31 @@ </refsect1> <refsect1> + <title>Automatic Dependencies</title> + + <para>A few execution parameters result in additional, automatic + dependencies to be added.</para> + + <para>Units with <varname>WorkingDirectory=</varname> or + <varname>RootDirectory=</varname> set automatically gain + dependencies of type <varname>Requires=</varname> and + <varname>After=</varname> on all mount units required to access + the specified paths. This is equivalent to having them listed + explicitly in <varname>RequiresMountsFor=</varname>.</para> + + <para>Similar, units with <varname>PrivateTmp=</varname> enabled + automatically get mount unit dependencies for all mounts + required to access <filename>/tmp</filename> and + <filename>/var/tmp</filename>.</para> + + <para>Units whose output standard output or error output is + connected to any other sink but <option>null</option>, + <option>tty</option> and <option>socket</option> automatically + acquire dependencies of type <varname>After=</varname> on + <filename>journald.socket</filename>.</para> + </refsect1> + + <refsect1> <title>Options</title> <variablelist class='unit-directives'> @@ -86,14 +111,16 @@ <listitem><para>Takes an absolute directory path, or the special value <literal>~</literal>. Sets the working directory - for executed processes. If set to <literal>~</literal> the + for executed processes. If set to <literal>~</literal>, the home directory of the user specified in <varname>User=</varname> is used. If not set, defaults to the root directory when systemd is running as a system instance and the respective user's home directory if run as user. If the setting is prefixed with the <literal>-</literal> character, a missing working directory is not considered - fatal.</para></listitem> + fatal. Note that setting this parameter might result in + additional dependencies to be added to the unit (see + above).</para></listitem> </varlistentry> <varlistentry> @@ -104,7 +131,9 @@ project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call. If this is used, it must be ensured that the process binary and all its auxiliary files are available in - the <function>chroot()</function> jail.</para></listitem> + the <function>chroot()</function> jail. Note that setting this + parameter might result in additional dependencies to be added + to the unit (see above).</para></listitem> </varlistentry> <varlistentry> @@ -123,8 +152,8 @@ <listitem><para>Sets the supplementary Unix groups the processes are executed as. This takes a space-separated list of group names or IDs. This option may be specified more than - once in which case all listed groups are set as supplementary - groups. When the empty string is assigned the list of + once, in which case all listed groups are set as supplementary + groups. When the empty string is assigned, the list of supplementary groups is reset, and all assignments prior to this one will have no effect. In any way, this option does not override, but extends the list of supplementary groups @@ -157,7 +186,7 @@ <varlistentry> <term><varname>IOSchedulingClass=</varname></term> - <listitem><para>Sets the IO scheduling class for executed + <listitem><para>Sets the I/O scheduling class for executed processes. Takes an integer between 0 and 3 or one of the strings <option>none</option>, <option>realtime</option>, <option>best-effort</option> or <option>idle</option>. See @@ -168,10 +197,10 @@ <varlistentry> <term><varname>IOSchedulingPriority=</varname></term> - <listitem><para>Sets the IO scheduling priority for executed + <listitem><para>Sets the I/O scheduling priority for executed processes. Takes an integer between 0 (highest priority) and 7 (lowest priority). The available priorities depend on the - selected IO scheduling class (see above). See + selected I/O scheduling class (see above). See <citerefentry><refentrytitle>ioprio_set</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details.</para></listitem> </varlistentry> @@ -217,8 +246,10 @@ <term><varname>CPUAffinity=</varname></term> <listitem><para>Controls the CPU affinity of the executed - processes. Takes a space-separated list of CPU indices. This - option may be specified more than once in which case the + processes. Takes a list of CPU indices or ranges separated by + either whitespace or commas. CPU ranges are specified by the + lower and upper CPU indices separated by a dash. + This option may be specified more than once, in which case the specified CPU affinity masks are merged. If the empty string is assigned, the mask is reset, all assignments prior to this will have no effect. See @@ -240,7 +271,7 @@ <listitem><para>Sets environment variables for executed processes. Takes a space-separated list of variable - assignments. This option may be specified more than once in + assignments. This option may be specified more than once, in which case all listed variables will be set. If the same variable is set twice, the later setting will override the earlier setting. If the empty string is assigned to this @@ -301,6 +332,33 @@ </varlistentry> <varlistentry> + <term><varname>PassEnvironment=</varname></term> + + <listitem><para>Pass environment variables from the systemd system + manager to executed processes. Takes a space-separated list of variable + names. This option may be specified more than once, in which case all + listed variables will be set. If the empty string is assigned to this + option, the list of environment variables is reset, all prior + assignments have no effect. Variables that are not set in the system + manager will not be passed and will be silently ignored.</para> + + <para>Variables passed from this setting are overridden by those passed + from <varname>Environment=</varname> or + <varname>EnvironmentFile=</varname>.</para> + + <para>Example: + <programlisting>PassEnvironment=VAR1 VAR2 VAR3</programlisting> + passes three variables <literal>VAR1</literal>, + <literal>VAR2</literal>, <literal>VAR3</literal> + with the values set for those variables in PID1.</para> + + <para> + See + <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> + for details about environment variables.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>StandardInput=</varname></term> <listitem><para>Controls where file descriptor 0 (STDIN) of the executed processes is connected to. Takes one of @@ -349,6 +407,7 @@ <para>This setting defaults to <option>null</option>.</para></listitem> </varlistentry> + <varlistentry> <term><varname>StandardOutput=</varname></term> <listitem><para>Controls where file descriptor 1 (STDOUT) of @@ -414,8 +473,11 @@ <para>This setting defaults to the value set with <option>DefaultStandardOutput=</option> in <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - which defaults to <option>journal</option>.</para></listitem> + which defaults to <option>journal</option>. Note that setting + this parameter might result in additional dependencies to be + added to the unit (see above).</para></listitem> </varlistentry> + <varlistentry> <term><varname>StandardError=</varname></term> <listitem><para>Controls where file descriptor 2 (STDERR) of @@ -426,8 +488,11 @@ standard error. This setting defaults to the value set with <option>DefaultStandardError=</option> in <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - which defaults to <option>inherit</option>.</para></listitem> + which defaults to <option>inherit</option>. Note that setting + this parameter might result in additional dependencies to be + added to the unit (see above).</para></listitem> </varlistentry> + <varlistentry> <term><varname>TTYPath=</varname></term> <listitem><para>Sets the terminal device node to use if @@ -491,7 +556,7 @@ </varlistentry> <varlistentry> <term><varname>SyslogLevel=</varname></term> - <listitem><para>Default syslog level to use when logging to + <listitem><para>The default syslog level to use when logging to syslog or the kernel log buffer. One of <option>emerg</option>, <option>alert</option>, @@ -510,7 +575,7 @@ different log level which can be used to override the default log level specified here. The interpretation of these prefixes may be disabled with <varname>SyslogLevelPrefix=</varname>, - see below. For details see + see below. For details, see <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Defaults to @@ -566,88 +631,133 @@ of various resources for executed processes. See <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details. Use the string <varname>infinity</varname> to - configure no limit on a specific resource.</para></listitem> + configure no limit on a specific resource. The multiplicative + suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E + may be used for resource limits measured in bytes + (e.g. LimitAS=16G). For the limits referring to time values, + the usual time units ms, s, min, h and so on may be used (see + <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> + for details). Note that if no time unit is specified for + <varname>LimitCPU=</varname> the default unit of seconds is + implied, while for <varname>LimitRTTIME=</varname> the default + unit of microseconds is implied. Also, note that the effective + granularity of the limits might influence their + enforcement. For example, time limits specified for + <varname>LimitCPU=</varname> will be rounded up implicitly to + multiples of 1s.</para> + + <para>Note that most process resource limits configured with + these options are per-process, and processes may fork in order + to acquire a new set of resources that are accounted + independently of the original process, and may thus escape + limits set. Also note that <varname>LimitRSS=</varname> is not + implemented on Linux, and setting it has no effect. Often it + is advisable to prefer the resource controls listed in + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> + over these per-process limits, as they apply to services as a + whole, may be altered dynamically at runtime, and are + generally more expressive. For example, + <varname>MemoryLimit=</varname> is a more powerful (and + working) replacement for <varname>LimitRSS=</varname>.</para> <table> <title>Limit directives and their equivalent with ulimit</title> - <tgroup cols='2'> + <tgroup cols='3'> <colspec colname='directive' /> <colspec colname='equivalent' /> + <colspec colname='unit' /> <thead> <row> <entry>Directive</entry> <entry>ulimit equivalent</entry> + <entry>Unit</entry> </row> </thead> <tbody> <row> - <entry>LimitCPU</entry> + <entry>LimitCPU=</entry> <entry>ulimit -t</entry> + <entry>Seconds</entry> </row> <row> - <entry>LimitFSIZE</entry> + <entry>LimitFSIZE=</entry> <entry>ulimit -f</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitDATA</entry> + <entry>LimitDATA=</entry> <entry>ulimit -d</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitSTACK</entry> + <entry>LimitSTACK=</entry> <entry>ulimit -s</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitCORE</entry> + <entry>LimitCORE=</entry> <entry>ulimit -c</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitRSS</entry> + <entry>LimitRSS=</entry> <entry>ulimit -m</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitNOFILE</entry> + <entry>LimitNOFILE=</entry> <entry>ulimit -n</entry> + <entry>Number of File Descriptors</entry> </row> <row> - <entry>LimitAS</entry> + <entry>LimitAS=</entry> <entry>ulimit -v</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitNPROC</entry> + <entry>LimitNPROC=</entry> <entry>ulimit -u</entry> + <entry>Number of Processes</entry> </row> <row> - <entry>LimitMEMLOCK</entry> + <entry>LimitMEMLOCK=</entry> <entry>ulimit -l</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitLOCKS</entry> + <entry>LimitLOCKS=</entry> <entry>ulimit -x</entry> + <entry>Number of Locks</entry> </row> <row> - <entry>LimitSIGPENDING</entry> + <entry>LimitSIGPENDING=</entry> <entry>ulimit -i</entry> + <entry>Number of Queued Signals</entry> </row> <row> - <entry>LimitMSGQUEUE</entry> + <entry>LimitMSGQUEUE=</entry> <entry>ulimit -q</entry> + <entry>Bytes</entry> </row> <row> - <entry>LimitNICE</entry> + <entry>LimitNICE=</entry> <entry>ulimit -e</entry> + <entry>Nice Level</entry> </row> <row> - <entry>LimitRTPRIO</entry> + <entry>LimitRTPRIO=</entry> <entry>ulimit -r</entry> + <entry>Realtime Priority</entry> </row> <row> - <entry>LimitRTTIME</entry> + <entry>LimitRTTIME=</entry> <entry>No equivalent</entry> + <entry>Microseconds</entry> </row> </tbody> </tgroup> - </table> + </table></listitem> </varlistentry> <varlistentry> @@ -683,7 +793,7 @@ of what <varname>Capabilities=</varname> does. If this option is not used, the capability bounding set is not modified on process execution, hence no limits on the capabilities of the - process are enforced. This option may appear more than once in + process are enforced. This option may appear more than once, in which case the bounding sets are merged. If the empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior settings have no effect. @@ -704,7 +814,7 @@ <option>no-setuid-fixup-locked</option>, <option>noroot</option>, and <option>noroot-locked</option>. - This option may appear more than once in which case the secure + This option may appear more than once, in which case the secure bits are ORed. If the empty string is assigned to this option, the bits are reset to 0. See <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry> @@ -745,7 +855,7 @@ inaccessible for processes inside the namespace. Note that restricting access with these options does not extend to submounts of a directory that are created later on. These - options may be specified more than once in which case all + options may be specified more than once, in which case all directories listed will have limited access from within the namespace. If the empty string is assigned to this option, the specific list is reset, and all prior assignments have no @@ -848,7 +958,7 @@ directories read-only for processes invoked by this unit. If set to <literal>full</literal>, the <filename>/etc</filename> directory is mounted read-only, too. This setting ensures that - any modification of the vendor supplied operating system (and + any modification of the vendor-supplied operating system (and optionally its configuration) is prohibited for the service. It is recommended to enable this setting for all long-running services, unless they are involved with system updates or need @@ -949,15 +1059,15 @@ invoked process must implement a <command>getty</command>-compatible utmp/wtmp logic. If <literal>login</literal> is set, first an - <constant>INIT_PROCESS</constant> entry, followed by an + <constant>INIT_PROCESS</constant> entry, followed by a <constant>LOGIN_PROCESS</constant> entry is generated. In - this case the invoked process must implement a <citerefentry + this case, the invoked process must implement a <citerefentry project='die-net'><refentrytitle>login</refentrytitle><manvolnum>1</manvolnum></citerefentry>-compatible utmp/wtmp logic. If <literal>user</literal> is set, first an <constant>INIT_PROCESS</constant> entry, then a - <constant>LOGIN_PROCESS</constant> entry and finally an + <constant>LOGIN_PROCESS</constant> entry and finally a <constant>USER_PROCESS</constant> entry is generated. In this - case the invoked process may be any process that is suitable + case, the invoked process may be any process that is suitable to be run as session leader. Defaults to <literal>init</literal>.</para></listitem> </varlistentry> @@ -992,7 +1102,7 @@ <listitem><para>Takes a <option>SMACK64</option> security label as argument. The process executed by the unit will be started under this label and SMACK will decide whether the - processes is allowed to run or not based on it. The process + process is allowed to run or not, based on it. The process will continue to run under the label specified here unless the executable has its own <option>SMACK64EXEC</option> label, in which case the process will transition to run under that @@ -1048,7 +1158,7 @@ <function>sigreturn</function>, <function>exit_group</function>, <function>exit</function> system calls are implicitly whitelisted and do not need to be - listed explicitly. This option may be specified more than once + listed explicitly. This option may be specified more than once, in which case the filter masks are merged. If the empty string is assigned, the filter is reset, all prior assignments will have no effect.</para> @@ -1084,7 +1194,7 @@ <varlistentry> <term><varname>SystemCallArchitectures=</varname></term> - <listitem><para>Takes a space separated list of architecture + <listitem><para>Takes a space-separated list of architecture identifiers to include in the system call filter. The known architecture identifiers are <constant>x86</constant>, <constant>x86-64</constant>, <constant>x32</constant>, @@ -1316,6 +1426,7 @@ <citerefentry><refentrytitle>systemd.mount</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>exec</refentrytitle><manvolnum>3</manvolnum></citerefentry> diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml index 4514c1afdf..b36aab3259 100644 --- a/man/systemd.generator.xml +++ b/man/systemd.generator.xml @@ -87,7 +87,7 @@ dynamically into native unit files.</para> <para>Generators are loaded from a set of paths determined during - compilation, listed above. System and user generators are loaded + compilation, as listed above. System and user generators are loaded from directories with names ending in <filename>system-generators/</filename> and <filename>user-generators/</filename>, respectively. Generators @@ -96,7 +96,7 @@ <filename>/dev/null</filename> or an empty file can be used to mask a generator, thereby preventing it from running. Please note that the order of the two directories with the highest priority is - reversed with respect to the unit load path and generators in + reversed with respect to the unit load path, and generators in <filename>/run</filename> overwrite those in <filename>/etc</filename>.</para> @@ -169,14 +169,14 @@ or <command>systemd</command> itself (this means: no <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>!). They can however rely on the most basic kernel functionality to - be available, including mounted <filename>/sys</filename>, + be available, including a mounted <filename>/sys</filename>, <filename>/proc</filename>, <filename>/dev</filename>. </para> </listitem> <listitem> <para> - Units written by generators are removed when configuration + Units written by generators are removed when the configuration is reloaded. That means the lifetime of the generated units is closely bound to the reload cycles of <command>systemd</command> itself. @@ -187,9 +187,9 @@ <para> Generators should only be used to generate unit files, not any other kind of configuration. Due to the lifecycle - logic mentioned above generators are not a good fit to + logic mentioned above, generators are not a good fit to generate dynamic configuration for other services. If you - need to generate dynamic configuration for other services + need to generate dynamic configuration for other services, do so in normal services you order before the service in question. </para> @@ -199,7 +199,7 @@ <para> Since <citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry> - is not available (see above) log messages have to be + is not available (see above), log messages have to be written to <filename>/dev/kmsg</filename> instead. </para> </listitem> @@ -221,19 +221,19 @@ Generators may write out dynamic unit files or just hook unit files into other units with the usual <filename>.wants/</filename> or - <filename>.requires/</filename> symlinks. Often it is + <filename>.requires/</filename> symlinks. Often, it is nicer to simply instantiate a template unit file from <filename>/usr</filename> with a generator instead of - writing out entirely dynamic unit files. Of course this + writing out entirely dynamic unit files. Of course, this works only if a single parameter is to be used. </para> </listitem> <listitem> <para> - If you are careful you can implement generators in shell + If you are careful, you can implement generators in shell scripts. We do recommend C code however, since generators - delay are executed synchronously and hence delay the + are executed synchronously and hence delay the entire boot if they are slow. </para> </listitem> @@ -269,7 +269,7 @@ <para> Instead of heading off now and writing all kind of generators for legacy configuration file formats, please - think twice! It's often a better idea to just deprecate + think twice! It is often a better idea to just deprecate old stuff instead of keeping it artificially alive. </para> </listitem> @@ -308,7 +308,7 @@ temporarily redirects <filename>default.target</filename> to <filename>system-update.target</filename> if a system update is scheduled. Since this needs to override the default user - configuration for <filename>default.target</filename> it uses + configuration for <filename>default.target</filename>, it uses argv[2]. For details about this logic, see <ulink url="http://www.freedesktop.org/wiki/Software/systemd/SystemUpdates">Implementing Offline System Updates</ulink>.</para> diff --git a/man/systemd.kill.xml b/man/systemd.kill.xml index 1292f4f513..13b7ab14df 100644 --- a/man/systemd.kill.xml +++ b/man/systemd.kill.xml @@ -138,8 +138,8 @@ <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>. Defaults to <constant>SIGTERM</constant>. </para> - <para>Note that right after sending the signal specified in - this setting systemd will always send + <para>Note that, right after sending the signal specified in + this setting, systemd will always send <constant>SIGCONT</constant>, to ensure that even suspended tasks can be terminated cleanly.</para> </listitem> diff --git a/man/systemd.link.xml b/man/systemd.link.xml index 7745260a39..a9f8a654c8 100644 --- a/man/systemd.link.xml +++ b/man/systemd.link.xml @@ -1,4 +1,4 @@ -<?xml version='1.0'?> <!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> @@ -70,7 +70,7 @@ name in <filename>/usr/lib</filename>. This can be used to override a system-supplied link file with a local file if needed. As a special case, an empty file (file size 0) or symlink with the - same name pointing to <filename>/dev/null</filename>, disable the + same name pointing to <filename>/dev/null</filename> disables the configuration file entirely (it is "masked").</para> <para>The link file contains a <literal>[Match]</literal> section, @@ -217,8 +217,8 @@ generated which is guaranteed to be the same on every boot for the given machine and the given device, but which is otherwise random. This feature depends on ID_NET_NAME_* - properties existing for the link, on hardware where these - properties are not set the generation of a persistent MAC address + properties to exist for the link. On hardware where these + properties are not set, the generation of a persistent MAC address will fail.</para> </listitem> </varlistentry> @@ -228,7 +228,7 @@ <para>If the kernel is using a random MAC address, nothing is done. Otherwise, a new address is randomly generated each time the device appears, typically at - boot. Either way the random address will have the + boot. Either way, the random address will have the <literal>unicast</literal> and <literal>locally administered</literal> bits set.</para> </listitem> @@ -387,10 +387,53 @@ </refsect1> <refsect1> - <title>Example</title> + <title>Examples</title> + + <example> + <title>/usr/lib/systemd/network/99-default.link</title> + + <para>The link file <filename>99-default.link</filename> that is + shipped with systemd defines the default naming policy for + links.</para> + + <programlisting>[Link] +NamePolicy=kernel database onboard slot path +MACAddressPolicy=persistent</programlisting> + </example> + + <example> + <title>/etc/systemd/network/10-dmz.link</title> + + <para>This example assigns the fixed name + <literal>dmz0</literal> to the interface with the MAC address + 00:a0:de:63:7a:e6:</para> + + <programlisting>[Match] +MACAddress=00:a0:de:63:7a:e6 + +[Link] +Name=dmz0</programlisting> + </example> + + <example> + <title>/etc/systemd/network/10-internet.link</title> + + <para>This example assigns the fixed name + <literal>internet0</literal> to the interface with the device + path <literal>pci-0000:00:1a.0-*</literal>:</para> + + <programlisting>[Match] +Path=pci-0000:00:1a.0-* + +[Link] +Name=internet0</programlisting> + </example> + <example> <title>/etc/systemd/network/25-wireless.link</title> + <para>Here's an overly complex example that shows the use of a large number of [Match] and [Link] settings.</para> + <programlisting>[Match] MACAddress=12:34:56:78:9a:bc Driver=brcmsmac diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index ffffc56936..a724d88584 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -94,10 +94,6 @@ unit, to allow on-demand or parallelized mounting. See <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> - <para>If a mount point is beneath another mount point in the file - system hierarchy, a dependency between both units is created - automatically.</para> - <para>Mount points created at runtime (independently of unit files or <filename>/etc/fstab</filename>) will be monitored by systemd and appear like any other mount unit in systemd. See @@ -114,6 +110,52 @@ </refsect1> <refsect1> + <title>Automatic Dependencies</title> + + <para>If a mount unit is beneath another mount unit in the file + system hierarchy, both a requirement dependency and an ordering + dependency between both units are created automatically.</para> + + <para>Block device backed file systems automatically gain + <varname>BindsTo=</varname> and <varname>After=</varname> type + dependencies on the device unit encapsulating the block + device (see below).</para> + + <para>If traditional file system quota is enabled for a mount + unit, automatic <varname>Wants=</varname> and + <varname>Before=</varname> dependencies on + <filename>systemd-quotacheck.service</filename> and + <filename>quotaon.service</filename> are added.</para> + + <para>For mount units with + <varname>DefaultDependencies=yes</varname> (the default) a couple + additional dependencies are added. Mount units referring to local + file systems automatically gain an <varname>After=</varname> + dependency on <filename>local-fs-pre.target</filename>. Network + mount units automatically acquire <varname>After=</varname> + dependencies on <filename>remote-fs-pre.target</filename>, + <filename>network.target</filename> and + <filename>network-online.target</filename>. Towards the latter a + <varname>Wants=</varname> unit is added as well. Mount units + referring to local and network file systems are distinguished by + their file system type specification. In some cases this is not + sufficient (for example network block device based mounts, such as + iSCSI), in which case <option>_netdev</option> may be added to the + mount option string of the unit, which forces systemd to consider the + mount unit a network mount. Mount units (regardless if local or + network) also acquire automatic <varname>Before=</varname> and + <varname>Conflicts=</varname> on + <filename>umount.target</filename> in order to be stopped + during shutdown.</para> + + <para>Additional implicit dependencies may be added as result of + execution and resource control parameters as documented in + <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> + and + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + </refsect1> + + <refsect1> <title><filename>fstab</filename></title> <para>Mount units may either be configured via unit files, or via @@ -130,7 +172,7 @@ <para>When reading <filename>/etc/fstab</filename> a few special mount options are understood by systemd which influence how dependencies are created for mount points. systemd will create a - dependency of type <option>Wants</option> or + dependency of type <varname>Wants=</varname> or <option>Requires</option> (see option <option>nofail</option> below), from either <filename>local-fs.target</filename> or <filename>remote-fs.target</filename>, depending whether the file @@ -180,7 +222,7 @@ <varlistentry> <term><option>x-systemd.idle-timeout=</option></term> - <listitem><para>Configures the idleness timeout of the + <listitem><para>Configures the idle timeout of the automount unit. See <varname>TimeoutIdleSec=</varname> in <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details.</para></listitem> @@ -192,13 +234,13 @@ <listitem><para>Configure how long systemd should wait for a device to show up before giving up on an entry from <filename>/etc/fstab</filename>. Specify a time in seconds or - explicitly append a unit as <literal>s</literal>, + explicitly append a unit such as <literal>s</literal>, <literal>min</literal>, <literal>h</literal>, <literal>ms</literal>.</para> <para>Note that this option can only be used in <filename>/etc/fstab</filename>, and will be - ignored when part of <varname>Options=</varname> + ignored when part of the <varname>Options=</varname> setting in a unit file.</para> </listitem> </varlistentry> @@ -212,7 +254,7 @@ <filename>local-fs.target</filename> or <filename>remote-fs.target</filename>. This means that it will not be mounted automatically during boot, unless it is pulled - in by some other unit. Option <option>auto</option> has the + in by some other unit. The <option>auto</option> option has the opposite meaning and is the default.</para> </listitem> </varlistentry> @@ -220,7 +262,7 @@ <varlistentry> <term><option>nofail</option></term> - <listitem><para>With <option>nofail</option> this mount will + <listitem><para>With <option>nofail</option>, this mount will be only wanted, not required, by <filename>local-fs.target</filename> or <filename>remote-fs.target</filename>. This means that the diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 70311ca9d9..16e41e05b3 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -81,8 +81,8 @@ name in <filename>/usr/lib</filename>. This can be used to override a system-supplied configuration file with a local file if needed. As a special case, an empty file (file size 0) or symlink - with the same name pointing to <filename>/dev/null</filename>, - disable the configuration file entirely (it is "masked").</para> + with the same name pointing to <filename>/dev/null</filename> + disables the configuration file entirely (it is "masked").</para> </refsect1> <refsect1> @@ -106,7 +106,7 @@ <entry>A bond device is an aggregation of all its slave devices. See <ulink url="https://www.kernel.org/doc/Documentation/networking/bonding.txt">Linux Ethernet Bonding Driver HOWTO</ulink> for details.Local configuration</entry></row> <row><entry><varname>bridge</varname></entry> - <entry>A bridge device is a software switch, each of its slave devices and the bridge itself are ports of the switch.</entry></row> + <entry>A bridge device is a software switch, and each of its slave devices and the bridge itself are ports of the switch.</entry></row> <row><entry><varname>dummy</varname></entry> <entry>A dummy device drops all packets sent to it.</entry></row> @@ -148,7 +148,7 @@ <entry>A persistent Level 3 tunnel between a network device and a device node.</entry></row> <row><entry><varname>veth</varname></entry> - <entry>An ethernet tunnel between a pair of network devices.</entry></row> + <entry>An Ethernet tunnel between a pair of network devices.</entry></row> <row><entry><varname>vlan</varname></entry> <entry>A VLAN is a stacked device which receives packets from its underlying device based on VLAN tagging. See <ulink url="http://www.ieee802.org/1/pages/802.1Q.html">IEEE 802.1Q</ulink> for details.</entry></row> @@ -282,13 +282,13 @@ <para>The <literal>[Bridge]</literal> section only applies for netdevs of kind <literal>bridge</literal>, and accepts the - following key:</para> + following keys:</para> <variablelist class='network-directives'> <varlistentry> <term><varname>HelloTimeSec=</varname></term> <listitem> - <para>HelloTimeSec specifies the number of seconds a hello packet is + <para>HelloTimeSec specifies the number of seconds between two hello packets sent out by the root bridge and the designated bridges. Hello packets are used to communicate information about the topology throughout the entire bridged local area network.</para> @@ -414,7 +414,7 @@ <term><varname>TTL=</varname></term> <listitem> <para>A fixed Time To Live N on Virtual eXtensible Local - Area Network packets. N is a number in the range 1-255. 0 + Area Network packets. N is a number in the range 1–255. 0 is a special value meaning that packets inherit the TTL value.</para> </listitem> @@ -430,13 +430,19 @@ <term><varname>FDBAgeingSec=</varname></term> <listitem> <para>The lifetime of Forwarding Database entry learnt by - the kernel in seconds.</para> + the kernel, in seconds.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>MaximumFDBEntries=</varname></term> + <listitem> + <para>Configures maximum number of FDB entries.</para> </listitem> </varlistentry> <varlistentry> <term><varname>ARPProxy=</varname></term> <listitem> - <para>A boolean. When true, enables ARP proxy.</para> + <para>A boolean. When true, enables ARP proxying.</para> </listitem> </varlistentry> <varlistentry> @@ -449,40 +455,40 @@ <varlistentry> <term><varname>L3MissNotification=</varname></term> <listitem> - <para>A boolean. When true, enables netlink IP ADDR miss + <para>A boolean. When true, enables netlink IP address miss notifications.</para> </listitem> </varlistentry> <varlistentry> <term><varname>RouteShortCircuit=</varname></term> <listitem> - <para>A boolean. When true route short circuit is turned + <para>A boolean. When true, route short circuiting is turned on.</para> </listitem> </varlistentry> <varlistentry> <term><varname>UDPCheckSum=</varname></term> <listitem> - <para>A boolean. When true transmitting UDP checksums when doing VXLAN/IPv4 is turned on.</para> + <para>A boolean. When true, transmitting UDP checksums when doing VXLAN/IPv4 is turned on.</para> </listitem> </varlistentry> <varlistentry> <term><varname>UDP6ZeroChecksumTx=</varname></term> <listitem> - <para>A boolean. When true sending zero checksums in VXLAN/IPv6 is turned on.</para> + <para>A boolean. When true, sending zero checksums in VXLAN/IPv6 is turned on.</para> </listitem> </varlistentry> <varlistentry> <term><varname>UDP6ZeroCheckSumRx=</varname></term> <listitem> - <para>A boolean. When true receiving zero checksums in VXLAN/IPv6 is turned on.</para> + <para>A boolean. When true, receiving zero checksums in VXLAN/IPv6 is turned on.</para> </listitem> </varlistentry> <varlistentry> <term><varname>GroupPolicyExtension=</varname></term> <listitem> - <para>A boolean. When true it enables Group Policy VXLAN extension security label mechanism - across network peers based on VXLAN. For details about the Group Policy VXLAN see the + <para>A boolean. When true, it enables Group Policy VXLAN extension security label mechanism + across network peers based on VXLAN. For details about the Group Policy VXLAN, see the <ulink url="https://tools.ietf.org/html/draft-smith-vxlan-group-policy"> VXLAN Group Policy </ulink> document. Defaults to false.</para> </listitem> @@ -523,7 +529,7 @@ <term><varname>TOS=</varname></term> <listitem> <para>The Type Of Service byte value for a tunnel interface. - For details about the TOS see the + For details about the TOS, see the <ulink url="http://tools.ietf.org/html/rfc1349"> Type of Service in the Internet Protocol Suite </ulink> document. </para> @@ -533,9 +539,9 @@ <term><varname>TTL=</varname></term> <listitem> <para>A fixed Time To Live N on tunneled packets. N is a - number in the range 1-255. 0 is a special value meaning that + number in the range 1–255. 0 is a special value meaning that packets inherit the TTL value. The default value for IPv4 - tunnels is: inherit. The default value for IPv6 tunnels is: + tunnels is: inherit. The default value for IPv6 tunnels is 64.</para> </listitem> </varlistentry> @@ -549,14 +555,14 @@ <varlistentry> <term><varname>IPv6FlowLabel=</varname></term> <listitem> - <para>Configures The 20-bit Flow Label (see <ulink url="https://tools.ietf.org/html/rfc6437"> + <para>Configures the 20-bit flow label (see <ulink url="https://tools.ietf.org/html/rfc6437"> RFC 6437</ulink>) field in the IPv6 header (see <ulink url="https://tools.ietf.org/html/rfc2460"> - RFC 2460</ulink>), is used by a node to label packets of a flow. - It's only used for IPv6 Tunnels. - A Flow Label of zero is used to indicate packets that have - not been labeled. Takes following values. - When <literal>inherit</literal> it uses the original flowlabel, - or can be configured to any value between 0 to 0xFFFFF.</para> + RFC 2460</ulink>), which is used by a node to label packets of a flow. + It is only used for IPv6 tunnels. + A flow label of zero is used to indicate packets that have + not been labeled. + It can be configured to a value in the range 0–0xFFFFF, or be + set to <literal>inherit</literal>, in which case the original flowlabel is used.</para> </listitem> </varlistentry> <varlistentry> @@ -580,14 +586,14 @@ value of zero means that a packet carrying that option may not enter another tunnel before exiting the current tunnel. (see <ulink url="https://tools.ietf.org/html/rfc2473#section-4.1.1"> RFC 2473</ulink>). - The valid range is 0-255 and <literal>none</literal>. Defaults to 4. + The valid range is 0–255 and <literal>none</literal>. Defaults to 4. </para> </listitem> </varlistentry> <varlistentry> <term><varname>Mode=</varname></term> <listitem> - <para>An <literal>ip6tnl</literal> tunnels can have three + <para>An <literal>ip6tnl</literal> tunnel can be in one of three modes <literal>ip6ip6</literal> for IPv6 over IPv6, <literal>ipip6</literal> for IPv4 over IPv6 or @@ -602,7 +608,7 @@ <para>The <literal>[Peer]</literal> section only applies for netdevs of kind <literal>veth</literal> and accepts the - following key:</para> + following keys:</para> <variablelist class='network-directives'> <varlistentry> @@ -615,7 +621,7 @@ <varlistentry> <term><varname>MACAddress=</varname></term> <listitem> - <para>The peer MACAddress, if not set it is generated in + <para>The peer MACAddress, if not set, it is generated in the same way as the MAC address of the main interface.</para> </listitem> @@ -651,7 +657,7 @@ <term><varname>PacketInfo=</varname></term> <listitem><para>Takes a boolean argument. Configures whether packets should be prepended with four extra bytes (two flag - bytes and two protocol bytes). If disabled it indicates that + bytes and two protocol bytes). If disabled, it indicates that the packets will be pure IP packets. Defaults to <literal>no</literal>.</para> </listitem> @@ -777,9 +783,9 @@ <term><varname>LearnPacketIntervalSec=</varname></term> <listitem> <para>Specifies the number of seconds between instances where the bonding - driver sends learning packets to each slaves peer switch. - The valid range is 1 - 0x7fffffff; the default value is 1. This Option - has effect only in balance-tlb and balance-alb modes.</para> + driver sends learning packets to each slave peer switch. + The valid range is 1–0x7fffffff; the default value is 1. This option + has an effect only for the balance-tlb and balance-alb modes.</para> </listitem> </varlistentry> @@ -788,8 +794,8 @@ <listitem> <para>Specifies the 802.3ad aggregation selection logic to use. Possible values are <literal>stable</literal>, - <literal>bandwidth</literal>, - <literal>count</literal> + <literal>bandwidth</literal> and + <literal>count</literal>. </para> </listitem> </varlistentry> @@ -797,13 +803,13 @@ <varlistentry> <term><varname>FailOverMACPolicy=</varname></term> <listitem> - <para>Specifies whether active-backup mode should set all slaves to - the same MAC address at enslavement or, when enabled, perform special handling of the + <para>Specifies whether the active-backup mode should set all slaves to + the same MAC address at the time of enslavement or, when enabled, to perform special handling of the bond's MAC address in accordance with the selected policy. The default policy is none. Possible values are <literal>none</literal>, - <literal>active</literal>, - <literal>follow</literal> + <literal>active</literal> and + <literal>follow</literal>. </para> </listitem> </varlistentry> @@ -817,8 +823,8 @@ monitoring purposes. Possible values are <literal>none</literal>, <literal>active</literal>, - <literal>backup</literal>, - <literal>all</literal> + <literal>backup</literal> and + <literal>all</literal>. </para> </listitem> </varlistentry> @@ -838,7 +844,7 @@ <para>Specifies the IP addresses to use as ARP monitoring peers when ARPIntervalSec is greater than 0. These are the targets of the ARP request sent to determine the health of the link to the targets. - Specify these values in ipv4 dotted decimal format. At least one IP + Specify these values in IPv4 dotted decimal format. At least one IP address must be given for ARP monitoring to function. The maximum number of targets that can be specified is 16. The default value is no IP addresses. @@ -853,8 +859,8 @@ in order for the ARP monitor to consider a slave as being up. This option affects only active-backup mode for slaves with ARPValidate enabled. Possible values are - <literal>any</literal>, - <literal>all</literal> + <literal>any</literal> and + <literal>all</literal>. </para> </listitem> </varlistentry> @@ -868,8 +874,8 @@ occurs. This option is designed to prevent flip-flopping between the primary slave and other slaves. Possible values are <literal>always</literal>, - <literal>better</literal>, - <literal>failure</literal> + <literal>better</literal> and + <literal>failure</literal>. </para> </listitem> </varlistentry> @@ -880,7 +886,7 @@ <para>Specifies the number of IGMP membership reports to be issued after a failover event. One membership report is issued immediately after the failover, subsequent packets are sent in each 200ms interval. - The valid range is (0 - 255). Defaults to 1. A value of 0 + The valid range is 0–255. Defaults to 1. A value of 0 prevents the IGMP membership report from being issued in response to the failover event. </para> @@ -890,10 +896,10 @@ <varlistentry> <term><varname>PacketsPerSlave=</varname></term> <listitem> - <para> Specify the number of packets to transmit through a slave before - moving to the next one. When set to 0 then a slave is chosen at - random. The valid range is (0 - 65535). Defaults to 1. This option - has effect only in balance-rr mode. + <para>Specify the number of packets to transmit through a slave before + moving to the next one. When set to 0, then a slave is chosen at + random. The valid range is 0–65535. Defaults to 1. This option + only has effect when in balance-rr mode. </para> </listitem> </varlistentry> @@ -903,11 +909,11 @@ <listitem> <para>Specify the number of peer notifications (gratuitous ARPs and unsolicited IPv6 Neighbor Advertisements) to be issued after a - failover event. As soon as the link is up on the new slave + failover event. As soon as the link is up on the new slave, a peer notification is sent on the bonding device and each VLAN sub-device. This is repeated at each link monitor interval (ARPIntervalSec or MIIMonitorSec, whichever is active) if the number is - greater than 1. The valid range is (0 - 255). Default value is 1. + greater than 1. The valid range is 0–255. The default value is 1. These options affect only the active-backup mode. </para> </listitem> @@ -916,8 +922,8 @@ <varlistentry> <term><varname>AllSlavesActive=</varname></term> <listitem> - <para> A boolean. Specifies that duplicate frames (received on inactive ports) - should be dropped false or delivered true. Normally, bonding will drop + <para>A boolean. Specifies that duplicate frames (received on inactive ports) + should be dropped when false, or delivered when true. Normally, bonding will drop duplicate frames (received on inactive ports), which is desirable for most users. But there are some times it is nice to allow duplicate frames to be delivered. The default value is false (drop duplicate frames diff --git a/man/systemd.network.xml b/man/systemd.network.xml index a27f2ff99e..e6dedb027d 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -77,8 +77,8 @@ name in <filename>/usr/lib</filename>. This can be used to override a system-supplied configuration file with a local file if needed. As a special case, an empty file (file size 0) or symlink - with the same name pointing to <filename>/dev/null</filename>, - disable the configuration file entirely (it is "masked").</para> + with the same name pointing to <filename>/dev/null</filename> + disables the configuration file entirely (it is "masked").</para> </refsect1> <refsect1> @@ -227,7 +227,14 @@ <literal>yes</literal>, <literal>no</literal>, <literal>ipv4</literal>, or <literal>ipv6</literal>.</para> - <para>Please note that by default the domain name + <para>Note that DHCPv6 will by default be triggered by Router + Advertisment, if that is enabled, regardless of this parameter. + By enabling DHCPv6 support explicitly, the DHCPv6 client will + be started regardless of the presence of routers on the link, + or what flags the routers pass. See + <literal>IPv6AcceptRouterAdvertisements=</literal>.</para> + + <para>Furthermore, note that by default the domain name specified through DHCP is not used for name resolution. See option <option>UseDomains=</option> below.</para> </listitem> @@ -263,7 +270,7 @@ <term><varname>IPv6Token=</varname></term> <listitem> <para>An IPv6 address with the top 64 bits unset. When set, indicates the - 64 bits interface part of SLAAC IPv6 addresses for this link. By default + 64-bit interface part of SLAAC IPv6 addresses for this link. By default, it is autogenerated.</para> </listitem> </varlistentry> @@ -271,8 +278,8 @@ <term><varname>LLMNR=</varname></term> <listitem> <para>A boolean or <literal>resolve</literal>. When true, enables - Link-Local Multicast Name Resolution on the link, when set to - <literal>resolve</literal> only resolution is enabled, but not + Link-Local Multicast Name Resolution on the link. When set to + <literal>resolve</literal>, only resolution is enabled, but not announcement. Defaults to true.</para> </listitem> </varlistentry> @@ -356,35 +363,34 @@ </varlistentry> <varlistentry> <term><varname>IPForward=</varname></term> - <listitem><para>Configures IP forwarding for the network - interface. If enabled incoming packets on the network - interface will be forwarded to other interfaces according to - the routing table. Takes either a boolean argument, or the - values <literal>ipv4</literal> or <literal>ipv6</literal>, - which only enables IP forwarding for the specified address - family, or <literal>kernel</literal>, which preserves existing sysctl settings. - This controls the - <filename>net.ipv4.conf.<interface>.forwarding</filename> - and - <filename>net.ipv6.conf.<interface>.forwarding</filename> - sysctl options of the network interface (see <ulink + <listitem><para>Configures IP packet forwarding for the + system. If enabled, incoming packets on any network + interface will be forwarded to any other interfaces + according to the routing table. Takes either a boolean + argument, or the values <literal>ipv4</literal> or + <literal>ipv6</literal>, which only enable IP packet + forwarding for the specified address family. This controls + the <filename>net.ipv4.ip_forward</filename> and + <filename>net.ipv6.conf.all.forwarding</filename> sysctl + options of the network interface (see <ulink url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink> for details about sysctl options). Defaults to <literal>no</literal>.</para> - <para>Note: unless this option is turned on, or set to <literal>kernel</literal>, - no IP forwarding is done on this interface, even if this is - globally turned on in the kernel, with the - <filename>net.ipv4.ip_forward</filename>, - <filename>net.ipv4.conf.all.forwarding</filename>, and - <filename>net.ipv6.conf.all.forwarding</filename> sysctl - options.</para> + <para>Note: this setting controls a global kernel option, + and does so one way only: if a network that has this setting + enabled is set up the global setting is turned on. However, + it is never turned off again, even after all networks with + this setting enabled are shut down again.</para> + + <para>To allow IP packet forwarding only between specific + network interfaces use a firewall.</para> </listitem> </varlistentry> <varlistentry> <term><varname>IPMasquerade=</varname></term> <listitem><para>Configures IP masquerading for the network - interface. If enabled packets forwarded from the network + interface. If enabled, packets forwarded from the network interface will be appear as coming from the local host. Takes a boolean argument. Implies <varname>IPForward=ipv4</varname>. Defaults to @@ -398,21 +404,48 @@ Privacy Extensions for Stateless Address Autoconfiguration in IPv6). Takes a boolean or the special values <literal>prefer-public</literal> and - <literal>kernel</literal>. When true enables the privacy + <literal>kernel</literal>. When true, enables the privacy extensions and prefers temporary addresses over public - addresses. When <literal>prefer-public</literal> enables the + addresses. When <literal>prefer-public</literal>, enables the privacy extensions, but prefers public addresses over temporary addresses. When false, the privacy extensions - remain disabled. When <literal>kernel</literal> the kernel's + remain disabled. When <literal>kernel</literal>, the kernel's default setting will be left in place. Defaults to <literal>no</literal>.</para></listitem> </varlistentry> <varlistentry> <term><varname>IPv6AcceptRouterAdvertisements=</varname></term> - <listitem><para>Configures Accept Router Advertisements. - This is enabled if local forwarding is disabled. - Disabled if local forwarding is enabled. - Takes a boolean. Defaults to unset. + <listitem><para>Force the setting of the <filename>accept_ra</filename> + (router advertisements) setting for the interface. + When unset, the kernel default is used, and router + advertisements are accepted only when local forwarding + is disabled for that interface. + When router advertisements are accepted, they will + trigger the start of the DHCPv6 client if the relevant + flags are passed, or if no routers are found on the link. + Takes a boolean. If true, router advertisements are + accepted, when false, router advertisements are ignored, + independently of the local forwarding state.</para> + + <para>See + <ulink url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink> + in the kernel documentation, but note that systemd's + setting of <constant>1</constant> corresponds to + kernel's setting of <constant>2</constant>.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>IPv6DuplicateAddressDetection=</varname></term> + <listitem><para>Configures the amount of IPv6 Duplicate + Address Detection (DAD) probes to send. Defaults to unset. + </para></listitem> + </varlistentry> + <varlistentry> + <term><varname>IPv6HopLimit=</varname></term> + <listitem><para>Configures IPv6 Hop Limit. For each router that + forwards the packet, the hop limit is decremented by 1. When the + hop limit field reaches zero, the packet is discarded. + Defaults to unset. </para></listitem> </varlistentry> <varlistentry> @@ -519,7 +552,7 @@ <term><varname>Destination=</varname></term> <listitem> <para>The destination prefix of the route. Possibly - followed by a slash and the prefixlength. If omitted, a + followed by a slash and the prefix length. If omitted, a full-length host route is assumed.</para> </listitem> </varlistentry> @@ -527,20 +560,20 @@ <term><varname>Source=</varname></term> <listitem> <para>The source prefix of the route. Possibly followed by - a slash and the prefixlength. If omitted, a full-length + a slash and the prefix length. If omitted, a full-length host route is assumed.</para> </listitem> </varlistentry> <varlistentry> <term><varname>Metric=</varname></term> <listitem> - <para>The metric of the route. An unsigned integer</para> + <para>The metric of the route (an unsigned integer).</para> </listitem> </varlistentry> <varlistentry> <term><varname>Scope=</varname></term> <listitem> - <para>The scope of the route. One of the values <literal>global</literal>, + <para>The scope of the route, which can be <literal>global</literal>, <literal>link</literal> or <literal>host</literal>. Defaults to <literal>global</literal>.</para> </listitem> @@ -632,7 +665,7 @@ <listitem> <para>When true (the default), the static routes will be requested from the DHCP server and added to the routing - table with metric of 1024.</para> + table with a metric of 1024.</para> </listitem> </varlistentry> @@ -709,7 +742,7 @@ address. <varname>PoolOffset=</varname> takes the offset of the pool from the start of subnet, or zero to use the default value. <varname>PoolSize=</varname> takes the number of IP addresses in the - pool or zero to use the default value. By default the pool starts at + pool or zero to use the default value. By default, the pool starts at the first address after the subnet address and takes up the rest of the subnet, excluding the broadcast address. If the pool includes the server address (the default), this is reserved and not handed @@ -725,7 +758,7 @@ another common time unit, depending on the suffix. The default lease time is used for clients that did not ask for a specific lease time. If a client asks for a lease time longer than the - maximum lease time it is automatically shortened to the + maximum lease time, it is automatically shortened to the specified time. The default lease time defaults to 1h, the maximum lease time to 12h. Shorter lease times are beneficial if the configuration data in DHCP leases changes frequently @@ -745,7 +778,7 @@ pass to clients may be configured with the <varname>DNS=</varname> option, which takes a list of IPv4 addresses. If the <varname>EmitDNS=</varname> option is - enabled but no servers configured the servers are + enabled but no servers configured, the servers are automatically propagated from an "uplink" interface that has appropriate servers set. The "uplink" interface is determined by the default route of the system with the highest @@ -754,9 +787,9 @@ into account that acquire DNS or NTP server information at a later point. DNS server propagation does not take <filename>/etc/resolv.conf</filename> into account. Also, note - that the leases are not refreshed if uplink network + that the leases are not refreshed if the uplink network configuration changes. To ensure clients regularly acquire the - most current uplink DNS server information it is thus + most current uplink DNS server information, it is thus advisable to shorten the DHCP lease time via <varname>MaxLeaseTimeSec=</varname> described above.</para></listitem> @@ -767,7 +800,7 @@ <term><varname>NTP=</varname></term> <listitem><para>Similar to the <varname>EmitDNS=</varname> and - <varname>DNS=</varname> settings described above these + <varname>DNS=</varname> settings described above, these settings configure whether and what NTP server information shall be emitted as part of the DHCP lease. The same syntax, propagation semantics and defaults apply as for @@ -786,7 +819,7 @@ <varname>Timezone=</varname> setting takes a timezone string (such as <literal>Europe/Berlin</literal> or <literal>UTC</literal>) to pass to clients. If no explicit - timezone is set the system timezone of the local host is + timezone is set, the system timezone of the local host is propagated, as determined by the <filename>/etc/localtime</filename> symlink.</para></listitem> </varlistentry> @@ -828,7 +861,7 @@ <term><varname>FastLeave=</varname></term> <listitem> <para>A boolean. This flag allows the bridge to immediately stop multicast - traffic on a port that receives IGMP Leave message. It is only used with + traffic on a port that receives an IGMP Leave message. It is only used with IGMP snooping if enabled on the bridge. Defaults to off.</para> </listitem> </varlistentry> @@ -844,7 +877,7 @@ <term><varname>Cost=</varname></term> <listitem> <para>Sets the "cost" of sending packets of this interface. - Each port in a bridge may have different speed and the cost + Each port in a bridge may have a different speed and the cost is used to decide which link to use. Faster interfaces should have lower costs.</para> </listitem> @@ -869,8 +902,8 @@ <varlistentry> <term><varname>VLANId=</varname></term> <listitem> - <para>The VLAN Id for the new static MAC table entry. If - omitted, no VLAN Id info is appended to the new static MAC + <para>The VLAN ID for the new static MAC table entry. If + omitted, no VLAN ID info is appended to the new static MAC table entry.</para> </listitem> </varlistentry> diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 7bfafb424f..e952688331 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -73,11 +73,11 @@ to specific containers. The syntax of these files is inspired by <filename>.desktop</filename> files following the <ulink url="http://standards.freedesktop.org/desktop-entry-spec/latest/">XDG - Desktop Entry Specification</ulink>, which are in turn inspired by + Desktop Entry Specification</ulink>, which in turn are inspired by Microsoft Windows <filename>.ini</filename> files.</para> <para>Boolean arguments used in these settings files can be - written in various formats. For positive settings the strings + written in various formats. For positive settings, the strings <option>1</option>, <option>yes</option>, <option>true</option> and <option>on</option> are equivalent. For negative settings, the strings <option>0</option>, <option>no</option>, @@ -102,27 +102,27 @@ directory or image file name. This file is first searched in <filename>/etc/systemd/nspawn/</filename> and <filename>/run/systemd/nspawn/</filename>. If found in these - directories its settings are read and all of them take full effect + directories, its settings are read and all of them take full effect (but are possibly overridden by corresponding command line - arguments). If not found the file will then be searched next to + arguments). If not found, the file will then be searched next to the image file or in the immediate parent of the root directory of - the container. If the file is found there only a subset of the + the container. If the file is found there, only a subset of the settings will take effect however. All settings that possibly elevate privileges or grant additional access to resources of the host (such as files or directories) are ignored. To which options this applies is documented below.</para> - <para>Persistent settings file created and maintained by the + <para>Persistent settings files created and maintained by the administrator (and thus trusted) should be placed in <filename>/etc/systemd/nspawn/</filename>, while automatically downloaded (and thus potentially untrusted) settings files are placed in <filename>/var/lib/machines/</filename> instead (next to the container images), where their security impact is limited. In order to add privileged settings to <filename>.nspawn</filename> - files acquired from the image vendor it is recommended to copy the + files acquired from the image vendor, it is recommended to copy the settings files into <filename>/etc/systemd/nspawn/</filename> and edit them there, so that the privileged options become - available. The precise algorithm how the files are searched and + available. The precise algorithm for how the files are searched and interpreted may be configured with <command>systemd-nspawn</command>'s <option>--settings=</option> switch, see @@ -141,10 +141,10 @@ <varlistentry> <term><varname>Boot=</varname></term> - <listitem><para>Takes a boolean argument, defaults to off. If - enabled <command>systemd-nspawn</command> will automatically + <listitem><para>Takes a boolean argument, which defaults to off. If + enabled, <command>systemd-nspawn</command> will automatically search for an <filename>init</filename> executable and invoke - it. In this case the specified parameters using + it. In this case, the specified parameters using <varname>Parameters=</varname> are passed as additional arguments to the <filename>init</filename> process. This setting corresponds to the <option>--boot</option> switch on @@ -155,7 +155,7 @@ <varlistentry> <term><varname>Parameters=</varname></term> - <listitem><para>Takes a space separated list of + <listitem><para>Takes a space-separated list of arguments. This is either a command line, beginning with the binary name to execute, or – if <varname>Boot=</varname> is enabled – the list of arguments to pass to the init @@ -190,7 +190,7 @@ <term><varname>Capability=</varname></term> <term><varname>DropCapability=</varname></term> - <listitem><para>Takes a space separated list of Linux process + <listitem><para>Takes a space-separated list of Linux process capabilities (see <citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details). The <varname>Capability=</varname> setting @@ -205,7 +205,7 @@ <filename>.nspawn</filename> files in <filename>/etc/systemd/nspawn/</filename> and <filename>/run/system/nspawn/</filename> (see above). On the - other hand <varname>DropCapability=</varname> takes effect in + other hand, <varname>DropCapability=</varname> takes effect in all cases.</para></listitem> </varlistentry> @@ -220,7 +220,7 @@ <varlistentry> <term><varname>MachineID=</varname></term> - <listitem><para>Configures the 128bit machine ID (UUID) to pass to + <listitem><para>Configures the 128-bit machine ID (UUID) to pass to the container. This is equivalent to the <option>--uuid=</option> command line switch. This option is privileged (see above). </para></listitem> @@ -240,8 +240,8 @@ <varlistentry> <term><varname>ReadOnly=</varname></term> - <listitem><para>Takes a boolean argument, defaults to off. If - specified the container will be run with a read-only file + <listitem><para>Takes a boolean argument, which defaults to off. If + specified, the container will be run with a read-only file system. This setting corresponds to the <option>--read-only</option> command line switch.</para></listitem> @@ -303,8 +303,8 @@ <varlistentry> <term><varname>Private=</varname></term> - <listitem><para>Takes a boolean argument, defaults to off. If - enabled the container will run in its own network namespace + <listitem><para>Takes a boolean argument, which defaults to off. If + enabled, the container will run in its own network namespace and not share network interfaces and configuration with the host. This setting corresponds to the <option>--private-network</option> command line @@ -315,7 +315,7 @@ <term><varname>VirtualEthernet=</varname></term> <listitem><para>Takes a boolean argument. Configures whether - to create a virtual ethernet connection + to create a virtual Ethernet connection (<literal>veth</literal>) between host and the container. This setting implies <varname>Private=yes</varname>. This setting corresponds to the <option>--network-veth</option> command @@ -324,9 +324,26 @@ </varlistentry> <varlistentry> + <term><varname>VirtualEthernetExtra=</varname></term> + + <listitem><para>Takes a colon-separated pair of interface + names. Configures an additional virtual Ethernet connection + (<literal>veth</literal>) between host and the container. The + first specified name is the interface name on the host, the + second the interface name in the container. The latter may be + omitted in which case it is set to the same name as the host + side interface. This setting implies + <varname>Private=yes</varname>. This setting corresponds to + the <option>--network-veth-extra=</option> command line + switch, and maybe be used multiple times. It is independent of + <varname>VirtualEthernet=</varname>. This option is privileged + (see above).</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>Interface=</varname></term> - <listitem><para>Takes a space separated list of interfaces to + <listitem><para>Takes a space-separated list of interfaces to add to the container. This option corresponds to the <option>--network-interface=</option> command line switch and implies <varname>Private=yes</varname>. This option is @@ -337,7 +354,7 @@ <term><varname>MACVLAN=</varname></term> <term><varname>IPVLAN=</varname></term> - <listitem><para>Takes a space separated list of interfaces to + <listitem><para>Takes a space-separated list of interfaces to add MACLVAN or IPVLAN interfaces to, which are then added to the container. These options correspond to the <option>--network-macvlan=</option> and diff --git a/man/systemd.path.xml b/man/systemd.path.xml index d02bc92ae6..1bd65ce86d 100644 --- a/man/systemd.path.xml +++ b/man/systemd.path.xml @@ -79,13 +79,24 @@ limitations as inotify, and for example cannot be used to monitor files or directories changed by other machines on remote NFS file systems.</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> + + <para>If a path unit is beneath another mount unit in the file + system hierarchy, both a requirement and an ordering dependency + between both units are created automatically.</para> - <para>If a path unit is beneath another mount point in the file - system hierarchy, a dependency between both units is created - automatically.</para> + <para>An implicit <varname>Before=</varname> dependency is added + between a path unit and the unit it is supposed to activate.</para> <para>Unless <varname>DefaultDependencies=false</varname> is used, path units will implicitly have dependencies of type + <varname>Before=</varname> on <filename>paths.target</filename>, + dependencies of type <varname>After=</varname> and + <varname>Requires=</varname> on + <filename>sysinit.target</filename>, and have dependencies of type <varname>Conflicts=</varname> and <varname>Before=</varname> on <filename>shutdown.target</filename>. These ensure that path units are terminated cleanly prior to system shutdown. Only path units diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 98f4d75ddb..0497f60546 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -90,6 +90,15 @@ </refsect1> <refsect1> + <title>Automatic Dependencies</title> + + <para>Units with the <varname>Slice=</varname> setting set get + automatic <varname>Requires=</varname> and + <varname>After=</varname> dependencies on the specified slice + unit.</para> + </refsect1> + + <refsect1> <title>Options</title> <para>Units of the types listed above can have settings @@ -189,7 +198,7 @@ or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. If assigned the special value - <literal>infinity</literal> no memory limit is applied. This + <literal>infinity</literal>, no memory limit is applied. This controls the <literal>memory.limit_in_bytes</literal> control group attribute. For details about this control group attribute, see <ulink @@ -226,7 +235,7 @@ created in the unit. This ensures that the number of tasks accounted for the unit (see above) stays below a specific limit. If assigned the special value - <literal>infinity</literal> no tasks limit is applied. This + <literal>infinity</literal>, no tasks limit is applied. This controls the <literal>pids.max</literal> control group attribute. For details about this control group attribute, see <ulink @@ -240,8 +249,8 @@ <term><varname>BlockIOAccounting=</varname></term> <listitem> - <para>Turn on Block IO accounting for this unit. Takes a - boolean argument. Note that turning on block IO accounting + <para>Turn on Block I/O accounting for this unit. Takes a + boolean argument. Note that turning on block I/O accounting for one unit will also implicitly turn it on for all units contained in the same slice and all for its parent slices and the units contained therein. The system default for this @@ -255,15 +264,15 @@ <term><varname>BlockIOWeight=<replaceable>weight</replaceable></varname></term> <term><varname>StartupBlockIOWeight=<replaceable>weight</replaceable></varname></term> - <listitem><para>Set the default overall block IO weight for + <listitem><para>Set the default overall block I/O weight for the executed processes. Takes a single weight value (between - 10 and 1000) to set the default block IO weight. This controls + 10 and 1000) to set the default block I/O weight. This controls the <literal>blkio.weight</literal> control group attribute, which defaults to 500. For details about this control group attribute, see <ulink url="https://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>. - The available IO bandwidth is split up among all units within - one slice relative to their block IO weight.</para> + The available I/O bandwidth is split up among all units within + one slice relative to their block I/O weight.</para> <para>While <varname>StartupBlockIOWeight=</varname> only applies to the startup phase of the system, @@ -281,7 +290,7 @@ <term><varname>BlockIODeviceWeight=<replaceable>device</replaceable> <replaceable>weight</replaceable></varname></term> <listitem> - <para>Set the per-device overall block IO weight for the + <para>Set the per-device overall block I/O weight for the executed processes. Takes a space-separated pair of a file path and a weight value to specify the device specific weight value, between 10 and 1000. (Example: "/dev/sda @@ -305,7 +314,7 @@ <term><varname>BlockIOWriteBandwidth=<replaceable>device</replaceable> <replaceable>bytes</replaceable></varname></term> <listitem> - <para>Set the per-device overall block IO bandwidth limit + <para>Set the per-device overall block I/O bandwidth limit for the executed processes. Takes a space-separated pair of a file path and a bandwidth value (in bytes per second) to specify the device specific bandwidth. The file path may be @@ -412,6 +421,23 @@ </varlistentry> <varlistentry> + <term><varname>NetClass=</varname></term> + <listitem><para>Configures a network class number to assign to the + unit. This value will be set to the + <literal>net_cls.class_id</literal> property of the + <literal>net_cls</literal> cgroup of the unit. The directive + accepts a numerical value (for fixed number assignment) and the keyword + <literal>auto</literal> (for dynamic allocation). Network traffic of + all processes inside the unit will have the network class ID assigned + by the kernel. Also see + the kernel docs for + <ulink url="https://www.kernel.org/doc/Documentation/cgroups/net_cls.txt">net_cls controller</ulink> + and + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>. + </para></listitem> + </varlistentry> + + <varlistentry> <term><varname>Slice=</varname></term> <listitem> @@ -440,9 +466,9 @@ <para>Turns on delegation of further resource control partitioning to processes of the unit. For unprivileged services (i.e. those using the <varname>User=</varname> - setting) this allows processes to create a subhierarchy + setting), this allows processes to create a subhierarchy beneath its control group path. For privileged services and - scopes this ensures the processes will have all control + scopes, this ensures the processes will have all control group controllers enabled.</para> </listitem> </varlistentry> diff --git a/man/systemd.scope.xml b/man/systemd.scope.xml index fd65a851e2..f69b2ef635 100644 --- a/man/systemd.scope.xml +++ b/man/systemd.scope.xml @@ -72,6 +72,10 @@ url="http://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/">New Control Group Interfaces</ulink> for an introduction on how to make use of scope units from programs.</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> <para>Unless <varname>DefaultDependencies=false</varname> is used, scope units will implicitly have dependencies of @@ -82,6 +86,11 @@ shutdown. Only scope units involved with early boot or late system shutdown should disable this option. </para> + + <para>Additional implicit dependencies may be added as result of + resource control parameters as documented in + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + </refsect1> <refsect1> diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 8afdbc513b..c6ed75d158 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -1,4 +1,4 @@ -<?xml version='1.0'?> <!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> @@ -77,18 +77,6 @@ which configure resource control settings for the processes of the service.</para> - <para>Unless <varname>DefaultDependencies=</varname> is set to - <option>false</option>, service units will implicitly have - dependencies of type <varname>Requires=</varname> and - <varname>After=</varname> on <filename>basic.target</filename> as - well as dependencies of type <varname>Conflicts=</varname> and - <varname>Before=</varname> on - <filename>shutdown.target</filename>. These ensure that normal - service units pull in basic system initialization, and are - terminated cleanly prior to system shutdown. Only services - involved with early boot or late system shutdown should disable - this option.</para> - <para>If a service is requested under a certain name but no unit configuration file is found, systemd looks for a SysV init script by the same name (with the <filename>.service</filename> suffix @@ -97,8 +85,39 @@ compatibility is quite comprehensive but not 100%. For details about the incompatibilities, see the <ulink url="http://www.freedesktop.org/wiki/Software/systemd/Incompatibilities">Incompatibilities - with SysV</ulink> document. - </para> + with SysV</ulink> document.</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> + + <para>Services with <varname>Type=dbus</varname> set automatically + acquire dependencies of type <varname>Requires=</varname> and + <varname>After=</varname> on + <filename>dbus.socket</filename>.</para> + + <para>Socket activated service are automatically ordered after + their activated <filename>.socket</filename> units via an + automatic <varname>After=</varname> dependency.</para> + + <para>Unless <varname>DefaultDependencies=</varname> is set to + <option>false</option>, service units will implicitly have + dependencies of type <varname>Requires=</varname> and + <varname>After=</varname> on <filename>sysinit.target</filename>, + a dependency of type <varname>After=</varname> on + <filename>basic.target</filename> as well as dependencies of + type <varname>Conflicts=</varname> and <varname>Before=</varname> + on <filename>shutdown.target</filename>. These ensure that normal + service units pull in basic system initialization, and are + terminated cleanly prior to system shutdown. Only services + involved with early boot or late system shutdown should disable + this option.</para> + + <para>Additional implicit dependencies may be added as result of + execution and resource control parameters as documented in + <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> + and + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> </refsect1> <refsect1> @@ -254,7 +273,7 @@ for, and its node will be bind-mounted over the default bus node location, so the service can only access the bus through its own endpoint. Note that custom bus endpoints default to a - 'deny all' policy. Hence, if at least one + "deny all" policy. Hence, if at least one <varname>BusPolicy=</varname> directive is given, you have to make sure to add explicit rules for everything the service should be able to do.</para> @@ -283,7 +302,7 @@ <term><varname>ExecStart=</varname></term> <listitem><para>Commands with their arguments that are executed when this service is started. The value is split into - zero or more command lines is according to the rules described + zero or more command lines according to the rules described below (see section "Command Lines" below). </para> @@ -343,7 +362,7 @@ <para><varname>ExecStartPost=</varname> commands are only run after the service has started, as determined by <varname>Type=</varname> - (i.e. The process has been started for <varname>Type=simple</varname> + (i.e. the process has been started for <varname>Type=simple</varname> or <varname>Type=idle</varname>, the process exits successfully for <varname>Type=oneshot</varname>, the initial process exits successfully for <varname>Type=forking</varname>, <literal>READY=1</literal> is sent @@ -403,11 +422,11 @@ <para>Note that it is usually not sufficient to specify a command for this setting that only asks the service to - terminate (for example by queuing some form of termination + terminate (for example, by queuing some form of termination signal for it), but does not wait for it to do so. Since the remaining processes of the services are killed using <constant>SIGKILL</constant> immediately after the command - exited this would not result in a clean stop. The specified + exited, this would not result in a clean stop. The specified command should hence be a synchronous operation, not an asynchronous one.</para></listitem> </varlistentry> @@ -628,7 +647,7 @@ </tgroup> </table> - <para>As exceptions to the setting above the service will not + <para>As exceptions to the setting above, the service will not be restarted if the exit code or signal is specified in <varname>RestartPreventExitStatus=</varname> (see below). Also, the services will always be restarted if the exit code @@ -646,8 +665,8 @@ <varlistentry> <term><varname>SuccessExitStatus=</varname></term> - <listitem><para>Takes a list of exit status definitions that - when returned by the main service process will be considered + <listitem><para>Takes a list of exit status definitions that, + when returned by the main service process, will be considered successful termination, in addition to the normal successful exit code 0 and the signals <constant>SIGHUP</constant>, <constant>SIGINT</constant>, <constant>SIGTERM</constant>, and @@ -679,8 +698,8 @@ <varlistentry> <term><varname>RestartPreventExitStatus=</varname></term> - <listitem><para>Takes a list of exit status definitions that - when returned by the main service process will prevent + <listitem><para>Takes a list of exit status definitions that, + when returned by the main service process, will prevent automatic service restarts, regardless of the restart setting configured with <varname>Restart=</varname>. Exit status definitions can either be numeric exit codes or termination @@ -699,8 +718,8 @@ <varlistentry> <term><varname>RestartForceExitStatus=</varname></term> - <listitem><para>Takes a list of exit status definitions that - when returned by the main service process will force automatic + <listitem><para>Takes a list of exit status definitions that, + when returned by the main service process, will force automatic service restarts, regardless of the restart setting configured with <varname>Restart=</varname>. The argument format is similar to @@ -779,8 +798,8 @@ <term><varname>Sockets=</varname></term> <listitem><para>Specifies the name of the socket units this service shall inherit socket file descriptors from when the - service is started. Normally it should not be necessary to use - this setting as all socket file descriptors whose unit shares + service is started. Normally, it should not be necessary to use + this setting, as all socket file descriptors whose unit shares the same name as the service (subject to the different unit name suffix of course) are passed to the spawned process.</para> @@ -789,7 +808,7 @@ to multiple processes simultaneously. Also note that a different service may be activated on incoming socket traffic than the one which is ultimately configured to inherit the - socket file descriptors. Or in other words: the + socket file descriptors. Or, in other words: the <varname>Service=</varname> setting of <filename>.socket</filename> units does not have to match the inverse of the <varname>Sockets=</varname> setting of the @@ -859,7 +878,7 @@ <option>reboot-immediate</option> causes immediate execution of the <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> - system call, which might result in data loss. Similar, + system call, which might result in data loss. Similarly, <option>poweroff</option>, <option>poweroff-force</option>, <option>poweroff-immediate</option> have the effect of powering down the system with similar semantics. Defaults to @@ -909,9 +928,9 @@ <ulink url="https://www.kernel.org/doc/Documentation/usb/functionfs.txt">USB FunctionFS</ulink> descriptors, for implementation of USB - gadget functions. This is is used only in conjunction with a + gadget functions. This is used only in conjunction with a socket unit with <varname>ListenUSBFunction=</varname> - configured. The contents of this file is written to the + configured. The contents of this file are written to the <filename>ep0</filename> file after it is opened.</para></listitem> </varlistentry> @@ -992,7 +1011,7 @@ contains, resulting in a single argument. Use <literal>$FOO</literal> as a separate word on the command line, in which case it will be replaced by the value of the environment - variable split at whitespace resulting in zero or more arguments. + variable split at whitespace, resulting in zero or more arguments. For this type of expansion, quotes are respected when splitting into words, and afterwards removed.</para> @@ -1175,7 +1194,7 @@ WantedBy=multi-user.target</programlisting> <example> <title>Oneshot service</title> - <para>Sometimes units should just execute an action without + <para>Sometimes, units should just execute an action without keeping active processes, such as a filesystem check or a cleanup action on boot. For this, <varname>Type=</varname><option>oneshot</option> exists. Units @@ -1194,10 +1213,10 @@ ExecStart=/usr/sbin/foo-cleanup WantedBy=multi-user.target</programlisting> <para>Note that systemd will consider the unit to be in the - state 'starting' until the program has terminated, so ordered + state "starting" until the program has terminated, so ordered dependencies will wait for the program to finish before starting - themselves. The unit will revert to the 'inactive' state after - the execution is done, never reaching the 'active' state. That + themselves. The unit will revert to the "inactive" state after + the execution is done, never reaching the "active" state. That means another request to start the unit will perform the action again.</para> @@ -1214,9 +1233,9 @@ WantedBy=multi-user.target</programlisting> <para>Similarly to the oneshot services, there are sometimes units that need to execute a program to set up something and then execute another to shut it down, but no process remains - active while they are considered 'started'. Network + active while they are considered "started". Network configuration can sometimes fall into this category. Another use - case is if a oneshot service shall not be executed a each time + case is if a oneshot service shall not be executed each time when they are pulled in as a dependency, but only the first time.</para> @@ -1227,11 +1246,11 @@ WantedBy=multi-user.target</programlisting> types, but is most useful with <varname>Type=</varname><option>oneshot</option> and <varname>Type=</varname><option>simple</option>. With - <varname>Type=</varname><option>oneshot</option> systemd waits + <varname>Type=</varname><option>oneshot</option>, systemd waits until the start action has completed before it considers the unit to be active, so dependencies start only after the start action has succeeded. With - <varname>Type=</varname><option>simple</option> dependencies + <varname>Type=</varname><option>simple</option>, dependencies will start immediately after the start action has been dispatched. The following unit provides an example for a simple static firewall.</para> @@ -1266,7 +1285,7 @@ WantedBy=multi-user.target</programlisting> <varname>RemainAfterExit=</varname><option>no</option>), the service is considered started.</para> - <para>Often a traditional daemon only consists of one process. + <para>Often, a traditional daemon only consists of one process. Therefore, if only one process is left after the original process terminates, systemd will consider that process the main process of the service. In that case, the @@ -1281,7 +1300,7 @@ WantedBy=multi-user.target</programlisting> traditional PID file, systemd will be able to read the main PID from there. Please set <varname>PIDFile=</varname> accordingly. Note that the daemon should write that file before finishing - with its initialization, otherwise systemd might try to read the + with its initialization. Otherwise, systemd might try to read the file before it exists.</para> <para>The following example shows a simple daemon that forks and @@ -1324,7 +1343,7 @@ ExecStart=/usr/sbin/simple-dbus-service [Install] WantedBy=multi-user.target</programlisting> - <para>For <emphasis>bus-activatable</emphasis> services, don't + <para>For <emphasis>bus-activatable</emphasis> services, do not include a <literal>[Install]</literal> section in the systemd service file, but use the <varname>SystemdService=</varname> option in the corresponding DBus service file, for example @@ -1366,7 +1385,7 @@ ExecStart=/usr/sbin/simple-notifying-service WantedBy=multi-user.target</programlisting> <para>Note that the daemon has to support systemd's notification - protocol, else systemd will think the service hasn't started yet + protocol, else systemd will think the service has not started yet and kill it after a timeout. For an example of how to update daemons to support this protocol transparently, take a look at <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. diff --git a/man/systemd.slice.xml b/man/systemd.slice.xml index 87c2a3bce3..5c87bf0260 100644 --- a/man/systemd.slice.xml +++ b/man/systemd.slice.xml @@ -97,6 +97,14 @@ url="http://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/">New Control Group Interfaces</ulink> for an introduction on how to make use of slice units from programs.</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> + + <para>Slice units automatically gain dependencies of type + <varname>After=</varname> and <varname>Requires=</varname> on + their immediate parent slice unit.</para> <para>Unless <varname>DefaultDependencies=false</varname> is used, slice units will implicitly have dependencies of diff --git a/man/systemd.snapshot.xml b/man/systemd.snapshot.xml deleted file mode 100644 index 96069c324a..0000000000 --- a/man/systemd.snapshot.xml +++ /dev/null @@ -1,83 +0,0 @@ -<?xml version='1.0'?> <!--*-nxml-*--> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" - "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> - -<!-- - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ---> - -<refentry id="systemd.snapshot"> - <refentryinfo> - <title>systemd.snapshot</title> - <productname>systemd</productname> - - <authorgroup> - <author> - <contrib>Developer</contrib> - <firstname>Lennart</firstname> - <surname>Poettering</surname> - <email>lennart@poettering.net</email> - </author> - </authorgroup> - </refentryinfo> - - <refmeta> - <refentrytitle>systemd.snapshot</refentrytitle> - <manvolnum>5</manvolnum> - </refmeta> - - <refnamediv> - <refname>systemd.snapshot</refname> - <refpurpose>Snapshot unit configuration</refpurpose> - </refnamediv> - - <refsynopsisdiv> - <para><filename><replaceable>snapshot</replaceable>.snapshot</filename></para> - </refsynopsisdiv> - - <refsect1> - <title>Description</title> - - <para>Snapshot units are not configured via unit configuration - files. Nonetheless they are named similar to filenames. A unit - whose name ends in <literal>.snapshot</literal> refers to a - dynamic snapshot of the systemd runtime state.</para> - - <para>Snapshots are not configured on disk but created dynamically - via <command>systemctl snapshot</command> (see - <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> - for details) or an equivalent command. When created, they will - automatically get dependencies on the currently activated units. - They act as saved runtime state of the systemd manager. Later on, - the user may choose to return to the saved state via - <command>systemctl isolate</command>. They are useful to roll back - to a defined state after temporarily starting/stopping services or - similar.</para> - </refsect1> - - <refsect1> - <title>See Also</title> - <para> - <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry> - </para> - </refsect1> - -</refentry> diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index 46a47b2d95..beac053bf0 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -134,6 +134,40 @@ </refsect1> <refsect1> + <title>Automatic Dependencies</title> + + <para>Socket units automatically gain a <varname>Before=</varname> + dependency on the service units they activate.</para> + + <para>Socket units referring to file system paths (such as AF_UNIX + sockets or FIFOs) implicitly gain <varname>Requires=</varname> and + <varname>After=</varname> dependencies on all mount units + necessary to access those paths.</para> + + <para>Socket units using the <varname>BindToDevice=</varname> + setting automatically gain a <varname>BindsTo=</varname> and + <varname>After=</varname> dependency on the device unit + encapsulating the specified network interface.</para> + + <para>If <varname>DefaultDependencies=yes</varname> is set (the + default), socket units automatically gain a + <varname>Before=</varname> dependency on + <filename>sockets.target</filename>. They also gain a pair of + <varname>After=</varname> and <varname>Requires=</varname> + dependency on <filename>sysinit.target</filename>, and a pair of + <varname>Before=</varname> and <varname>Conflicts=</varname> + dependencies on <filename>shutdown.target</filename>. These + dependencies ensure that the socket unit is started before normal + services at boot, and is stopped on shutdown.</para> + + <para>Additional implicit dependencies may be added as result of + execution and resource control parameters as documented in + <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> + and + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + </refsect1> + + <refsect1> <title>Options</title> <para>Socket files must include a [Socket] section, which carries @@ -194,7 +228,7 @@ refers to TCP sockets, <constant>SOCK_DGRAM</constant> (i.e. <varname>ListenDatagram=</varname>) to UDP.</para> - <para>These options may be specified more than once in which + <para>These options may be specified more than once, in which case incoming traffic on any of the sockets will trigger service activation, and all listed sockets will be passed to the service, regardless of whether there is incoming traffic @@ -268,7 +302,7 @@ implementation of USB gadget functions. This expects an absolute file system path as the argument. Behavior otherwise is very similar to the <varname>ListenFIFO=</varname> - directive above. Use this to open FunctionFS endpoint + directive above. Use this to open the FunctionFS endpoint <filename>ep0</filename>. When using this option, the activated service has to have the <varname>USBFunctionDescriptors=</varname> and @@ -309,12 +343,14 @@ <listitem><para>Specifies a network interface name to bind this socket to. If set, traffic will only be accepted from the specified network interfaces. This controls the - SO_BINDTODEVICE socket option (see - <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry> + SO_BINDTODEVICE socket option (see <citerefentry + project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details). If this option is used, an automatic dependency from this socket unit on the network interface device unit (<citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry> - is created.</para></listitem> + is created. Note that setting this parameter might result in + additional dependencies to be added to the unit (see + above).</para></listitem> </varlistentry> <varlistentry> @@ -375,10 +411,10 @@ to work unmodified with systemd socket activation.</para> - <para>For IPv4 and IPv6 connections the <varname>REMOTE_ADDR</varname> - environment variable will contain the remote IP, and <varname>REMOTE_PORT</varname> + <para>For IPv4 and IPv6 connections, the <varname>REMOTE_ADDR</varname> + environment variable will contain the remote IP address, and <varname>REMOTE_PORT</varname> will contain the remote port. This is the same as the format used by CGI. - For SOCK_RAW the port is the IP protocol.</para></listitem> + For SOCK_RAW, the port is the IP protocol.</para></listitem> </varlistentry> <varlistentry> @@ -386,7 +422,7 @@ <listitem><para>Takes a boolean argument. May only be used in conjunction with <varname>ListenSpecial=</varname>. If true, the specified special file is opened in read-write mode, if - false in read-only mode. Defaults to false.</para></listitem> + false, in read-only mode. Defaults to false.</para></listitem> </varlistentry> <varlistentry> @@ -418,7 +454,7 @@ <varlistentry> <term><varname>KeepAliveTimeSec=</varname></term> - <listitem><para>Takes time (in seconds) as argument . The connection needs to remain + <listitem><para>Takes time (in seconds) as argument. The connection needs to remain idle before TCP starts sending keepalive probes. This controls the TCP_KEEPIDLE socket option (see <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry> @@ -432,7 +468,7 @@ <term><varname>KeepAliveIntervalSec=</varname></term> <listitem><para>Takes time (in seconds) as argument between individual keepalive probes, if the socket option SO_KEEPALIVE - has been set on this socket seconds as argument. This controls + has been set on this socket. This controls the TCP_KEEPINTVL socket option (see <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry> and the <ulink @@ -443,7 +479,7 @@ <varlistentry> <term><varname>KeepAliveProbes=</varname></term> - <listitem><para>Takes integer as argument. It's the number of + <listitem><para>Takes an integer as argument. It is the number of unacknowledged probes to send before considering the connection dead and notifying the application layer. This controls the TCP_KEEPCNT socket option (see @@ -719,7 +755,9 @@ with <varname>Accept=no</varname>. It defaults to the service that bears the same name as the socket (with the suffix replaced). In most cases, it should not be necessary to use - this option.</para></listitem> + this option. Note that setting this parameter might result in + additional dependencies to be added to the unit (see + above).</para></listitem> </varlistentry> <varlistentry> @@ -752,14 +790,14 @@ <term><varname>FileDescriptorName=</varname></term> <listitem><para>Assigns a name to all file descriptors this socket unit encapsulates. This is useful to help activated - services to identify specific file descriptors, if multiple + services identify specific file descriptors, if multiple fds are passed. Services may use the <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry> call to acquire the names configured for the received file descriptors. Names may contain any ASCII character, but must - exclude control characters or <literal>:</literal>, and must + exclude control characters and <literal>:</literal>, and must be at most 255 characters in length. If this setting is not - used the file descriptor name defaults to the name of the + used, the file descriptor name defaults to the name of the socket unit, including its <filename>.socket</filename> suffix.</para></listitem> </varlistentry> diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 78bad4d814..54e7c49a9e 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -130,7 +130,7 @@ for this target unit to all services (except for those with <varname>DefaultDependencies=no</varname>).</para> - <para>Usually this should pull-in all local mount points plus + <para>Usually, this should pull-in all local mount points plus <filename>/var</filename>, <filename>/tmp</filename> and <filename>/var/tmp</filename>, swap devices, sockets, timers, path units and other basic initialization necessary for general @@ -152,7 +152,7 @@ <term><filename>ctrl-alt-del.target</filename></term> <listitem> <para>systemd starts this target whenever Control+Alt+Del is - pressed on the console. Usually this should be aliased + pressed on the console. Usually, this should be aliased (symlinked) to <filename>reboot.target</filename>.</para> </listitem> </varlistentry> @@ -182,7 +182,7 @@ <varlistentry> <term><filename>default.target</filename></term> <listitem> - <para>The default unit systemd starts at bootup. Usually + <para>The default unit systemd starts at bootup. Usually, this should be aliased (symlinked) to <filename>multi-user.target</filename> or <filename>graphical.target</filename>.</para> @@ -195,7 +195,7 @@ <varlistentry> <term><filename>display-manager.service</filename></term> <listitem> - <para>The display manager service. Usually this should be + <para>The display manager service. Usually, this should be aliased (symlinked) to <filename>gdm.service</filename> or a similar display manager service.</para> </listitem> @@ -225,7 +225,7 @@ signal when running as user service daemon.</para> <para>Normally, this (indirectly) pulls in - <filename>shutdown.target</filename> which in turn should be + <filename>shutdown.target</filename>, which in turn should be conflicted by all units that want to be scheduled for shutdown when the service manager starts to exit.</para> </listitem> diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml index d9a39577d5..c600405c87 100644 --- a/man/systemd.swap.xml +++ b/man/systemd.swap.xml @@ -68,14 +68,15 @@ <para>Additional options are listed in <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - which define the execution environment the - <citerefentry project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry> - binary is executed in, and in + which define the execution environment the <citerefentry + project='man-pages'><refentrytitle>swapon</refentrytitle><manvolnum>8</manvolnum></citerefentry> + binary is executed in, in <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - which define the way the processes are terminated, and in + which define the way the these processes are + terminated, and in <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - which configure resource control settings for the processes of the - service.</para> + which configure resource control settings for these processes of the + unit.</para> <para>Swap units must be named after the devices or files they control. Example: the swap device @@ -84,15 +85,28 @@ the escaping logic used to convert a file system path to a unit name, see <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> - <para>All swap units automatically get the appropriate - dependencies on the devices or on the mount points of the files + <para>All swap units automatically get the + <varname>BindsTo=</varname> and <varname>After=</varname> + dependencies on the device units or the mount units of the files they are activated from.</para> <para>Swap units with <varname>DefaultDependencies=</varname> - enabled implicitly acquire a conflicting dependency to + enabled implicitly acquire a <varname>Conflicts=</varname> and an + <varname>After=</varname> dependency on <filename>umount.target</filename> so that they are deactivated at - shutdown.</para> + shutdown, unless <varname>DefaultDependencies=no</varname> is + specified.</para> + + <para>Additional implicit dependencies may be added as result of + execution and resource control parameters as documented in + <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> + and + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> </refsect1> <refsect1> @@ -111,7 +125,7 @@ <filename>/etc/fstab</filename> and a unit file, the configuration in the latter takes precedence.</para> - <para>When reading <filename>/etc/fstab</filename> a few special + <para>When reading <filename>/etc/fstab</filename>, a few special options are understood by systemd which influence how dependencies are created for swap units.</para> @@ -120,11 +134,11 @@ <term><option>noauto</option></term> <term><option>auto</option></term> - <listitem><para>With <option>noauto</option> the swap unit + <listitem><para>With <option>noauto</option>, the swap unit will not be added as a dependency for <filename>swap.target</filename>. This means that it will not be activated automatically during boot, unless it is pulled in - by some other unit. Option <option>auto</option> has the + by some other unit. The <option>auto</option> option has the opposite meaning and is the default.</para> </listitem> </varlistentry> @@ -132,7 +146,7 @@ <varlistentry> <term><option>nofail</option></term> - <listitem><para>With <option>nofail</option> the swap unit + <listitem><para>With <option>nofail</option>, the swap unit will be only wanted, not required by <filename>swap.target</filename>. This means that the boot will continue even if this swap device is not activated @@ -177,8 +191,8 @@ <listitem><para>Swap priority to use when activating the swap device or file. This takes an integer. This setting is - optional and ignored when priority is set by <option>pri=</option> in the - <varname>Options=</varname> option.</para></listitem> + optional and ignored when the priority is set by <option>pri=</option> in the + <varname>Options=</varname> key.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd.target.xml b/man/systemd.target.xml index e790e9b77a..bd4ab3903e 100644 --- a/man/systemd.target.xml +++ b/man/systemd.target.xml @@ -77,15 +77,19 @@ See <citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details).</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> <para>Unless <varname>DefaultDependencies=</varname> is set to - <option>false</option>, target units will implicitly complement - all configured dependencies of type <varname>Wants=</varname>, - <varname>Requires=</varname>, - <varname>RequiresOverridable=</varname> with dependencies of type - <varname>After=</varname> if the units in question also have - <varname>DefaultDependencies=true</varname>. - </para> + <option>no</option>, target units will implicitly complement all + configured dependencies of type <varname>Wants=</varname>, + <varname>Requires=</varname> with dependencies of type + <varname>After=</varname>, unless an ordering dependency of any + kind between the target and the respective other unit is already + in place. Note that this behaviour is disabled if either unit has + <varname>DefaultDependencies=no</varname>.</para> </refsect1> <refsect1> diff --git a/man/systemd.time.xml b/man/systemd.time.xml index 64358351d5..135eb35f1b 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -117,11 +117,12 @@ <refsect1> <title>Parsing Timestamps</title> - <para>When parsing systemd will accept a similar timestamp syntax, - but excluding any timezone specification (this limitation might be - removed eventually). The weekday specification is optional, but - when the weekday is specified it must either be in the abbreviated - (<literal>Wed</literal>) or non-abbreviated + <para>When parsing, systemd will accept a similar syntax, but + expects no timezone specification, unless it is given as the + literal string "UTC". In this case, the time is considered in UTC, + otherwise in the local timezone. The weekday specification is + optional, but when the weekday is specified, it must either be in + the abbreviated (<literal>Wed</literal>) or non-abbreviated (<literal>Wednesday</literal>) English language form (case does not matter), and is not subject to the locale choice of the user. Either the date, or the time part may be omitted, in which case @@ -138,8 +139,8 @@ placeholders instead of timestamps: <literal>now</literal> may be used to refer to the current time (or of the invocation of the command that is currently executed). <literal>today</literal>, - <literal>yesterday</literal>, <literal>tomorrow</literal> refer to - 00:00:00 of the current day, the day before or the next day, + <literal>yesterday</literal>, and <literal>tomorrow</literal> refer to + 00:00:00 of the current day, the day before, or the next day, respectively.</para> <para>When parsing, systemd will also accept relative time @@ -157,27 +158,34 @@ 00:00.</para> <para>Examples for valid timestamps and their normalized form - (assuming the current time was 2012-11-23 18:15:22):</para> + (assuming the current time was 2012-11-23 18:15:22 and the timezone + was UTC+8, for example TZ=Asia/Shanghai):</para> <programlisting>Fri 2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13 2012-11-23 11:12:13 → Fri 2012-11-23 11:12:13 - 2012-11-23 → Fri 2012-11-23 00:00:00 - 12-11-23 → Fri 2012-11-23 00:00:00 - 11:12:13 → Fri 2012-11-23 11:12:13 - 11:12 → Fri 2012-11-23 11:12:00 - now → Fri 2012-11-23 18:15:22 - today → Fri 2012-11-23 00:00:00 - yesterday → Fri 2012-11-22 00:00:00 - tomorrow → Fri 2012-11-24 00:00:00 - +3h30min → Fri 2012-11-23 21:45:22 - -5s → Fri 2012-11-23 18:15:17 - 11min ago → Fri 2012-11-23 18:04:22 - @1395716396 → Tue 2014-03-25 03:59:56</programlisting> +2012-11-23 11:12:13 UTC → Fri 2012-11-23 19:12:13 + 2012-11-23 → Fri 2012-11-23 00:00:00 + 12-11-23 → Fri 2012-11-23 00:00:00 + 11:12:13 → Fri 2012-11-23 11:12:13 + 11:12:13.9900009 → Fri 2012-11-23 11:12:13 + format_timestamp_us: Fri 2012-11-23 11:12:13.990000 + 11:12 → Fri 2012-11-23 11:12:00 + now → Fri 2012-11-23 18:15:22 + today → Fri 2012-11-23 00:00:00 + today UTC → Fri 2012-11-23 16:00:00 + yesterday → Fri 2012-11-22 00:00:00 + tomorrow → Fri 2012-11-24 00:00:00 + +3h30min → Fri 2012-11-23 21:45:22 + +3h30min UTC → -EINVAL + -5s → Fri 2012-11-23 18:15:17 + 11min ago → Fri 2012-11-23 18:04:22 + 11min ago UTC → -EINVAL + @1395716396 → Tue 2014-03-25 03:59:56</programlisting> <para>Note that timestamps printed by systemd will not be parsed correctly by systemd, as the timezone specification is not accepted, and printing timestamps is subject to locale settings - for the weekday while parsing only accepts English weekday + for the weekday, while parsing only accepts English weekday names.</para> <para>In some cases, systemd will display a relative timestamp @@ -226,7 +234,8 @@ second component is not specified, <literal>:00</literal> is assumed.</para> - <para>Timezone names may not be specified.</para> + <para>A timezone specification is not expected, unless it is given + as the literal string "UTC", similarly to timestamps.</para> <para>The special expressions <literal>minutely</literal>, @@ -242,8 +251,8 @@ <literal>*-*-01 00:00:00</literal>, <literal>Mon *-*-* 00:00:00</literal>, <literal>*-01-01 00:00:00</literal>, - <literal>*-01,04,07,10-01 00:00:0</literal> and - <literal>*-01,07-01 00:00:00</literal> respectively. + <literal>*-01,04,07,10-01 00:00:00</literal> and + <literal>*-01,07-01 00:00:00</literal>, respectively. </para> <para>Examples for valid timestamps and their @@ -251,31 +260,33 @@ <programlisting> Sat,Thu,Mon-Wed,Sat-Sun → Mon-Thu,Sat,Sun *-*-* 00:00:00 Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00 - Wed *-1 → Wed *-*-01 00:00:00 - Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00 - Wed, 17:48 → Wed *-*-* 17:48:00 + Wed *-1 → Wed *-*-01 00:00:00 + Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00 + Wed, 17:48 → Wed *-*-* 17:48:00 Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 - *-*-7 0:0:0 → *-*-07 00:00:00 - 10-15 → *-10-15 00:00:00 + *-*-7 0:0:0 → *-*-07 00:00:00 + 10-15 → *-10-15 00:00:00 monday *-12-* 17:00 → Mon *-12-* 17:00:00 Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45 12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00 mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45 - 03-05 08:05:40 → *-03-05 08:05:40 - 08:05:40 → *-*-* 08:05:40 - 05:40 → *-*-* 05:40:00 + 03-05 08:05:40 → *-03-05 08:05:40 + 08:05:40 → *-*-* 08:05:40 + 05:40 → *-*-* 05:40:00 Sat,Sun 12-05 08:05:40 → Sat,Sun *-12-05 08:05:40 - Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40 - 2003-03-05 05:40 → 2003-03-05 05:40:00 - 2003-03-05 → 2003-03-05 00:00:00 - 03-05 → *-03-05 00:00:00 - hourly → *-*-* *:00:00 - daily → *-*-* 00:00:00 - monthly → *-*-01 00:00:00 - weekly → Mon *-*-* 00:00:00 - yearly → *-01-01 00:00:00 - annually → *-01-01 00:00:00 - *:2/3 → *-*-* *:02/3:00</programlisting> + Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40 + 2003-03-05 05:40 → 2003-03-05 05:40:00 + 2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC + 2003-03-05 → 2003-03-05 00:00:00 + 03-05 → *-03-05 00:00:00 + hourly → *-*-* *:00:00 + daily → *-*-* 00:00:00 + daily UTC → *-*-* 00:00:00 UTC + monthly → *-*-01 00:00:00 + weekly → Mon *-*-* 00:00:00 + yearly → *-01-01 00:00:00 + annually → *-01-01 00:00:00 + *:2/3 → *-*-* *:02/3:00</programlisting> <para>Calendar events are used by timer units, see <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry> diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 20890f2270..8cf6c4683b 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -1,4 +1,4 @@ -<?xml version='1.0'?> <!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> @@ -73,19 +73,29 @@ <filename>foo.timer</filename> activates a matching service <filename>foo.service</filename>. The unit to activate may be controlled by <varname>Unit=</varname> (see below).</para> + </refsect1> + + <refsect1> + <title>Automatic Dependencies</title> + + <para>Timer units automatically gain a <varname>Before=</varname> + dependency on the service they are supposed to activate.</para> <para>Unless <varname>DefaultDependencies=</varname> is set to <option>false</option>, all timer units will implicitly have - dependencies of type <varname>Conflicts=</varname> and - <varname>Before=</varname> on <filename>shutdown.target</filename> - to ensure that they are stopped cleanly prior to system shutdown. - Timer units with at least one <varname>OnCalendar=</varname> - directive will have an additional <varname>After=</varname> - dependency on <filename>timer-sync.target</filename> to avoid - being started before the system clock has been correctly set. Only - timer units involved with early boot or late system shutdown - should disable the <varname>DefaultDependencies=</varname> - option.</para> + dependencies of type <varname>Requires=</varname> and + <varname>After=</varname> on <filename>sysinit.target</filename>, + a dependency of type <varname>Before=</varname> on + <filename>timers.target</filename>, as well as + <varname>Conflicts=</varname> and <varname>Before=</varname> on + <filename>shutdown.target</filename> to ensure that they are + stopped cleanly prior to system shutdown. Timer units with at + least one <varname>OnCalendar=</varname> directive will have an + additional <varname>After=</varname> dependency on + <filename>timer-sync.target</filename> to avoid being started + before the system clock has been correctly set. Only timer units + involved with early boot or late system shutdown should disable + the <varname>DefaultDependencies=</varname> option.</para> </refsect1> <refsect1> @@ -127,7 +137,7 @@ boot-up. The argument may also include time units. Example: "OnBootSec=5h 30min" means 5 hours and 30 minutes after boot-up. For details about the syntax of time spans, see - <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> <para>If a timer configured with <varname>OnBootSec=</varname> or <varname>OnStartupSec=</varname> is already in the past diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 8985b6b940..5b12378eda 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -1,4 +1,4 @@ -<?xml version='1.0'?> <!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ <!ENTITY % entities SYSTEM "custom-entities.ent" > @@ -60,7 +60,6 @@ <filename><replaceable>target</replaceable>.target</filename>, <filename><replaceable>path</replaceable>.path</filename>, <filename><replaceable>timer</replaceable>.timer</filename>, - <filename><replaceable>snapshot</replaceable>.snapshot</filename>, <filename><replaceable>slice</replaceable>.slice</filename>, <filename><replaceable>scope</replaceable>.scope</filename></para> @@ -90,7 +89,7 @@ swap file or partition, a start-up target, a watched file system path, a timer controlled and supervised by <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - a temporary system state snapshot, a resource management slice or + a resource management slice or a group of externally created processes. The syntax is inspired by <ulink url="http://standards.freedesktop.org/desktop-entry-spec/latest/">XDG @@ -115,8 +114,7 @@ <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>. - <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>. + <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>. </para> @@ -186,8 +184,8 @@ be parsed after the file itself is parsed. This is useful to alter or add configuration settings to a unit, without having to modify their unit files. Make sure that the file that is included has the - appropriate section headers before any directive. Note that for - instanced units this logic will first look for the instance + appropriate section headers before any directive. Note that, for + instanced units, this logic will first look for the instance <literal>.d/</literal> subdirectory and read its <literal>.conf</literal> files, followed by the template <literal>.d/</literal> subdirectory and reads its @@ -197,19 +195,13 @@ consider it mostly obsolete, and want people to use .d/ drop-ins instead. --> - <para>Note that while systemd offers a flexible dependency system - between units it is recommended to use this functionality only - sparingly and instead rely on techniques such as bus-based or - socket-based activation which make dependencies implicit, - resulting in a both simpler and more flexible system.</para> - <para>Some unit names reflect paths existing in the file system namespace. Example: a device unit <filename>dev-sda.device</filename> refers to a device with the device node <filename noindex='true'>/dev/sda</filename> in the file system namespace. If this applies, a special way to escape the path name is used, so that the result is usable as part of a - filename. Basically, given a path, "/" is replaced by "-" and all + filename. Basically, given a path, "/" is replaced by "-", and all other characters which are not ASCII alphanumerics are replaced by C-style "\x2d" escapes (except that "_" is never replaced and "." is only replaced when it would be the first character in the @@ -256,6 +248,31 @@ </refsect1> <refsect1> + <title>Automatic Dependencies</title> + + <para>Note that while systemd offers a flexible dependency system + between units it is recommended to use this functionality only + sparingly and instead rely on techniques such as bus-based or + socket-based activation which make dependencies implicit, + resulting in a both simpler and more flexible system.</para> + + <para>A number of unit dependencies are automatically established, + depending on unit configuration. On top of that, for units with + <varname>DefaultDependencies=yes</varname> (the default) a couple + of additional dependencies are added. The precise effect of + <varname>DefaultDependencies=yes</varname> depends on the unit + type (see below).</para> + + <para>If <varname>DefaultDependencies=yes</varname> is set, units + that are referenced by other units of type + <filename>.target</filename> via a <varname>Wants=</varname> or + <varname>Requires=</varname> dependency might automatically gain + an <varname>Before=</varname> dependency too. See + <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details.</para> + </refsect1> + + <refsect1> <title>Unit File Load Path</title> <para>Unit files are loaded from a set of paths determined during @@ -263,10 +280,8 @@ in directories listed earlier override files with the same name in directories lower in the list.</para> - <para>When systemd is running in user mode - (<option>--user</option>) and the variable - <varname>$SYSTEMD_UNIT_PATH</varname> is set, the contents of this - variable overrides the unit load path. If + <para>When the variable <varname>$SYSTEMD_UNIT_PATH</varname> is set, + the contents of this variable overrides the unit load path. If <varname>$SYSTEMD_UNIT_PATH</varname> ends with an empty component (<literal>:</literal>), the usual unit load path will be appended to the contents of the variable.</para> @@ -365,7 +380,7 @@ <refsect1> <title>[Unit] Section Options</title> - <para>Unit file may include a [Unit] section, which carries + <para>The unit file may include a [Unit] section, which carries generic information about the unit that is not dependent on the type of unit:</para> @@ -424,7 +439,7 @@ with <varname>After=</varname> or <varname>Before=</varname>, then both units will be started simultaneously and without any delay between them if <filename>foo.service</filename> is - activated. Often it is a better choice to use + activated. Often, it is a better choice to use <varname>Wants=</varname> instead of <varname>Requires=</varname> in order to achieve a system that is more robust when dealing with failing services.</para> @@ -432,32 +447,14 @@ <para>Note that dependencies of this type may also be configured outside of the unit configuration file by adding a symlink to a <filename>.requires/</filename> directory - accompanying the unit file. For details see + accompanying the unit file. For details, see above.</para></listitem> </varlistentry> <varlistentry> - <term><varname>RequiresOverridable=</varname></term> - - <listitem><para>Similar to <varname>Requires=</varname>. - Dependencies listed in <varname>RequiresOverridable=</varname> - which cannot be fulfilled or fail to start are ignored if the - startup was explicitly requested by the user. If the start-up - was pulled in indirectly by some dependency or automatic - start-up of units that is not requested by the user, this - dependency must be fulfilled and otherwise the transaction - fails. Hence, this option may be used to configure - dependencies that are normally honored unless the user - explicitly starts up the unit, in which case whether they - failed or not is irrelevant.</para></listitem> - - </varlistentry> - <varlistentry> <term><varname>Requisite=</varname></term> - <term><varname>RequisiteOverridable=</varname></term> - <listitem><para>Similar to <varname>Requires=</varname> and - <varname>RequiresOverridable=</varname>, respectively. + <listitem><para>Similar to <varname>Requires=</varname>. However, if the units listed here are not started already, they will not be started and the transaction will fail immediately. </para></listitem> @@ -654,21 +651,11 @@ </varlistentry> <varlistentry> - <term><varname>IgnoreOnSnapshot=</varname></term> - - <listitem><para>Takes a boolean argument. If - <option>true</option>, this unit will not be included in - snapshots. Defaults to <option>true</option> for device and - snapshot units, <option>false</option> for the - others.</para></listitem> - </varlistentry> - - <varlistentry> <term><varname>StopWhenUnneeded=</varname></term> <listitem><para>Takes a boolean argument. If <option>true</option>, this unit will be stopped when it is no - longer used. Note that in order to minimize the work to be + longer used. Note that, in order to minimize the work to be executed, systemd will not stop units by default unless they are conflicting with other units, or the user explicitly requested their shut down. If this option is set, a unit will @@ -730,7 +717,7 @@ <term><varname>JobTimeoutAction=</varname></term> <term><varname>JobTimeoutRebootArgument=</varname></term> - <listitem><para>When a job for this unit is queued a time-out + <listitem><para>When a job for this unit is queued, a time-out may be configured. If this time limit is reached, the job will be cancelled, the unit however will not change state or even enter the <literal>failed</literal> mode. This value defaults @@ -781,8 +768,8 @@ <term><varname>ConditionFileNotEmpty=</varname></term> <term><varname>ConditionFileIsExecutable=</varname></term> - <!-- We don't document ConditionNull= - here as it is not particularly + <!-- We do not document ConditionNull= + here, as it is not particularly useful and probably just confusing. --> @@ -856,7 +843,8 @@ <varname>lxc</varname>, <varname>lxc-libvirt</varname>, <varname>systemd-nspawn</varname>, - <varname>docker</varname> to test + <varname>docker</varname>, + <varname>rkt</varname> to test against a specific implementation. See <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry> for a full list of known virtualization technologies and their @@ -887,7 +875,7 @@ <para><varname>ConditionSecurity=</varname> may be used to check whether the given security module is enabled on the - system. Currently the recognized values values are + system. Currently, the recognized values values are <varname>selinux</varname>, <varname>apparmor</varname>, <varname>ima</varname>, @@ -1027,10 +1015,10 @@ <listitem><para>Similar to the <varname>ConditionArchitecture=</varname>, - <varname>ConditionVirtualization=</varname>, ... condition - settings described above these settings add assertion checks + <varname>ConditionVirtualization=</varname>, etc., condition + settings described above, these settings add assertion checks to the start-up of the unit. However, unlike the conditions - settings any assertion setting that is not met results in + settings, any assertion setting that is not met results in failure of the start job it was triggered by.</para></listitem> </varlistentry> @@ -1045,22 +1033,6 @@ units.</para></listitem> </varlistentry> - <varlistentry> - <term><varname>NetClass=</varname></term> - <listitem><para>Configures a network class number to assign to the - unit. This value will be set to the - <literal>net_cls.class_id</literal> property of the - <literal>net_cls</literal> cgroup of the unit. The directive - accepts a numerical value (for fixed number assignment) and the keyword - <literal>auto</literal> (for dynamic allocation). Network traffic of - all processes inside the unit will have the network class ID assigned - by the kernel. Also see - the kernel docs for - <ulink url="https://www.kernel.org/doc/Documentation/cgroups/net_cls.txt">net_cls controller</ulink> - and - <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>. - </para></listitem> - </varlistentry> </variablelist> </refsect1> @@ -1237,22 +1209,22 @@ <row> <entry><literal>%u</literal></entry> <entry>User name</entry> - <entry>This is the name of the configured user of the unit, or (if none is set) the user running the systemd instance.</entry> + <entry>This is the name of the user running the service manager instance. In case of the system manager this resolves to <literal>root</literal>.</entry> </row> <row> <entry><literal>%U</literal></entry> <entry>User UID</entry> - <entry>This is the numeric UID of the configured user of the unit, or (if none is set) the user running the systemd user instance. Note that this specifier is not available for units run by the systemd system instance (as opposed to those run by a systemd user instance), unless the user has been configured as a numeric UID in the first place or the configured user is the root user.</entry> + <entry>This is the numeric UID of the user running the service manager instance. In case of the system manager this resolves to <literal>0</literal>.</entry> </row> <row> <entry><literal>%h</literal></entry> <entry>User home directory</entry> - <entry>This is the home directory of the configured user of the unit, or (if none is set) the user running the systemd user instance. Similar to <literal>%U</literal>, this specifier is not available for units run by the systemd system instance, unless the configured user is the root user.</entry> + <entry>This is the home directory of the user running the service manager instance. In case of the system manager this resolves to <literal>/root</literal>.</entry> </row> <row> <entry><literal>%s</literal></entry> <entry>User shell</entry> - <entry>This is the shell of the configured user of the unit, or (if none is set) the user running the systemd user instance. Similar to <literal>%U</literal>, this specifier is not available for units run by the systemd system instance, unless the configured user is the root user.</entry> + <entry>This is the shell of the user running the service manager instance. In case of the system manager this resolves to <literal>/bin/sh</literal>.</entry> </row> <row> <entry><literal>%m</literal></entry> @@ -1448,7 +1420,6 @@ PrivateTmp=yes</programlisting> <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.scope</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>, diff --git a/man/systemd.xml b/man/systemd.xml index 8d74ca49c3..6de18f8294 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -119,7 +119,7 @@ run a system instance, even if the process ID is not 1, i.e. systemd is not run as init process. <option>--user</option> does the opposite, running a user instance even if the process - ID is 1. Normally it should not be necessary to pass these + ID is 1. Normally, it should not be necessary to pass these options, as systemd automatically detects the mode it is started in. These options are hence of little use except for debugging. Note that it is not supported booting and @@ -142,7 +142,7 @@ <term><option>--crash-vt=</option><replaceable>VT</replaceable></term> <listitem><para>Switch to a specific virtual console (VT) on - crash. Takes a positive integer in the range 1..63, or a + crash. Takes a positive integer in the range 1–63, or a boolean argument. If an integer is passed, selects which VT to switch to. If <constant>yes</constant>, the VT kernel messages are written to is selected. If <constant>no</constant>, no VT @@ -289,12 +289,12 @@ <orderedlist> <listitem><para>Service units, which start and control daemons - and the processes they consist of. For details see + and the processes they consist of. For details, see <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem> <listitem><para>Socket units, which encapsulate local IPC or network sockets in the system, useful for socket-based - activation. For details about socket units see + activation. For details about socket units, see <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>, for details on socket-based activation and other forms of activation, see @@ -306,7 +306,7 @@ <listitem><para>Device units expose kernel devices in systemd and may be used to implement device-based activation. For - details see + details, see <citerefentry><refentrytitle>systemd.device</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem> <listitem><para>Mount units control mount points in the file @@ -318,12 +318,6 @@ boot-up. See <citerefentry><refentrytitle>systemd.automount</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem> - <listitem><para>Snapshot units can be used to temporarily save - the state of the set of systemd units, which later may be - restored by activating the saved snapshot unit. For more - information see - <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem> - <listitem><para>Timer units are useful for triggering activation of other units based on timers. You may find details in <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem> @@ -379,7 +373,7 @@ <para>On boot systemd activates the target unit <filename>default.target</filename> whose job is to activate on-boot services and other on-boot units by pulling them in via - dependencies. Usually the unit name is just an alias (symlink) for + dependencies. Usually, the unit name is just an alias (symlink) for either <filename>graphical.target</filename> (for fully-featured boots into the UI) or <filename>multi-user.target</filename> (for limited console-only boots for use in embedded or server @@ -448,7 +442,7 @@ <para>Units may be generated dynamically at boot and system manager reload time, for example based on other configuration - files or parameters passed on the kernel command line. For details see + files or parameters passed on the kernel command line. For details, see <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> <para>Systems which invoke systemd in a container or initrd @@ -562,9 +556,9 @@ <filename>ctrl-alt-del.target</filename> unit. This is mostly equivalent to <command>systemctl start ctl-alt-del.target</command>. If this signal is received more - often than 7 times per 2s an immediate reboot is triggered. + than 7 times per 2s, an immediate reboot is triggered. Note that pressing Ctrl-Alt-Del on the console will trigger - this signal. Hence, if a reboot is hanging pressing + this signal. Hence, if a reboot is hanging, pressing Ctrl-Alt-Del more than 7 times in 2s is a relatively safe way to trigger an immediate reboot.</para> @@ -606,7 +600,7 @@ <term><constant>SIGUSR2</constant></term> <listitem><para>When this signal is received the systemd - manager will log its complete state in human readable form. + manager will log its complete state in human-readable form. The data logged is the same as printed by <command>systemd-analyze dump</command>.</para></listitem> </varlistentry> @@ -895,11 +889,11 @@ <term><varname>systemd.crash_chvt=</varname></term> <listitem><para>Takes a positive integer, or a boolean - argument. If a positive integer (in the range 1..63) is - specified the system manager (PID 1) will activate the specified + argument. If a positive integer (in the range 1–63) is + specified, the system manager (PID 1) will activate the specified virtual terminal (VT) when it crashes. Defaults to <constant>no</constant>, meaning that no such switch is - attempted. If set to <constant>yes</constant> the VT the + attempted. If set to <constant>yes</constant>, the VT the kernel messages are written to is selected.</para></listitem> </varlistentry> @@ -945,7 +939,7 @@ like <option>false</option> until a service fails or there is a significant delay in boot. Defaults to <option>yes</option>, unless <option>quiet</option> is passed - as kernel command line option in which case it defaults to + as kernel command line option, in which case it defaults to <constant>auto</constant>.</para></listitem> </varlistentry> @@ -1061,7 +1055,7 @@ <listitem><para>Set the system locale to use. This overrides the settings in <filename>/etc/locale.conf</filename>. For - more information see + more information, see <citerefentry project='man-pages'><refentrytitle>locale.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> and <citerefentry project='man-pages'><refentrytitle>locale</refentrytitle><manvolnum>7</manvolnum></citerefentry>. diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml index 11cb83388f..42b53b2759 100644 --- a/man/sysusers.d.xml +++ b/man/sysusers.d.xml @@ -121,7 +121,7 @@ u root 0 "Superuser" /root</programlisting> <term><varname>r</varname></term> <listitem><para>Add a range of numeric UIDs/GIDs to the pool to allocate new UIDs and GIDs from. If no line of this type - is specified the range of UIDs/GIDs is set to some + is specified, the range of UIDs/GIDs is set to some compiled-in default. Note that both UIDs and GIDs are allocated from the same pool, in order to ensure that users and groups of the same name are likely to carry the same @@ -143,32 +143,32 @@ u root 0 "Superuser" /root</programlisting> all system and group names with the underscore, and avoiding too generic names.</para> - <para>For <varname>m</varname> lines this field should contain + <para>For <varname>m</varname> lines, this field should contain the user name to add to a group.</para> - <para>For lines of type <varname>r</varname> this field should + <para>For lines of type <varname>r</varname>, this field should be set to <literal>-</literal>.</para> </refsect2> <refsect2> <title>ID</title> - <para>For <varname>u</varname> and <varname>g</varname> the - numeric 32bit UID or GID of the user/group. Do not use IDs 65535 + <para>For <varname>u</varname> and <varname>g</varname>, the + numeric 32-bit UID or GID of the user/group. Do not use IDs 65535 or 4294967295, as they have special placeholder meanings. Specify <literal>-</literal> for automatic UID/GID allocation for the user or group. Alternatively, specify an absolute path - in the file system. In this case the UID/GID is read from the + in the file system. In this case, the UID/GID is read from the path's owner/group. This is useful to create users whose UID/GID match the owners of pre-existing files (such as SUID or SGID binaries).</para> - <para>For <varname>m</varname> lines this field should contain + <para>For <varname>m</varname> lines, this field should contain the group name to add to a user to.</para> - <para>For lines of type <varname>r</varname> this field should + <para>For lines of type <varname>r</varname>, this field should be set to a UID/GID range in the format - <literal>FROM-TO</literal> where both values are formatted as + <literal>FROM-TO</literal>, where both values are formatted as decimal ASCII numbers. Alternatively, a single UID/GID may be specified formatted as decimal ASCII numbers.</para> </refsect2> @@ -188,7 +188,7 @@ u root 0 "Superuser" /root</programlisting> <refsect2> <title>Home Directory</title> - <para>The home directory for a new system user. If omitted + <para>The home directory for a new system user. If omitted, defaults to the root directory. It is recommended to not unnecessarily specify home directories for system users, unless software strictly requires one to be set.</para> @@ -207,7 +207,7 @@ u root 0 "Superuser" /root</programlisting> <para>Note that <command>systemd-sysusers</command> will do nothing if the specified users or groups already exist, so - normally there no reason to override + normally, there is no reason to override <filename>sysusers.d</filename> vendor configuration, except to block certain users or groups from being created.</para> </refsect1> diff --git a/man/timedatectl.xml b/man/timedatectl.xml index c439bc56ed..415e2c799a 100644 --- a/man/timedatectl.xml +++ b/man/timedatectl.xml @@ -108,7 +108,7 @@ on. Note that whether network time synchronization is on simply reflects whether the <filename>systemd-timesyncd.service</filename> unit is - enabled. Even if this command shows the status as off a + enabled. Even if this command shows the status as off, a different service might still synchronize the clock with the network.</para></listitem> </varlistentry> @@ -179,10 +179,10 @@ <para>Note that even if time synchronization is turned off with this command, another unrelated system service might - still synchronize the clock with the network. Also note that - strictly speaking + still synchronize the clock with the network. Also note that, + strictly speaking, <filename>systemd-timesyncd.service</filename> does more than - just network time synchronization as it ensures a monotonic + just network time synchronization, as it ensures a monotonic clock on systems without RTC even if no network is available. See <citerefentry><refentrytitle>systemd-timesyncd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> diff --git a/man/timesyncd.conf.xml b/man/timesyncd.conf.xml index c883685c97..10c2de89f6 100644 --- a/man/timesyncd.conf.xml +++ b/man/timesyncd.conf.xml @@ -72,7 +72,7 @@ <varlistentry> <term><varname>NTP=</varname></term> - <listitem><para>A space separated list of NTP server host + <listitem><para>A space-separated list of NTP server host names or IP addresses. During runtime this list is combined with any per-interface NTP servers acquired from <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. @@ -84,7 +84,7 @@ <varlistentry> <term><varname>FallbackNTP=</varname></term> - <listitem><para>A space separated list of NTP server host + <listitem><para>A space-separated list of NTP server host names or IP addresses to be used as the fallback NTP servers. Any per-interface NTP servers obtained from <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 8d3ed37ae3..3f6128cb5b 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -1,5 +1,4 @@ -<?xml version="1.0"?> -<!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> <!-- This file is part of systemd. @@ -103,8 +102,8 @@ prefix and suffix of each other, then the prefix is always processed first, the suffix later. Lines that take globs are applied after those accepting no globs. If multiple operations - shall be applied on the same file (such as ACL, xattr, file - attribute adjustments) these are always done in the same fixed + shall be applied on the same file, (such as ACL, xattr, file + attribute adjustments), these are always done in the same fixed order. Otherwise, the files/directories are processed in the order they are listed.</para> @@ -171,8 +170,78 @@ <term><varname>v</varname></term> <listitem><para>Create a subvolume if the path does not exist yet and the file system supports this - (btrfs). Otherwise create a normal directory, in the same - way as <varname>d</varname>.</para></listitem> + (btrfs). Otherwise, create a normal directory, in the same + way as <varname>d</varname>. A subvolume created with this + line type is not assigned to any higher-level quota + group. For that, use <varname>q</varname> or + <varname>Q</varname>, which allow creating simple quota group + hierarchies, see below.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>q</varname></term> + <listitem><para>Similar to <varname>v</varname>. However, + makes sure that the subvolume will be assigned to the same + higher-level quota groups as the subvolume it has been + created in. This ensures that higher-level limits and + accounting applied to the parent subvolume also include the + specified subvolume. On non-btrfs file systems, this line + type is identical to <varname>d</varname>. If the subvolume + already exists and is already assigned to one or more higher + level quota groups, no change to the quota hierarchy is + made. Also see <varname>Q</varname> below. See <citerefentry + project='die-net'><refentrytitle>btrfs-qgroup</refentrytitle><manvolnum>8</manvolnum></citerefentry> + for details about the btrfs quota group + concept.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>Q</varname></term> + <listitem><para>Similar to <varname>q</varname>. However, + instead of copying the higher-level quota group assignments + from the parent as-is, the lowest quota group of the parent + subvolume is determined that is not the leaf quota + group. Then, an "intermediary" quota group is inserted that + is one level below this level, and shares the same ID part + as the specified subvolume. If no higher-level quota group + exists for the parent subvolume, a new quota group at level + 255 sharing the same ID as the specified subvolume is + inserted instead. This new intermediary quota group is then + assigned to the parent subvolume's higher-level quota + groups, and the specified subvolume's leaf quota group is + assigned to it.</para> + + <para>Effectively, this has a similar effect as + <varname>q</varname>, however introduces a new higher-level + quota group for the specified subvolume that may be used to + enforce limits and accounting to the specified subvolume and + children subvolume created within it. Thus, by creating + subvolumes only via <varname>q</varname> and + <varname>Q</varname>, a concept of "subtree quotas" is + implemented. Each subvolume for which <varname>Q</varname> + is set will get a "subtree" quota group created, and all + child subvolumes created within it will be assigned to + it. Each subvolume for which <varname>q</varname> is set + will not get such a "subtree" quota group, but it is ensured + that they are added to the same "subtree" quota group as their + immediate parents.</para> + + <para>It is recommended to use + <varname>Q</varname> for subvolumes that typically contain + further subvolumes, and where it is desirable to have + accounting and quota limits on all child subvolumes + together. Examples for <varname>Q</varname> are typically + <filename>/home</filename> or + <filename>/var/lib/machines</filename>. In contrast, + <varname>q</varname> should be used for subvolumes that + either usually do not include further subvolumes or where no + accounting and quota limits are needed that apply to all + child subvolumes together. Examples for <varname>q</varname> + are typically <filename>/var</filename> or + <filename>/var/tmp</filename>. As with <varname>Q</varname>, + <varname>q</varname> has no effect on the quota group + hierarchy if the subvolume exists and already has at least + one higher-level quota group assigned.</para></listitem> </varlistentry> <varlistentry> @@ -318,15 +387,15 @@ <varname>+</varname> (the default one) causes the attribute(s) to be added; <varname>-</varname> causes the attribute(s) to be removed; <varname>=</varname> causes the - attributes to set exactly as the following letters. The + attributes to be set exactly as the following letters. The letters <literal>aAcCdDeijsStTu</literal> select the new attributes for the files, see - <citerefentry><refentrytitle>chattr</refentrytitle> + <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle> <manvolnum>1</manvolnum></citerefentry> for further information. </para> <para>Passing only <varname>=</varname> as argument resets all the file attributes listed above. It has to be pointed - out that the <varname>=</varname> prefix, limits itself to + out that the <varname>=</varname> prefix limits itself to the attributes corresponding to the letters listed here. All other attributes will be left untouched. Does not follow symlinks.</para> @@ -345,7 +414,7 @@ <term><varname>a</varname></term> <term><varname>a+</varname></term> <listitem><para>Set POSIX ACLs (access control lists). If - suffixed with <varname>+</varname>, specified entries will + suffixed with <varname>+</varname>, the specified entries will be added to the existing set. <command>systemd-tmpfiles</command> will automatically add the required base entries for user and group based on the @@ -468,7 +537,7 @@ <para>The user and group to use for this file or directory. This may either be a numeric user/group ID or a user or group name. If omitted or when set to <literal>-</literal>, the - default 0 (root) is used. For <varname>z</varname>, + default 0 (root) is used. For <varname>z</varname> and <varname>Z</varname> lines, when omitted or when set to <literal>-</literal>, the file ownership will not be modified. These parameters are ignored for <varname>x</varname>, @@ -483,16 +552,16 @@ delete when cleaning. If a file or directory is older than the current time minus the age field, it is deleted. The field format is a series of integers each followed by one of the - following postfixes for the respective time units: + following suffixes for the respective time units: <constant>s</constant>, <constant>m</constant> or <constant>min</constant>, <constant>h</constant>, <constant>d</constant>, <constant>w</constant>, - <constant>ms</constant>, + <constant>ms</constant>, and <constant>us</constant>, - respectively meaning seconds, minutes, hours, days, weeks, - milliseconds, and microseconds. Full names of the time units can + meaning seconds, minutes, hours, days, weeks, + milliseconds, and microseconds, respectively. Full names of the time units can be used too. </para> @@ -504,12 +573,12 @@ <para>When the age is set to zero, the files are cleaned unconditionally.</para> - <para>The age field only applies to lines - starting with <varname>d</varname>, - <varname>D</varname>, and - <varname>x</varname>. If omitted or set to - <literal>-</literal>, no automatic clean-up is - done.</para> + <para>The age field only applies to lines starting with + <varname>d</varname>, <varname>D</varname>, + <varname>v</varname>, <varname>q</varname>, + <varname>Q</varname>, <varname>C</varname>, <varname>x</varname> + and <varname>X</varname>. If omitted or set to + <literal>-</literal>, no automatic clean-up is done.</para> <para>If the age field starts with a tilde character <literal>~</literal>, the clean-up is only applied to files and @@ -521,19 +590,19 @@ <title>Argument</title> <para>For <varname>L</varname> lines determines the destination - path of the symlink. For <varname>c</varname>, - <varname>b</varname> determines the major/minor of the device + path of the symlink. For <varname>c</varname> and + <varname>b</varname>, determines the major/minor of the device node, with major and minor formatted as integers, separated by <literal>:</literal>, e.g. <literal>1:3</literal>. For <varname>f</varname>, <varname>F</varname>, and - <varname>w</varname> may be used to specify a short string that + <varname>w</varname>, the argument may be used to specify a short string that is written to the file, suffixed by a newline. For <varname>C</varname>, specifies the source file or - directory. For <varname>t</varname>, <varname>T</varname> + directory. For <varname>t</varname> and <varname>T</varname>, determines extended attributes to be set. For - <varname>a</varname>, <varname>A</varname> determines ACL - attributes to be set. For <varname>h</varname>, - <varname>H</varname> determines the file attributes to + <varname>a</varname> and <varname>A</varname>, determines ACL + attributes to be set. For <varname>h</varname> and + <varname>H</varname>, determines the file attributes to set. Ignored for all other lines.</para> </refsect2> @@ -571,7 +640,9 @@ x /var/tmp/abrt/*</programlisting> <citerefentry project='man-pages'><refentrytitle>setfattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>setfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>getfacl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry> + <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry project='die-net'><refentrytitle>btrfs-subvolume</refentrytitle><manvolnum>8</manvolnum></citerefentry>, + <citerefentry project='die-net'><refentrytitle>btrfs-qgroup</refentrytitle><manvolnum>8</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/udev.xml b/man/udev.xml index 2e1655bf55..dd5563605c 100644 --- a/man/udev.xml +++ b/man/udev.xml @@ -470,7 +470,7 @@ <term><literal>program</literal></term> <listitem> <para>Execute an external program specified as the assigned - value and if it returns successfully + value and, if it returns successfully, import its output, which must be in environment key format. Path specification, command/argument separation, and quoting work like in <varname>RUN</varname>.</para> @@ -536,7 +536,7 @@ <varlistentry> <term><option>string_escape=<replaceable>none|replace</replaceable></option></term> <listitem> - <para>Usually control and other possibly unsafe characters are replaced + <para>Usually, control and other possibly unsafe characters are replaced in strings used for device naming. The mode of replacement can be specified with this option.</para> </listitem> diff --git a/man/udev_device_get_syspath.xml b/man/udev_device_get_syspath.xml index b3062ae4a8..ca9763fedf 100644 --- a/man/udev_device_get_syspath.xml +++ b/man/udev_device_get_syspath.xml @@ -181,7 +181,7 @@ <function>udev_device_get_parent_with_subsystem_devtype()</function> return a pointer to the parent device. No additional reference to this device is acquired, but the child device owns a reference - to such parent device. On failure, <constant>NULL</constant> + to such a parent device. On failure, <constant>NULL</constant> is returned.</para> <para>On success, <function>udev_device_get_is_initialized()</function> diff --git a/man/udev_device_new_from_syspath.xml b/man/udev_device_new_from_syspath.xml index 9c4ab7a1bf..11db1a0fab 100644 --- a/man/udev_device_new_from_syspath.xml +++ b/man/udev_device_new_from_syspath.xml @@ -127,7 +127,7 @@ <function>udev_device_new_from_subsystem_sysname</function>, and <function>udev_device_new_from_device_id</function> create the device object based on information found in - <filename>/sys</filename> annotated with properties from the udev-internal + <filename>/sys</filename>, annotated with properties from the udev-internal device database. A syspath is any subdirectory of <filename>/sys</filename>, with the restriction that a subdirectory of <filename>/sys/devices</filename> (or a symlink to one) represents a real device and as such must contain @@ -141,7 +141,7 @@ and <citerefentry><refentrytitle>udev_device_get_sysname</refentrytitle><manvolnum>3</manvolnum></citerefentry>) and <function>udev_device_new_from_device_id</function> looks up devices based on the provided - device id which is a special string in one of the following four forms: + device ID, which is a special string in one of the following four forms: <table> <title>Device ID strings</title> diff --git a/man/udev_enumerate_scan_devices.xml b/man/udev_enumerate_scan_devices.xml index 73566f5089..e0b6bfba32 100644 --- a/man/udev_enumerate_scan_devices.xml +++ b/man/udev_enumerate_scan_devices.xml @@ -112,7 +112,7 @@ <constant>NULL</constant> is returned.</para> <para><function>udev_enumerate_get_udev()</function> always - returns a pointer to the udev context that this enumerate + returns a pointer to the udev context that this enumerated object is associated with.</para> </refsect1> diff --git a/man/udev_list_entry.xml b/man/udev_list_entry.xml index 6e033bdc81..a1b531d52a 100644 --- a/man/udev_list_entry.xml +++ b/man/udev_list_entry.xml @@ -104,7 +104,7 @@ <function>udev_list_entry_get_name()</function> and <function>udev_list_entry_get_value()</function> return a pointer to a constant string representing the requested value. - The string is bound to the lifetime of the list-entry itself. + The string is bound to the lifetime of the list entry itself. On failure, <constant>NULL</constant> is returned.</para> </refsect1> diff --git a/man/udevadm.xml b/man/udevadm.xml index 8ef9e23aa2..8c1abd2770 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -202,7 +202,7 @@ </varlistentry> </variablelist> - <para>In addition an optional positional argument can be used + <para>In addition, an optional positional argument can be used to specify a device name or a sys path. It must start with <filename>/dev</filename> or <filename>/sys</filename> respectively.</para> @@ -317,7 +317,7 @@ <term><option>--name-match=<replaceable>NAME</replaceable></option></term> <listitem> <para>Trigger events for devices with a matching - device path. This options can be specified multiple + device path. This option can be specified multiple times.</para> </listitem> </varlistentry> @@ -338,7 +338,7 @@ </varlistentry> </variablelist> - <para>In addition optional positional arguments can be used + <para>In addition, optional positional arguments can be used to specify device names or sys paths. They must start with <filename>/dev</filename> or <filename>/sys</filename> respectively.</para> diff --git a/po/LINGUAS b/po/LINGUAS index db05932efd..2774a3228f 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -12,6 +12,7 @@ uk sv sr es +zh_CN zh_TW be be@latin diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 51254ec533..b56a9984c4 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -6,7 +6,6 @@ src/core/dbus-mount.c src/core/dbus-path.c src/core/dbus-service.c src/core/dbus-slice.c -src/core/dbus-snapshot.c src/core/dbus-socket.c src/core/dbus-swap.c src/core/dbus-target.c @@ -1,609 +1,609 @@ -# Danish translation for systemd.
-# Copyright (C) 2014 systemd's COPYRIGHT HOLDER
-# This file is distributed under the same license as the systemd package.
-# Daniel Machon <dmachon.dev@gmail.com>, 2015.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: systemd master\n"
-"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2015-10-07 19:30+0000\n"
-"PO-Revision-Date: 2015-10-07 19:30+0200\n"
-"Last-Translator: Daniel Machon <dmachon.dev@gmail.com>\n"
-"Language-Team: danish\n"
-"Language: da\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1
-msgid "Send passphrase back to system"
-msgstr "Send adgangssætning tilbage til systemet"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2
-msgid ""
-"Authentication is required to send the entered passphrase back to the system."
-msgstr ""
-"Autentificering er nødvendig for at sende adgangssætning tilbage til systemet."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3
-msgid "Manage system services or other units"
-msgstr "Håndtér system services eller andre enheder"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4
-msgid "Authentication is required to manage system services or other units."
-msgstr ""
-"Autentificering er nødvendig for at håndtere system services og andre enheder."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5
-msgid "Manage system service or unit files"
-msgstr "Håndtér system services eller enhedsfiler"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6
-msgid "Authentication is required to manage system service or unit files."
-msgstr ""
-"Autentificering er nødvendig for at håndtere system service eller enhedsfiler."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7
-msgid "Set or unset system and service manager environment variables"
-msgstr ""
-"Sæt eller fjern system- og service-forvalter miljøvariabler"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8
-msgid ""
-"Authentication is required to set or unset system and service manager "
-"environment variables."
-msgstr "Autentificering er nødvendig for at sætte eller fjerne system- "
-"og service-forvalter miljøvariabler."
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9
-msgid "Reload the systemd state"
-msgstr "Genindlæs systemd tilstand"
-
-#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10
-msgid "Authentication is required to reload the systemd state."
-msgstr "Autentificering er nødvendig for at genindlæse systemd tilstanden."
-
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1
-msgid "Set host name"
-msgstr "Sæt værtsnavn"
-
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2
-msgid "Authentication is required to set the local host name."
-msgstr "Autentificering er nødvendig for at sætte værtsnavn."
-
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3
-msgid "Set static host name"
-msgstr "Sæt statisk værstnavn"
-
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4
-msgid ""
-"Authentication is required to set the statically configured local host name, "
-"as well as the pretty host name."
-msgstr ""
-"Autentificering er nødvendig for at sætte det statisk konfigurerede lokale "
-"værtsnavn, lige så vel som det pæne værtsnavn."
-
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5
-msgid "Set machine information"
-msgstr "Sæt maskininformation."
-
-#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6
-msgid "Authentication is required to set local machine information."
-msgstr "Autentificering er nødvendig for at sætte lokal maskininformation."
-
-#: ../src/import/org.freedesktop.import1.policy.in.h:1
-msgid "Import a VM or container image"
-msgstr "Importér en VM eller container billede"
-
-#: ../src/import/org.freedesktop.import1.policy.in.h:2
-msgid "Authentication is required to import a VM or container image"
-msgstr ""
-"Autentificering er nødvendig for at importére en VM eller "
-"container billeder."
-
-#: ../src/import/org.freedesktop.import1.policy.in.h:3
-msgid "Export a VM or container image"
-msgstr "Exportér en VM eller container billede"
-
-#: ../src/import/org.freedesktop.import1.policy.in.h:4
-msgid "Authentication is required to export a VM or container image"
-msgstr "Autentificering er nødvendig for at exportére en VM eller container billede"
-
-#: ../src/import/org.freedesktop.import1.policy.in.h:5
-msgid "Download a VM or container image"
-msgstr "Hent en VM eller container billede"
-
-#: ../src/import/org.freedesktop.import1.policy.in.h:6
-msgid "Authentication is required to download a VM or container image"
-msgstr "Autentificering er nødvendig for at hente en VM eller container billede"
-
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:1
-msgid "Set system locale"
-msgstr "Sæt sprogindstillinger for systemet"
-
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:2
-msgid "Authentication is required to set the system locale."
-msgstr ""
-"Autentificering er nødvendig for at sætte sprogindstillinger "
-"for systemet."
-
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:3
-msgid "Set system keyboard settings"
-msgstr "Sæt tastaturindstillinger for systemet."
-
-#: ../src/locale/org.freedesktop.locale1.policy.in.h:4
-msgid "Authentication is required to set the system keyboard settings."
-msgstr ""
-"Autentificering er nødvendig for at sætte tastaturindstillinger "
-"for systemet."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:1
-msgid "Allow applications to inhibit system shutdown"
-msgstr "Tillad applikationer at hæmme system nedlukning"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:2
-msgid ""
-"Authentication is required for an application to inhibit system shutdown."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan hæmme "
-"system nedlukning."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:3
-msgid "Allow applications to delay system shutdown"
-msgstr "Tillad applikationer at forsinke system nedlukning"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:4
-msgid "Authentication is required for an application to delay system shutdown."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan forsinke "
-"system nedlukning."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:5
-msgid "Allow applications to inhibit system sleep"
-msgstr "Tillad applikationer at hæmme system dvale"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:6
-msgid "Authentication is required for an application to inhibit system sleep"
-msgstr "Autentificering er nødvendig for at en applikation kan hæmme system dvale"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:7
-msgid "Allow applications to delay system sleep"
-msgstr "Tillad applikationer at forsinke system dvale"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:8
-msgid "Authentication is required for an application to delay system sleep."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan forsinke system "
-"dvale."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:9
-msgid "Allow applications to inhibit automatic system suspend"
-msgstr "Tillad applikationer at hæmme automatisk system standby"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:10
-msgid ""
-"Authentication is required for an application to inhibit automatic system "
-"suspend."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan hæmme automatisk "
-"system standby."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:11
-msgid "Allow applications to inhibit system handling of the power key"
-msgstr "Tillad applikationer at hæmme systemhåndtering af tænd/sluk-knappen"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:12
-msgid ""
-"Authentication is required for an application to inhibit system handling of "
-"the power key."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "
-"af tænd/sluk-knappen."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:13
-msgid "Allow applications to inhibit system handling of the suspend key"
-msgstr "Tillad applikationer at hæmme systemhåndtering af standby-knappen"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:14
-msgid ""
-"Authentication is required for an application to inhibit system handling of "
-"the suspend key."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "
-"af standby-knappen."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:15
-msgid "Allow applications to inhibit system handling of the hibernate key"
-msgstr "Tillad applikationer at hæmme systemhåndtering af dvale-knappen"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:16
-msgid ""
-"Authentication is required for an application to inhibit system handling of "
-"the hibernate key."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan hæmme "
-"systemhåndtering af dvale-knappen."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:17
-msgid "Allow applications to inhibit system handling of the lid switch"
-msgstr ""
-"Tillad applikationer at hæmme systemhåndtering af skærmlukning"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:18
-msgid ""
-"Authentication is required for an application to inhibit system handling of "
-"the lid switch."
-msgstr ""
-"Autentificering er nødvendig for at en applikation kan hæmme systemhåndtering "
-"af skærmlukning."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:19
-msgid "Allow non-logged-in users to run programs"
-msgstr "Tillad brugere der ikke er logget ind, at køre programmer"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:20
-msgid "Authentication is required to run programs as a non-logged-in user."
-msgstr ""
-"Autentificering er nødvendig for at brugere, som ikke er logget ind, kan "
-"køre programmer."
-
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
-#: ../src/login/org.freedesktop.login1.policy.in.h:21
-msgid "Allow attaching devices to seats"
-msgstr "Tillad at montere af enheder til arbejdsstationer"
-
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
-#: ../src/login/org.freedesktop.login1.policy.in.h:22
-msgid "Authentication is required for attaching a device to a seat."
-msgstr ""
-"Autentificering er nødvendig for at montere en enhed til en "
-"arbejdsstation."
-
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
-#: ../src/login/org.freedesktop.login1.policy.in.h:23
-msgid "Flush device to seat attachments"
-msgstr "Nulstil enhed monteret til en arbejdsstation"
-
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
-#: ../src/login/org.freedesktop.login1.policy.in.h:24
-msgid ""
-"Authentication is required for resetting how devices are attached to seats."
-msgstr ""
-"Autentificering er nødvendig for at nulstille måden enheder er monteret "
-"arbejdsstationer."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:25
-msgid "Power off the system"
-msgstr "Sluk for systemet"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:26
-msgid "Authentication is required for powering off the system."
-msgstr "Autentificering er nødvendig for at slukke systemet"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:27
-msgid "Power off the system while other users are logged in"
-msgstr "Sluk systemet mens andre brugere er logget på"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:28
-msgid ""
-"Authentication is required for powering off the system while other users are "
-"logged in."
-msgstr ""
-"Autentificering er nødvendig for at slukke systemet mens andre brugere "
-"er logget på."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:29
-msgid "Power off the system while an application asked to inhibit it"
-msgstr ""
-"Sluk for systemet mens en applikation har forespurgt at hæmme det"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:30
-msgid ""
-"Authentication is required for powering off the system while an application "
-"asked to inhibit it."
-msgstr ""
-"Autentificering er nødvendig for at slukke systemet mens en applikation har "
-"forespurgt at hæmme det."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:31
-msgid "Reboot the system"
-msgstr "Genstart systemet"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:32
-msgid "Authentication is required for rebooting the system."
-msgstr "Autentificering er nødvendig for at genstarte systemet."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:33
-msgid "Reboot the system while other users are logged in"
-msgstr "Genstart systemet mens andre brugere er logget ind"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:34
-msgid ""
-"Authentication is required for rebooting the system while other users are "
-"logged in."
-msgstr ""
-"Autentificering er nødvendig for at genstarte systemet mens andre brugere "
-"er logget ind."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:35
-msgid "Reboot the system while an application asked to inhibit it"
-msgstr ""
-"Genstart systemet mens en applikation har forespurgt at hæmme det"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:36
-msgid ""
-"Authentication is required for rebooting the system while an application "
-"asked to inhibit it."
-msgstr ""
-"Autentificering er nødvendig for at genstarte systemet mens en applikation "
-"har forespurgt at hæmme det."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:37
-msgid "Suspend the system"
-msgstr "Sæt systemet på standby"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:38
-msgid "Authentication is required for suspending the system."
-msgstr "Autentificering er nødvendig for at sætte systemet på standby"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:39
-msgid "Suspend the system while other users are logged in"
-msgstr "Sæt systemet på standby mens andre brugere er logget på"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:40
-msgid ""
-"Authentication is required for suspending the system while other users are "
-"logged in."
-msgstr ""
-"Autentificering er nødvendig for at sætte systemet på standby, mens andre "
-"brugere er logget på."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:41
-msgid "Suspend the system while an application asked to inhibit it"
-msgstr ""
-"Sæt systemet på standby mens en applikation har forespurgt at hæmme"
-"det"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:42
-msgid ""
-"Authentication is required for suspending the system while an application "
-"asked to inhibit it."
-msgstr ""
-"Autentificering er nødvendig for at sætte systemet på standby, mens en "
-"applikation har forespurgt at hæmme det."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:43
-msgid "Hibernate the system"
-msgstr "Sæt systemet i dvale"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:44
-msgid "Authentication is required for hibernating the system."
-msgstr ""
-"Autentificering er nødvendig for at sætte systemet i dvale-tilstand."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:45
-msgid "Hibernate the system while other users are logged in"
-msgstr ""
-"Sæt systemet i dvale-tilstand mens andre brugere er logget på"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:46
-msgid ""
-"Authentication is required for hibernating the system while other users are "
-"logged in."
-msgstr ""
-"Autentificering er nødvendig for at sætte systemet i dvale-tilstand, mens "
-"andre brugere er logget på."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:47
-msgid "Hibernate the system while an application asked to inhibit it"
-msgstr "Sæt systemet i dvale-tilstand mens en applikation har forespurgt at "
-"hæmme det"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:48
-msgid ""
-"Authentication is required for hibernating the system while an application "
-"asked to inhibit it."
-msgstr ""
-"Autentificering er nødvendig for at sætte systemet i dvale tilstand, mens "
-"en applikation har forespurgt at hæmme det."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:49
-msgid "Manage active sessions, users and seats"
-msgstr "Håndtér aktive sessioner, brugere og arbejdsstationer"
-
-# www.freedesktop.org/wiki/Software/systemd/multiseat/
-#: ../src/login/org.freedesktop.login1.policy.in.h:50
-msgid ""
-"Authentication is required for managing active sessions, users and seats."
-msgstr ""
-"Autentificering er nødvendig for at håndtere aktive sessioner, brugere "
-"og arbejdsstationer."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:51
-msgid "Lock or unlock active sessions"
-msgstr "Lås eller oplås aktive sessioner"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:52
-msgid "Authentication is required to lock or unlock active sessions."
-msgstr ""
-"Autentificering er nødvendig for at låse eller oplåse aktive sessioner."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:53
-msgid "Allow indication to the firmware to boot to setup interface"
-msgstr "Tillad meddelelse til firmwaren om at starte op i opsætningsgrænseflade"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:54
-msgid ""
-"Authentication is required to indicate to the firmware to boot to setup "
-"interface."
-msgstr "Autentificering er nødvendig for at meddele firmwaren om at starte "
-"op i opsætningsgrænseflade."
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:55
-msgid "Set a wall message"
-msgstr "Sæt broadcast-besked"
-
-#: ../src/login/org.freedesktop.login1.policy.in.h:56
-msgid "Authentication is required to set a wall message"
-msgstr "Autentificering er nødvendig for at sætte en broadcast-besked"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:1
-msgid "Log into a local container"
-msgstr "Log på en lokal container"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:2
-msgid "Authentication is required to log into a local container."
-msgstr "Autentificering er nødvendig for at logge på en lokal container."
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:3
-msgid "Log into the local host"
-msgstr "Log på den lokale vært"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:4
-msgid "Authentication is required to log into the local host."
-msgstr "Auitentificering er nødvendig for at logge på den lokale vært."
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:5
-msgid "Acquire a shell in a local container"
-msgstr "Anskaf en shell i en lokal container"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:6
-msgid "Authentication is required to acquire a shell in a local container."
-msgstr ""
-"Autentificering er nødvendig for at anskaffe en shell i en lokal "
-"container."
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:7
-msgid "Acquire a shell on the local host"
-msgstr "Anskaf en shell på den lokale vært"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:8
-msgid "Authentication is required to acquire a shell on the local host."
-msgstr ""
-"Autentificering er nødvendig for at anskaffe en shell på den lokale vært."
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:9
-msgid "Acquire a pseudo TTY in a local container"
-msgstr "Anskaf en pseudo-TTY i en lokal container"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:10
-msgid ""
-"Authentication is required to acquire a pseudo TTY in a local container."
-msgstr ""
-"Autentificering er nødvendig for at anskaffe en pseudo-TTY i en lokal "
-"container."
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:11
-msgid "Acquire a pseudo TTY on the local host"
-msgstr "Anskaf en pseudo-TTY på den lokale vært"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:12
-msgid "Authentication is required to acquire a pseudo TTY on the local host."
-msgstr ""
-"Autentificering er nødvendig for at anskaffe en pseudo-TTY på den "
-"lokale vært."
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:13
-msgid "Manage local virtual machines and containers"
-msgstr "Håndtér lokale virtuelle maskiner og containere"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:14
-msgid ""
-"Authentication is required to manage local virtual machines and containers."
-msgstr ""
-"Autentificering er nødvendig for at håndtere lokale virtuelle maskiner og "
-"containere."
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:15
-msgid "Manage local virtual machine and container images"
-msgstr "Håndtér lokal virtuel maskine- og container billeder"
-
-#: ../src/machine/org.freedesktop.machine1.policy.in.h:16
-msgid ""
-"Authentication is required to manage local virtual machine and container "
-"images."
-msgstr ""
-"Autentificering er nødvendig for at håndtere lokal virtuel maskine- og "
-"container billeder."
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1
-msgid "Set system time"
-msgstr "Sæt tiden for systemet"
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2
-msgid "Authentication is required to set the system time."
-msgstr "Autentificering er nødvendig for at sætte tiden for systemet."
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3
-msgid "Set system timezone"
-msgstr "Sæt tidszone for systemet"
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4
-msgid "Authentication is required to set the system timezone."
-msgstr "Autentificering er nødvendig for at sætte tidszonen for systemet."
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5
-msgid "Set RTC to local timezone or UTC"
-msgstr "Sæt RTC til lokal tidszone eller UTC"
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6
-msgid ""
-"Authentication is required to control whether the RTC stores the local or "
-"UTC time."
-msgstr ""
-"Autentificering er nødvendig for at kontrollere hvorvidt RTC'en gemmer "
-"den lokale tid eller UTC tid."
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7
-msgid "Turn network time synchronization on or off"
-msgstr "Slå synkronisering af netværkstid til eller fra"
-
-#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8
-msgid ""
-"Authentication is required to control whether network time synchronization "
-"shall be enabled."
-msgstr ""
-"Autentificering er nødvendig for at kontrollere hvorvidt synkronisering af "
-"netværkstid skal aktiveres"
-
-#: ../src/core/dbus-unit.c:428
-msgid "Authentication is required to start '$(unit)'."
-msgstr "Autentificering er nødvendig for at starte '$(unit)'."
-
-#: ../src/core/dbus-unit.c:429
-msgid "Authentication is required to stop '$(unit)'."
-msgstr "Autentificering er nødvendig for at stoppe '$(unit)'."
-
-#: ../src/core/dbus-unit.c:430
-msgid "Authentication is required to reload '$(unit)'."
-msgstr "Autentificering er nødvendig for at genindlæse '$(unit)'."
-
-#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432
-msgid "Authentication is required to restart '$(unit)'."
-msgstr "Autentificering at nødvendig for at genstarte '$(unit)'."
-
-#: ../src/core/dbus-unit.c:535
-msgid "Authentication is required to kill '$(unit)'."
-msgstr "Autentificering er nødvendig for at eliminere '$(unit)'."
-
-#: ../src/core/dbus-unit.c:565
-msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
-msgstr ""
-"Autentificering er nødvendig for at nulstille \"fejl\" tilstanden på '$(unit)'."
-
-#: ../src/core/dbus-unit.c:597
-msgid "Authentication is required to set properties on '$(unit)'."
-msgstr ""
-"Autentificering er nødvendig for at sætte egenskaber på '$(unit)'."
-
-#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress"
-#~ msgstr ""
-#~ "Tryk Ctrl-C for at annulere alle igangværende kontrolleringer af "
-#~ "filsystemet"
-
-#~ msgid "Checking in progress on %d disk (%3.1f%% complete)"
-#~ msgid_plural "Checking in progress on %d disks (%3.1f%% complete)"
-#~ msgstr[0] "Igangværende kontrollering på %d disk (%3.1f%% færdig)"
-#~ msgstr[1] "Igangværende kontrollering på %d diske (%3.1f%% færdig)"
+# Danish translation for systemd. +# Copyright (C) 2014 systemd's COPYRIGHT HOLDER +# This file is distributed under the same license as the systemd package. +# Daniel Machon <dmachon.dev@gmail.com>, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: systemd master\n" +"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n" +"POT-Creation-Date: 2015-10-07 19:30+0000\n" +"PO-Revision-Date: 2015-10-07 19:30+0200\n" +"Last-Translator: Daniel Machon <dmachon.dev@gmail.com>\n" +"Language-Team: danish\n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 +msgid "Send passphrase back to system" +msgstr "Send adgangssætning tilbage til systemet" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "" +"Autentificering er nødvendig for at sende adgangssætning tilbage til systemet." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 +msgid "Manage system services or other units" +msgstr "HÃ¥ndtér system services eller andre enheder" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 +msgid "Authentication is required to manage system services or other units." +msgstr "" +"Autentificering er nødvendig for at hÃ¥ndtere system services og andre enheder." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5 +msgid "Manage system service or unit files" +msgstr "HÃ¥ndtér system services eller enhedsfiler" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6 +msgid "Authentication is required to manage system service or unit files." +msgstr "" +"Autentificering er nødvendig for at hÃ¥ndtere system service eller enhedsfiler." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7 +msgid "Set or unset system and service manager environment variables" +msgstr "" +"Sæt eller fjern system- og service-forvalter miljøvariabler" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8 +msgid "" +"Authentication is required to set or unset system and service manager " +"environment variables." +msgstr "Autentificering er nødvendig for at sætte eller fjerne system- " +"og service-forvalter miljøvariabler." + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9 +msgid "Reload the systemd state" +msgstr "Genindlæs systemd tilstand" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10 +msgid "Authentication is required to reload the systemd state." +msgstr "Autentificering er nødvendig for at genindlæse systemd tilstanden." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1 +msgid "Set host name" +msgstr "Sæt værtsnavn" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2 +msgid "Authentication is required to set the local host name." +msgstr "Autentificering er nødvendig for at sætte værtsnavn." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3 +msgid "Set static host name" +msgstr "Sæt statisk værstnavn" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4 +msgid "" +"Authentication is required to set the statically configured local host name, " +"as well as the pretty host name." +msgstr "" +"Autentificering er nødvendig for at sætte det statisk konfigurerede lokale " +"værtsnavn, lige sÃ¥ vel som det pæne værtsnavn." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5 +msgid "Set machine information" +msgstr "Sæt maskininformation." + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6 +msgid "Authentication is required to set local machine information." +msgstr "Autentificering er nødvendig for at sætte lokal maskininformation." + +#: ../src/import/org.freedesktop.import1.policy.in.h:1 +msgid "Import a VM or container image" +msgstr "Importér en VM eller container billede" + +#: ../src/import/org.freedesktop.import1.policy.in.h:2 +msgid "Authentication is required to import a VM or container image" +msgstr "" +"Autentificering er nødvendig for at importére en VM eller " +"container billeder." + +#: ../src/import/org.freedesktop.import1.policy.in.h:3 +msgid "Export a VM or container image" +msgstr "Exportér en VM eller container billede" + +#: ../src/import/org.freedesktop.import1.policy.in.h:4 +msgid "Authentication is required to export a VM or container image" +msgstr "Autentificering er nødvendig for at exportére en VM eller container billede" + +#: ../src/import/org.freedesktop.import1.policy.in.h:5 +msgid "Download a VM or container image" +msgstr "Hent en VM eller container billede" + +#: ../src/import/org.freedesktop.import1.policy.in.h:6 +msgid "Authentication is required to download a VM or container image" +msgstr "Autentificering er nødvendig for at hente en VM eller container billede" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:1 +msgid "Set system locale" +msgstr "Sæt sprogindstillinger for systemet" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:2 +msgid "Authentication is required to set the system locale." +msgstr "" +"Autentificering er nødvendig for at sætte sprogindstillinger " +"for systemet." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:3 +msgid "Set system keyboard settings" +msgstr "Sæt tastaturindstillinger for systemet." + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:4 +msgid "Authentication is required to set the system keyboard settings." +msgstr "" +"Autentificering er nødvendig for at sætte tastaturindstillinger " +"for systemet." + +#: ../src/login/org.freedesktop.login1.policy.in.h:1 +msgid "Allow applications to inhibit system shutdown" +msgstr "Tillad applikationer at hæmme system nedlukning" + +#: ../src/login/org.freedesktop.login1.policy.in.h:2 +msgid "" +"Authentication is required for an application to inhibit system shutdown." +msgstr "" +"Autentificering er nødvendig for at en applikation kan hæmme " +"system nedlukning." + +#: ../src/login/org.freedesktop.login1.policy.in.h:3 +msgid "Allow applications to delay system shutdown" +msgstr "Tillad applikationer at forsinke system nedlukning" + +#: ../src/login/org.freedesktop.login1.policy.in.h:4 +msgid "Authentication is required for an application to delay system shutdown." +msgstr "" +"Autentificering er nødvendig for at en applikation kan forsinke " +"system nedlukning." + +#: ../src/login/org.freedesktop.login1.policy.in.h:5 +msgid "Allow applications to inhibit system sleep" +msgstr "Tillad applikationer at hæmme system dvale" + +#: ../src/login/org.freedesktop.login1.policy.in.h:6 +msgid "Authentication is required for an application to inhibit system sleep" +msgstr "Autentificering er nødvendig for at en applikation kan hæmme system dvale" + +#: ../src/login/org.freedesktop.login1.policy.in.h:7 +msgid "Allow applications to delay system sleep" +msgstr "Tillad applikationer at forsinke system dvale" + +#: ../src/login/org.freedesktop.login1.policy.in.h:8 +msgid "Authentication is required for an application to delay system sleep." +msgstr "" +"Autentificering er nødvendig for at en applikation kan forsinke system " +"dvale." + +#: ../src/login/org.freedesktop.login1.policy.in.h:9 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "Tillad applikationer at hæmme automatisk system standby" + +#: ../src/login/org.freedesktop.login1.policy.in.h:10 +msgid "" +"Authentication is required for an application to inhibit automatic system " +"suspend." +msgstr "" +"Autentificering er nødvendig for at en applikation kan hæmme automatisk " +"system standby." + +#: ../src/login/org.freedesktop.login1.policy.in.h:11 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "Tillad applikationer at hæmme systemhÃ¥ndtering af tænd/sluk-knappen" + +#: ../src/login/org.freedesktop.login1.policy.in.h:12 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the power key." +msgstr "" +"Autentificering er nødvendig for at en applikation kan hæmme systemhÃ¥ndtering " +"af tænd/sluk-knappen." + +#: ../src/login/org.freedesktop.login1.policy.in.h:13 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "Tillad applikationer at hæmme systemhÃ¥ndtering af standby-knappen" + +#: ../src/login/org.freedesktop.login1.policy.in.h:14 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the suspend key." +msgstr "" +"Autentificering er nødvendig for at en applikation kan hæmme systemhÃ¥ndtering " +"af standby-knappen." + +#: ../src/login/org.freedesktop.login1.policy.in.h:15 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "Tillad applikationer at hæmme systemhÃ¥ndtering af dvale-knappen" + +#: ../src/login/org.freedesktop.login1.policy.in.h:16 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the hibernate key." +msgstr "" +"Autentificering er nødvendig for at en applikation kan hæmme " +"systemhÃ¥ndtering af dvale-knappen." + +#: ../src/login/org.freedesktop.login1.policy.in.h:17 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" +"Tillad applikationer at hæmme systemhÃ¥ndtering af skærmlukning" + +#: ../src/login/org.freedesktop.login1.policy.in.h:18 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the lid switch." +msgstr "" +"Autentificering er nødvendig for at en applikation kan hæmme systemhÃ¥ndtering " +"af skærmlukning." + +#: ../src/login/org.freedesktop.login1.policy.in.h:19 +msgid "Allow non-logged-in users to run programs" +msgstr "Tillad brugere der ikke er logget ind, at køre programmer" + +#: ../src/login/org.freedesktop.login1.policy.in.h:20 +msgid "Authentication is required to run programs as a non-logged-in user." +msgstr "" +"Autentificering er nødvendig for at brugere, som ikke er logget ind, kan " +"køre programmer." + +# www.freedesktop.org/wiki/Software/systemd/multiseat/ +#: ../src/login/org.freedesktop.login1.policy.in.h:21 +msgid "Allow attaching devices to seats" +msgstr "Tillad at montere af enheder til arbejdsstationer" + +# www.freedesktop.org/wiki/Software/systemd/multiseat/ +#: ../src/login/org.freedesktop.login1.policy.in.h:22 +msgid "Authentication is required for attaching a device to a seat." +msgstr "" +"Autentificering er nødvendig for at montere en enhed til en " +"arbejdsstation." + +# www.freedesktop.org/wiki/Software/systemd/multiseat/ +#: ../src/login/org.freedesktop.login1.policy.in.h:23 +msgid "Flush device to seat attachments" +msgstr "Nulstil enhed monteret til en arbejdsstation" + +# www.freedesktop.org/wiki/Software/systemd/multiseat/ +#: ../src/login/org.freedesktop.login1.policy.in.h:24 +msgid "" +"Authentication is required for resetting how devices are attached to seats." +msgstr "" +"Autentificering er nødvendig for at nulstille mÃ¥den enheder er monteret " +"arbejdsstationer." + +#: ../src/login/org.freedesktop.login1.policy.in.h:25 +msgid "Power off the system" +msgstr "Sluk for systemet" + +#: ../src/login/org.freedesktop.login1.policy.in.h:26 +msgid "Authentication is required for powering off the system." +msgstr "Autentificering er nødvendig for at slukke systemet" + +#: ../src/login/org.freedesktop.login1.policy.in.h:27 +msgid "Power off the system while other users are logged in" +msgstr "Sluk systemet mens andre brugere er logget pÃ¥" + +#: ../src/login/org.freedesktop.login1.policy.in.h:28 +msgid "" +"Authentication is required for powering off the system while other users are " +"logged in." +msgstr "" +"Autentificering er nødvendig for at slukke systemet mens andre brugere " +"er logget pÃ¥." + +#: ../src/login/org.freedesktop.login1.policy.in.h:29 +msgid "Power off the system while an application asked to inhibit it" +msgstr "" +"Sluk for systemet mens en applikation har forespurgt at hæmme det" + +#: ../src/login/org.freedesktop.login1.policy.in.h:30 +msgid "" +"Authentication is required for powering off the system while an application " +"asked to inhibit it." +msgstr "" +"Autentificering er nødvendig for at slukke systemet mens en applikation har " +"forespurgt at hæmme det." + +#: ../src/login/org.freedesktop.login1.policy.in.h:31 +msgid "Reboot the system" +msgstr "Genstart systemet" + +#: ../src/login/org.freedesktop.login1.policy.in.h:32 +msgid "Authentication is required for rebooting the system." +msgstr "Autentificering er nødvendig for at genstarte systemet." + +#: ../src/login/org.freedesktop.login1.policy.in.h:33 +msgid "Reboot the system while other users are logged in" +msgstr "Genstart systemet mens andre brugere er logget ind" + +#: ../src/login/org.freedesktop.login1.policy.in.h:34 +msgid "" +"Authentication is required for rebooting the system while other users are " +"logged in." +msgstr "" +"Autentificering er nødvendig for at genstarte systemet mens andre brugere " +"er logget ind." + +#: ../src/login/org.freedesktop.login1.policy.in.h:35 +msgid "Reboot the system while an application asked to inhibit it" +msgstr "" +"Genstart systemet mens en applikation har forespurgt at hæmme det" + +#: ../src/login/org.freedesktop.login1.policy.in.h:36 +msgid "" +"Authentication is required for rebooting the system while an application " +"asked to inhibit it." +msgstr "" +"Autentificering er nødvendig for at genstarte systemet mens en applikation " +"har forespurgt at hæmme det." + +#: ../src/login/org.freedesktop.login1.policy.in.h:37 +msgid "Suspend the system" +msgstr "Sæt systemet pÃ¥ standby" + +#: ../src/login/org.freedesktop.login1.policy.in.h:38 +msgid "Authentication is required for suspending the system." +msgstr "Autentificering er nødvendig for at sætte systemet pÃ¥ standby" + +#: ../src/login/org.freedesktop.login1.policy.in.h:39 +msgid "Suspend the system while other users are logged in" +msgstr "Sæt systemet pÃ¥ standby mens andre brugere er logget pÃ¥" + +#: ../src/login/org.freedesktop.login1.policy.in.h:40 +msgid "" +"Authentication is required for suspending the system while other users are " +"logged in." +msgstr "" +"Autentificering er nødvendig for at sætte systemet pÃ¥ standby, mens andre " +"brugere er logget pÃ¥." + +#: ../src/login/org.freedesktop.login1.policy.in.h:41 +msgid "Suspend the system while an application asked to inhibit it" +msgstr "" +"Sæt systemet pÃ¥ standby mens en applikation har forespurgt at hæmme" +"det" + +#: ../src/login/org.freedesktop.login1.policy.in.h:42 +msgid "" +"Authentication is required for suspending the system while an application " +"asked to inhibit it." +msgstr "" +"Autentificering er nødvendig for at sætte systemet pÃ¥ standby, mens en " +"applikation har forespurgt at hæmme det." + +#: ../src/login/org.freedesktop.login1.policy.in.h:43 +msgid "Hibernate the system" +msgstr "Sæt systemet i dvale" + +#: ../src/login/org.freedesktop.login1.policy.in.h:44 +msgid "Authentication is required for hibernating the system." +msgstr "" +"Autentificering er nødvendig for at sætte systemet i dvale-tilstand." + +#: ../src/login/org.freedesktop.login1.policy.in.h:45 +msgid "Hibernate the system while other users are logged in" +msgstr "" +"Sæt systemet i dvale-tilstand mens andre brugere er logget pÃ¥" + +#: ../src/login/org.freedesktop.login1.policy.in.h:46 +msgid "" +"Authentication is required for hibernating the system while other users are " +"logged in." +msgstr "" +"Autentificering er nødvendig for at sætte systemet i dvale-tilstand, mens " +"andre brugere er logget pÃ¥." + +#: ../src/login/org.freedesktop.login1.policy.in.h:47 +msgid "Hibernate the system while an application asked to inhibit it" +msgstr "Sæt systemet i dvale-tilstand mens en applikation har forespurgt at " +"hæmme det" + +#: ../src/login/org.freedesktop.login1.policy.in.h:48 +msgid "" +"Authentication is required for hibernating the system while an application " +"asked to inhibit it." +msgstr "" +"Autentificering er nødvendig for at sætte systemet i dvale tilstand, mens " +"en applikation har forespurgt at hæmme det." + +#: ../src/login/org.freedesktop.login1.policy.in.h:49 +msgid "Manage active sessions, users and seats" +msgstr "HÃ¥ndtér aktive sessioner, brugere og arbejdsstationer" + +# www.freedesktop.org/wiki/Software/systemd/multiseat/ +#: ../src/login/org.freedesktop.login1.policy.in.h:50 +msgid "" +"Authentication is required for managing active sessions, users and seats." +msgstr "" +"Autentificering er nødvendig for at hÃ¥ndtere aktive sessioner, brugere " +"og arbejdsstationer." + +#: ../src/login/org.freedesktop.login1.policy.in.h:51 +msgid "Lock or unlock active sessions" +msgstr "LÃ¥s eller oplÃ¥s aktive sessioner" + +#: ../src/login/org.freedesktop.login1.policy.in.h:52 +msgid "Authentication is required to lock or unlock active sessions." +msgstr "" +"Autentificering er nødvendig for at lÃ¥se eller oplÃ¥se aktive sessioner." + +#: ../src/login/org.freedesktop.login1.policy.in.h:53 +msgid "Allow indication to the firmware to boot to setup interface" +msgstr "Tillad meddelelse til firmwaren om at starte op i opsætningsgrænseflade" + +#: ../src/login/org.freedesktop.login1.policy.in.h:54 +msgid "" +"Authentication is required to indicate to the firmware to boot to setup " +"interface." +msgstr "Autentificering er nødvendig for at meddele firmwaren om at starte " +"op i opsætningsgrænseflade." + +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "Sæt broadcast-besked" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +msgid "Authentication is required to set a wall message" +msgstr "Autentificering er nødvendig for at sætte en broadcast-besked" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:1 +msgid "Log into a local container" +msgstr "Log pÃ¥ en lokal container" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:2 +msgid "Authentication is required to log into a local container." +msgstr "Autentificering er nødvendig for at logge pÃ¥ en lokal container." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +msgid "Log into the local host" +msgstr "Log pÃ¥ den lokale vært" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +msgid "Authentication is required to log into the local host." +msgstr "Auitentificering er nødvendig for at logge pÃ¥ den lokale vært." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +msgid "Acquire a shell in a local container" +msgstr "Anskaf en shell i en lokal container" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "" +"Autentificering er nødvendig for at anskaffe en shell i en lokal " +"container." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "Anskaf en shell pÃ¥ den lokale vært" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "" +"Autentificering er nødvendig for at anskaffe en shell pÃ¥ den lokale vært." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Anskaf en pseudo-TTY i en lokal container" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" +"Autentificering er nødvendig for at anskaffe en pseudo-TTY i en lokal " +"container." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Anskaf en pseudo-TTY pÃ¥ den lokale vært" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "" +"Autentificering er nødvendig for at anskaffe en pseudo-TTY pÃ¥ den " +"lokale vært." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 +msgid "Manage local virtual machines and containers" +msgstr "HÃ¥ndtér lokale virtuelle maskiner og containere" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "" +"Autentificering er nødvendig for at hÃ¥ndtere lokale virtuelle maskiner og " +"containere." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 +msgid "Manage local virtual machine and container images" +msgstr "HÃ¥ndtér lokal virtuel maskine- og container billeder" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 +msgid "" +"Authentication is required to manage local virtual machine and container " +"images." +msgstr "" +"Autentificering er nødvendig for at hÃ¥ndtere lokal virtuel maskine- og " +"container billeder." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 +msgid "Set system time" +msgstr "Sæt tiden for systemet" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2 +msgid "Authentication is required to set the system time." +msgstr "Autentificering er nødvendig for at sætte tiden for systemet." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3 +msgid "Set system timezone" +msgstr "Sæt tidszone for systemet" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4 +msgid "Authentication is required to set the system timezone." +msgstr "Autentificering er nødvendig for at sætte tidszonen for systemet." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5 +msgid "Set RTC to local timezone or UTC" +msgstr "Sæt RTC til lokal tidszone eller UTC" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" +"Autentificering er nødvendig for at kontrollere hvorvidt RTC'en gemmer " +"den lokale tid eller UTC tid." + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7 +msgid "Turn network time synchronization on or off" +msgstr "SlÃ¥ synkronisering af netværkstid til eller fra" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" +"Autentificering er nødvendig for at kontrollere hvorvidt synkronisering af " +"netværkstid skal aktiveres" + +#: ../src/core/dbus-unit.c:428 +msgid "Authentication is required to start '$(unit)'." +msgstr "Autentificering er nødvendig for at starte '$(unit)'." + +#: ../src/core/dbus-unit.c:429 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Autentificering er nødvendig for at stoppe '$(unit)'." + +#: ../src/core/dbus-unit.c:430 +msgid "Authentication is required to reload '$(unit)'." +msgstr "Autentificering er nødvendig for at genindlæse '$(unit)'." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Autentificering at nødvendig for at genstarte '$(unit)'." + +#: ../src/core/dbus-unit.c:535 +msgid "Authentication is required to kill '$(unit)'." +msgstr "Autentificering er nødvendig for at eliminere '$(unit)'." + +#: ../src/core/dbus-unit.c:565 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" +"Autentificering er nødvendig for at nulstille \"fejl\" tilstanden pÃ¥ '$(unit)'." + +#: ../src/core/dbus-unit.c:597 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "" +"Autentificering er nødvendig for at sætte egenskaber pÃ¥ '$(unit)'." + +#~ msgid "Press Ctrl+C to cancel all filesystem checks in progress" +#~ msgstr "" +#~ "Tryk Ctrl-C for at annulere alle igangværende kontrolleringer af " +#~ "filsystemet" + +#~ msgid "Checking in progress on %d disk (%3.1f%% complete)" +#~ msgid_plural "Checking in progress on %d disks (%3.1f%% complete)" +#~ msgstr[0] "Igangværende kontrollering pÃ¥ %d disk (%3.1f%% færdig)" +#~ msgstr[1] "Igangværende kontrollering pÃ¥ %d diske (%3.1f%% færdig)" @@ -2,19 +2,20 @@ # Copyright (C) 2015 systemd author and translators. # This file is distributed under the same license as the systemd package. # Seong-ho Cho <shcho@gnome.org>, 2015. +# Dongsu Park <dongsu@endocode.com>, 2015. # msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n" "POT-Creation-Date: 2015-09-25 22:52+0900\n" -"PO-Revision-Date: 2015-09-25 23:50+0900\n" -"Last-Translator: Seong-ho Cho <shcho@gnome.org>\n" +"PO-Revision-Date: 2015-11-03 13:19+0100\n" +"Last-Translator: Dongsu Park <dongsu@endocode.com>\n" "Language-Team: GNOME Korea <gnome-kr@googlegroups.com>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.5.5\n" +"X-Generator: Gtranslator 2.91.7\n" "Plural-Forms: nplurals=1; plural=0;\n" "Language: ko\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -242,7 +243,7 @@ msgstr "ì‹œíŠ¸ì— ìž¥ì¹˜ ë¶€ì°©ì„ í—ˆìš©í•˜ë ¤ë©´ ì¸ì¦ì´ 필요합니다." #: ../src/login/org.freedesktop.login1.policy.in.h:23 msgid "Flush device to seat attachments" -msgstr "시트로부터 장치 탈거 허용" +msgstr "시트로부터 장치 í•´ì œ 허용" #: ../src/login/org.freedesktop.login1.policy.in.h:24 msgid "" @@ -393,13 +394,13 @@ msgstr "활성화 ì„¸ì…˜ì„ ìž ê¸ˆ ë˜ëŠ” ìž ê¸ˆ í•´ì œí•˜ë ¤ë©´ ì¸ì¦ì´ í•„ìš #: ../src/login/org.freedesktop.login1.policy.in.h:53 msgid "Allow indication to the firmware to boot to setup interface" -msgstr "ì¸í„°íŽ˜ì´ìŠ¤ë¥¼ ì„¤ì •í•˜ë„ë¡ íŽŒì›¨ì–´ 부팅 지시 허용" +msgstr "ì„¤ì • 화면으로 부팅하ë„ë¡ íŽŒì›¨ì–´ì—게 지시 허용" #: ../src/login/org.freedesktop.login1.policy.in.h:54 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." -msgstr "ì¸í„°íŽ˜ì´ìŠ¤ë¥¼ ì„¤ì •í•˜ë„ë¡ íŽŒì›¨ì–´ ë¶€íŒ…ì„ ì§€ì‹œí•˜ë ¤ë©´ ì¸ì¦ì´ 필요합니다." +msgstr "ì„¤ì • 화면으로 부팅하ë„ë¡ íŽŒì›¨ì–´ì—게 ì§€ì‹œí•˜ë ¤ë©´ ì¸ì¦ì´ 필요합니다." #: ../src/login/org.freedesktop.login1.policy.in.h:55 msgid "Set a wall message" @@ -452,7 +453,7 @@ msgstr "로컬 컨테ì´ë„ˆì—ì„œ ì˜ì‚¬ TTY를 íšë“í•˜ë ¤ë©´ ì¸ì¦ì´ í•„ìš” #: ../src/machine/org.freedesktop.machine1.policy.in.h:11 msgid "Acquire a pseudo TTY on the local host" -msgstr "로컬 호스트ì—ì„œ ì˜ì‚¬ TTY íšë“" +msgstr "로컬 호스트ì—ì„œ ìœ ì‚¬ TTY íšë“" #: ../src/machine/org.freedesktop.machine1.policy.in.h:12 msgid "Authentication is required to acquire a pseudo TTY on the local host." diff --git a/po/zh_CN.po b/po/zh_CN.po new file mode 100644 index 0000000000..67639620fb --- /dev/null +++ b/po/zh_CN.po @@ -0,0 +1,527 @@ +# Simplified Chinese translation for systemd. +# Copyright (C) 2015 systemd's COPYRIGHT HOLDER +# This file is distributed under the same license as the systemd package. +# +# Frank Hill <hxf.prc@gmail.com>, 2014. +# Boyuan Yang <073plan@gmail.com>, 2015. +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n" +"POT-Creation-Date: 2015-10-27 02:24+0000\n" +"PO-Revision-Date: 2015-10-28 15:00+0800\n" +"Last-Translator: Boyuan Yang <073plan@gmail.com>\n" +"Language-Team: Chinese <i18n-zh@googlegroups.com>\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Lokalize 2.0\n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 +msgid "Send passphrase back to system" +msgstr "将密ç å‘回系统" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:2 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "将输入的密ç å‘回系统需è¦éªŒè¯ã€‚" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 +msgid "Manage system services or other units" +msgstr "管ç†ç³»ç»ŸæœåŠ¡æˆ–其它å•å…ƒ" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 +msgid "Authentication is required to manage system services or other units." +msgstr "管ç†ç³»ç»ŸæœåŠ¡æˆ–其它å•å…ƒéœ€è¦éªŒè¯ã€‚" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5 +msgid "Manage system service or unit files" +msgstr "管ç†ç³»ç»ŸæœåŠ¡æˆ–å•å…ƒæ–‡ä»¶" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6 +msgid "Authentication is required to manage system service or unit files." +msgstr "管ç†ç³»ç»ŸæœåŠ¡æˆ–å•å…ƒæ–‡ä»¶éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7 +msgid "Set or unset system and service manager environment variables" +msgstr "设置或清除系统åŠæœåŠ¡ç®¡ç†å™¨çš„环境å˜é‡" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8 +msgid "" +"Authentication is required to set or unset system and service manager " +"environment variables." +msgstr "设置或清除系统åŠæœåŠ¡ç®¡ç†å™¨çš„环境å˜é‡éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9 +msgid "Reload the systemd state" +msgstr "é‡æ–°è½½å…¥ systemd 状æ€" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10 +msgid "Authentication is required to reload the systemd state." +msgstr "é‡æ–°è½½å…¥ systemd 状æ€éœ€è¦éªŒè¯ã€‚" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1 +msgid "Set host name" +msgstr "设置主机å" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:2 +msgid "Authentication is required to set the local host name." +msgstr "设置本地主机å需è¦éªŒè¯ã€‚" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:3 +msgid "Set static host name" +msgstr "设置é™æ€ä¸»æœºå" + +# For pretty hostname, the zh_CN/zh_TW translation should be discussed again. +# +# There were some discussions, like https://lists.fedoraprojects.org/pipermail/trans-zh_cn/2012-December/001347.html +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:4 +#, fuzzy +msgid "" +"Authentication is required to set the statically configured local host name, " +"as well as the pretty host name." +msgstr "设置é™æ€æœ¬åœ°ä¸»æœºå或漂亮的主机å需è¦éªŒè¯ã€‚" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:5 +msgid "Set machine information" +msgstr "设置机器信æ¯" + +#: ../src/hostname/org.freedesktop.hostname1.policy.in.h:6 +msgid "Authentication is required to set local machine information." +msgstr "设置本地机器信æ¯éœ€è¦éªŒè¯ã€‚" + +#: ../src/import/org.freedesktop.import1.policy.in.h:1 +msgid "Import a VM or container image" +msgstr "导入虚拟机或容器镜åƒ" + +#: ../src/import/org.freedesktop.import1.policy.in.h:2 +msgid "Authentication is required to import a VM or container image" +msgstr "导入虚拟机或容器镜åƒéœ€è¦éªŒè¯" + +#: ../src/import/org.freedesktop.import1.policy.in.h:3 +msgid "Export a VM or container image" +msgstr "导出虚拟机或容器镜åƒ" + +#: ../src/import/org.freedesktop.import1.policy.in.h:4 +msgid "Authentication is required to export a VM or container image" +msgstr "导出虚拟机或容器镜åƒéœ€è¦éªŒè¯" + +#: ../src/import/org.freedesktop.import1.policy.in.h:5 +msgid "Download a VM or container image" +msgstr "下载虚拟机或容器镜åƒ" + +#: ../src/import/org.freedesktop.import1.policy.in.h:6 +msgid "Authentication is required to download a VM or container image" +msgstr "下载虚拟机或容器镜åƒéœ€è¦éªŒè¯ã€‚" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:1 +msgid "Set system locale" +msgstr "设置系统区域和è¯è¨€" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:2 +msgid "Authentication is required to set the system locale." +msgstr "设置系统区域和è¯è¨€éœ€è¦éªŒè¯ã€‚" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:3 +msgid "Set system keyboard settings" +msgstr "设置系统键盘" + +#: ../src/locale/org.freedesktop.locale1.policy.in.h:4 +msgid "Authentication is required to set the system keyboard settings." +msgstr "设置系统键盘需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:1 +msgid "Allow applications to inhibit system shutdown" +msgstr "å…许应用程åºé˜»æ¢ç³»ç»Ÿå…³æœº" + +#: ../src/login/org.freedesktop.login1.policy.in.h:2 +msgid "" +"Authentication is required for an application to inhibit system shutdown." +msgstr "è¦å…许应用程åºé˜»æ¢ç³»ç»Ÿå…³æœºéœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:3 +msgid "Allow applications to delay system shutdown" +msgstr "å…许应用程åºå»¶è¿Ÿç³»ç»Ÿå…³æœº" + +#: ../src/login/org.freedesktop.login1.policy.in.h:4 +msgid "Authentication is required for an application to delay system shutdown." +msgstr "è¦å…许应用程åºå»¶è¿Ÿç³»ç»Ÿå…³æœºéœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:5 +msgid "Allow applications to inhibit system sleep" +msgstr "å…许应用程åºé˜»æ¢ç³»ç»Ÿç¡çœ " + +#: ../src/login/org.freedesktop.login1.policy.in.h:6 +msgid "Authentication is required for an application to inhibit system sleep." +msgstr "è¦å…许应用程åºé˜»æ¢ç³»ç»Ÿç¡çœ 需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:7 +msgid "Allow applications to delay system sleep" +msgstr "å…许应用程åºå»¶è¿Ÿç³»ç»Ÿç¡çœ " + +#: ../src/login/org.freedesktop.login1.policy.in.h:8 +msgid "Authentication is required for an application to delay system sleep." +msgstr "è¦å…许应用程åºå»¶è¿Ÿç³»ç»Ÿç¡çœ 需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:9 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "å…许应用程åºé˜»æ¢ç³»ç»Ÿè‡ªåŠ¨æŒ‚èµ·" + +#: ../src/login/org.freedesktop.login1.policy.in.h:10 +msgid "" +"Authentication is required for an application to inhibit automatic system " +"suspend." +msgstr "è¦å…许应用程åºé˜»æ¢ç³»ç»Ÿè‡ªåŠ¨æŒ‚起需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:11 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应电æºé”®" + +#: ../src/login/org.freedesktop.login1.policy.in.h:12 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the power key." +msgstr "è¦å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应电æºé”®éœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:13 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应挂起键" + +#: ../src/login/org.freedesktop.login1.policy.in.h:14 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the suspend key." +msgstr "è¦å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应挂起键需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:15 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应挂起键" + +#: ../src/login/org.freedesktop.login1.policy.in.h:16 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the hibernate key." +msgstr "è¦å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应挂起键需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:17 +#, fuzzy +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应笔记本上盖开关事件" + +#: ../src/login/org.freedesktop.login1.policy.in.h:18 +#, fuzzy +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the lid switch." +msgstr "è¦å…许应用程åºé˜»æ¢ç³»ç»Ÿå“应笔记本上盖开关事件需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:19 +msgid "Allow non-logged-in users to run programs" +msgstr "å…许未登录用户è¿è¡Œç¨‹åº" + +#: ../src/login/org.freedesktop.login1.policy.in.h:20 +msgid "Authentication is required to run programs as a non-logged-in user." +msgstr "è¦å…许未登录用户è¿è¡Œç¨‹åºéœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:21 +msgid "Allow attaching devices to seats" +msgstr "å…è®¸å°†è®¾å¤‡é™„åŠ è‡³ä¼šè¯åº§ä½" + +# Pay attention to the concept of "seat". +# +# To fully understand the meaning, please refer to session management in old ConsoleKit and new systemd-logind. +#: ../src/login/org.freedesktop.login1.policy.in.h:22 +msgid "Authentication is required for attaching a device to a seat." +msgstr "è¦å…è®¸å°†è®¾å¤‡é™„åŠ è‡³æŸä¸ªä¼šè¯åº§ä½éœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:23 +msgid "Flush device to seat attachments" +msgstr "刷新设备至会è¯åº§ä½é—´çš„连接" + +#: ../src/login/org.freedesktop.login1.policy.in.h:24 +msgid "" +"Authentication is required for resetting how devices are attached to seats." +msgstr "é‡æ–°è®¾å®šè®¾å¤‡çš„会è¯åº§ä½æŽ¥å…¥æ–¹å¼æ—¶éœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:25 +msgid "Power off the system" +msgstr "å…³é—系统" + +#: ../src/login/org.freedesktop.login1.policy.in.h:26 +msgid "Authentication is required for powering off the system." +msgstr "å…³é—系统需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:27 +msgid "Power off the system while other users are logged in" +msgstr "å˜åœ¨å…¶ä»–已登录用户时ä»ç„¶å…³æœº" + +#: ../src/login/org.freedesktop.login1.policy.in.h:28 +msgid "" +"Authentication is required for powering off the system while other users are " +"logged in." +msgstr "å˜åœ¨å…¶ä»–已登录用户时关é—系统需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:29 +msgid "Power off the system while an application asked to inhibit it" +msgstr "有其它应用程åºé˜»æ¢æ—¶ä»ç„¶å…³æœº" + +#: ../src/login/org.freedesktop.login1.policy.in.h:30 +msgid "" +"Authentication is required for powering off the system while an application " +"asked to inhibit it." +msgstr "è¦åœ¨å…¶å®ƒåº”用程åºé˜»æ¢å…³æœºæ—¶å…³é—系统需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:31 +msgid "Reboot the system" +msgstr "é‡å¯ç³»ç»Ÿ" + +#: ../src/login/org.freedesktop.login1.policy.in.h:32 +msgid "Authentication is required for rebooting the system." +msgstr "é‡å¯ç³»ç»Ÿéœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:33 +msgid "Reboot the system while other users are logged in" +msgstr "å˜åœ¨å…¶ä»–已登录用户时ä»ç„¶é‡å¯" + +#: ../src/login/org.freedesktop.login1.policy.in.h:34 +msgid "" +"Authentication is required for rebooting the system while other users are " +"logged in." +msgstr "å˜åœ¨å…¶ä»–已登录用户时é‡å¯ç³»ç»Ÿéœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:35 +msgid "Reboot the system while an application asked to inhibit it" +msgstr "有其它应用程åºé˜»æ¢æ—¶ä»ç„¶é‡å¯" + +#: ../src/login/org.freedesktop.login1.policy.in.h:36 +msgid "" +"Authentication is required for rebooting the system while an application " +"asked to inhibit it." +msgstr "è¦åœ¨å…¶å®ƒåº”用程åºé˜»æ¢é‡å¯æ—¶é‡å¯ç³»ç»Ÿéœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:37 +msgid "Suspend the system" +msgstr "挂起系统" + +#: ../src/login/org.freedesktop.login1.policy.in.h:38 +msgid "Authentication is required for suspending the system." +msgstr "挂起系统需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:39 +msgid "Suspend the system while other users are logged in" +msgstr "å˜åœ¨å…¶ä»–已登录用户时ä»ç„¶æŒ‚起系统" + +#: ../src/login/org.freedesktop.login1.policy.in.h:40 +msgid "" +"Authentication is required for suspending the system while other users are " +"logged in." +msgstr "å˜åœ¨å…¶ä»–已登录用户时挂起系统需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:41 +msgid "Suspend the system while an application asked to inhibit it" +msgstr "有其它应用程åºé˜»æ¢æ—¶ä»ç„¶æŒ‚起系统" + +#: ../src/login/org.freedesktop.login1.policy.in.h:42 +msgid "" +"Authentication is required for suspending the system while an application " +"asked to inhibit it." +msgstr "è¦åœ¨å…¶å®ƒåº”用程åºé˜»æ¢æŒ‚起时挂起系统需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:43 +msgid "Hibernate the system" +msgstr "ä¼‘çœ " + +#: ../src/login/org.freedesktop.login1.policy.in.h:44 +msgid "Authentication is required for hibernating the system." +msgstr "ä¼‘çœ éœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:45 +msgid "Hibernate the system while other users are logged in" +msgstr "å˜åœ¨å…¶ä»–已登录用户时ä»ç„¶ä¼‘çœ " + +#: ../src/login/org.freedesktop.login1.policy.in.h:46 +msgid "" +"Authentication is required for hibernating the system while other users are " +"logged in." +msgstr "å˜åœ¨å…¶ä»–å·²ç™»å½•ç”¨æˆ·æ—¶è¿›è¡Œä¼‘çœ éœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:47 +msgid "Hibernate the system while an application asked to inhibit it" +msgstr "有其它应用程åºé˜»æ¢æ—¶ä»ç„¶ä¼‘çœ " + +#: ../src/login/org.freedesktop.login1.policy.in.h:48 +msgid "" +"Authentication is required for hibernating the system while an application " +"asked to inhibit it." +msgstr "è¦åœ¨å…¶å®ƒåº”用程åºé˜»æ¢ä¼‘çœ æ—¶è¿›è¡Œä¼‘çœ éœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:49 +msgid "Manage active sessions, users and seats" +msgstr "管ç†æ´»åŠ¨ä¼šè¯ã€ç”¨æˆ·ä¸Žä¼šè¯åº§ä½" + +#: ../src/login/org.freedesktop.login1.policy.in.h:50 +msgid "" +"Authentication is required for managing active sessions, users and seats." +msgstr "è¦ç®¡ç†æ´»åŠ¨ä¼šè¯ã€ç”¨æˆ·ä¸Žä¼šè¯åº§ä½éœ€è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:51 +msgid "Lock or unlock active sessions" +msgstr "活动会è¯é”定与解é”" + +#: ../src/login/org.freedesktop.login1.policy.in.h:52 +msgid "Authentication is required to lock or unlock active sessions." +msgstr "è¦å¯¹æ´»åŠ¨ä¼šè¯è¿›è¡Œé”定或解é”需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:53 +msgid "Allow indication to the firmware to boot to setup interface" +msgstr "å…许å‘固件å‘出指示以å¯åŠ¨è‡³å›ºä»¶è®¾ç½®ç•Œé¢" + +#: ../src/login/org.freedesktop.login1.policy.in.h:54 +msgid "" +"Authentication is required to indicate to the firmware to boot to setup " +"interface." +msgstr "è¦å…许å‘固件å‘出å¯åŠ¨æ—¶è¿›å…¥è®¾ç½®ç•Œé¢çš„指令需è¦éªŒè¯ã€‚" + +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +#, fuzzy +msgid "Authentication is required to set a wall message" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:1 +msgid "Log into a local container" +msgstr "登入一个本地容器" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:2 +msgid "Authentication is required to log into a local container." +msgstr "è¦ç™»å…¥ä¸€ä¸ªæœ¬åœ°å®¹å™¨éœ€è¦éªŒè¯ã€‚" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +msgid "Log into the local host" +msgstr "登入本地主机" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +msgid "Authentication is required to log into the local host." +msgstr "è¦ç™»å…¥æœ¬åœ°ä¸»æœºéœ€è¦éªŒè¯ã€‚" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +msgid "Acquire a shell in a local container" +msgstr "在本地容器ä¸èŽ·å–一个 shell" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "è¦åœ¨æœ¬åœ°å®¹å™¨ä¸èŽ·å– shell 需è¦éªŒè¯ã€‚" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "在本地主机ä¸èŽ·å–一个 shell" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "è¦åœ¨æœ¬åœ°ä¸»æœºä¸èŽ·å– shell 需è¦éªŒè¯ã€‚" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "在本地容器ä¸èŽ·å–ä¸€ä¸ªå‡ TTY" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "è¦åœ¨æœ¬åœ°å®¹å™¨ä¸èŽ·å–å‡ TTY 需è¦éªŒè¯ã€‚" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "在本地主机ä¸èŽ·å–ä¸€ä¸ªå‡ TTY" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "è¦åœ¨æœ¬åœ°ä¸»æœºä¸èŽ·å–å‡ TTY 需è¦éªŒè¯ã€‚" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 +msgid "Manage local virtual machines and containers" +msgstr "管ç†æœ¬åœ°è™šæ‹Ÿæœºå’Œå®¹å™¨" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "è¦ç®¡ç†æœ¬åœ°è™šæ‹Ÿæœºå’Œå®¹å™¨éœ€è¦éªŒè¯ã€‚" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 +msgid "Manage local virtual machine and container images" +msgstr "管ç†æœ¬åœ°è™šæ‹Ÿæœºå’Œå®¹å™¨çš„é•œåƒ" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 +msgid "" +"Authentication is required to manage local virtual machine and container " +"images." +msgstr "è¦ç®¡ç†æœ¬åœ°çš„虚拟机和容器镜åƒéœ€è¦éªŒè¯ã€‚" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 +msgid "Set system time" +msgstr "设置系统时间" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:2 +msgid "Authentication is required to set the system time." +msgstr "设置系统时间需è¦éªŒè¯ã€‚" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:3 +msgid "Set system timezone" +msgstr "设置系统时区" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:4 +msgid "Authentication is required to set the system timezone." +msgstr "设置系统时区需è¦éªŒè¯ã€‚" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:5 +msgid "Set RTC to local timezone or UTC" +msgstr "设置硬件时钟使用本地时间或 UTC" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:6 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "设置硬件时钟使用本地时间或 UTC 需è¦éªŒè¯ã€‚" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:7 +msgid "Turn network time synchronization on or off" +msgstr "打开或关é—网络时间åŒæ¥" + +#: ../src/timedate/org.freedesktop.timedate1.policy.in.h:8 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "设置是å¦å¯ç”¨ç½‘络时间åŒæ¥éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/dbus-unit.c:430 +msgid "Authentication is required to start '$(unit)'." +msgstr "å¯åŠ¨â€œ$(unit)â€éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/dbus-unit.c:431 +msgid "Authentication is required to stop '$(unit)'." +msgstr "åœæ¢â€œ$(unit)â€éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/dbus-unit.c:432 +msgid "Authentication is required to reload '$(unit)'." +msgstr "é‡æ–°è½½å…¥â€œ$(unit)â€éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/dbus-unit.c:433 ../src/core/dbus-unit.c:434 +msgid "Authentication is required to restart '$(unit)'." +msgstr "é‡æ–°å¯åŠ¨â€œ$(unit)â€éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/dbus-unit.c:537 +msgid "Authentication is required to kill '$(unit)'." +msgstr "æ€æ»â€œ$(unit)â€éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/dbus-unit.c:567 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "é‡ç½®â€œ$(unit)â€çš„失败(\"failed\")状æ€éœ€è¦éªŒè¯ã€‚" + +#: ../src/core/dbus-unit.c:599 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "设置“$(unit)â€çš„属性需è¦éªŒè¯ã€‚" + diff --git a/shell-completion/bash/hostnamectl b/shell-completion/bash/hostnamectl index 9ad52e03b4..6a252188ea 100644 --- a/shell-completion/bash/hostnamectl +++ b/shell-completion/bash/hostnamectl @@ -38,7 +38,7 @@ _hostnamectl() { local -A VERBS=( [STANDALONE]='status' [ICONS]='set-icon-name' - [NAME]='set-hostname set-deployment' + [NAME]='set-hostname set-deployment set-location' [CHASSIS]='set-chassis' ) diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl index 056cdbce70..4a7e0da1ab 100644 --- a/shell-completion/bash/journalctl +++ b/shell-completion/bash/journalctl @@ -51,7 +51,7 @@ _journalctl() { [ARG]='-b --boot --this-boot -D --directory --file -F --field -o --output -u --unit --user-unit -p --priority --vacuum-size --vacuum-time' - [ARGUNKNOWN]='-c --cursor --interval -n --lines --since --until + [ARGUNKNOWN]='-c --cursor --interval -n --lines -S --since -U --until --after-cursor --verify-key -t --identifier --root -M --machine' ) diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index 29bb41c436..d80d8f02a8 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -106,6 +106,8 @@ _systemctl () { if __contains_word "--user" ${COMP_WORDS[*]}; then mode=--user + elif __contains_word "--global" ${COMP_WORDS[*]}; then + mode=--user else mode=--system fi @@ -159,7 +161,7 @@ _systemctl () { fi local -A VERBS=( - [ALL_UNITS]='is-active is-failed is-enabled status show cat mask preset help list-dependencies edit' + [ALL_UNITS]='is-active is-failed is-enabled status show cat mask preset help list-dependencies edit set-property' [ENABLED_UNITS]='disable' [DISABLED_UNITS]='enable' [REENABLABLE_UNITS]='reenable' @@ -172,14 +174,12 @@ _systemctl () { [TARGET_AND_UNITS]='add-wants add-requires' [MASKED_UNITS]='unmask' [JOBS]='cancel' - [SNAPSHOTS]='delete' [ENVS]='set-environment unset-environment' [STANDALONE]='daemon-reexec daemon-reload default emergency exit halt hibernate hybrid-sleep kexec list-jobs list-sockets list-timers list-units list-unit-files poweroff reboot rescue show-environment suspend get-default is-system-running' - [NAME]='snapshot' [FILE]='link switch-root' [TARGETS]='set-default' ) @@ -257,16 +257,12 @@ _systemctl () { fi compopt -o filenames - elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then + elif __contains_word "$verb" ${VERBS[STANDALONE]}; then comps='' elif __contains_word "$verb" ${VERBS[JOBS]}; then comps=$( __systemctl $mode list-jobs | { while read -r a b; do echo " $a"; done; } ) - elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then - comps=$( __systemctl $mode list-units --type snapshot --full --all \ - | { while read -r a b; do echo " $a"; done; } ) - elif __contains_word "$verb" ${VERBS[ENVS]}; then comps=$( __systemctl $mode show-environment \ | while read -r line; do echo " ${line%%=*}=";done ) diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index b1387a28b6..8152b021e7 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -83,7 +83,10 @@ _systemd_run() { LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= - TTYPath= SyslogIdentifier= SyslogLevelPrefix=' + TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= + SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= + ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= + ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment=' COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl index 863348e050..b50f0cafc9 100644 --- a/shell-completion/zsh/_journalctl +++ b/shell-completion/zsh/_journalctl @@ -69,6 +69,7 @@ _arguments -s \ {-u+,--unit=}'[Show data only from the specified unit]:units:_journal_fields _SYSTEMD_UNIT' \ '--user-unit=[Show data only from the specified user session unit]:units:_journal_fields USER_UNIT' \ {-p+,--priority=}'[Show only messages within the specified priority range]:priority:_journal_fields PRIORITY' \ + {-t+,--identifier=}'[Show only messages with the specified syslog identifier]:identifier:_journal_fields SYSLOG_IDENTIFIER' \ {-c+,--cursor=}'[Start showing entries from the specified cursor]:cursors:_journal_fields __CURSORS' \ '--after-cursor=[Start showing entries from after the specified cursor]:cursors:_journal_fields __CURSORS' \ '--since=[Start showing entries on or newer than the specified date]:YYYY-MM-DD HH\:MM\:SS' \ diff --git a/shell-completion/zsh/_sd_unit_files b/shell-completion/zsh/_sd_unit_files index 4778a0420d..3e7a4ee803 100644 --- a/shell-completion/zsh/_sd_unit_files +++ b/shell-completion/zsh/_sd_unit_files @@ -5,5 +5,5 @@ _sd_unit_files() { files=( '*:files:->files' ) _description files expl 'unit file' - _files "$expl[@]" -g '*.(automount|busname|device|mount|path|service|snapshot|socket|swap|target|timer)' + _files "$expl[@]" -g '*.(automount|busname|device|mount|path|service|socket|swap|target|timer)' } diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 96f51a0ee0..58c88c9d98 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -43,8 +43,6 @@ "is-enabled:Check whether unit files are enabled" "list-jobs:List jobs" "cancel:Cancel all, one, or more jobs" - "snapshot:Create a snapshot" - "delete:Remove one or more snapshots" "show-environment:Dump environment" "set-environment:Set one or more environment variables" "unset-environment:Unset one or more environment variables" @@ -268,14 +266,6 @@ done _message "no jobs found" } -# Completion functions for SNAPSHOTS -(( $+functions[_systemctl_delete] )) || _systemctl_delete() -{ - _wanted systemd-snapshots expl snapshot \ - compadd "$@" - ${${(f)"$(__systemctl list-units --type snapshot --all)"}%% *} || - _message "no snapshots found" -} - # Completion functions for TARGETS (( $+functions[_systemctl_set-default] )) || _systemctl_set-default() { @@ -310,7 +300,6 @@ done # [STANDALONE]='daemon-reexec daemon-reload default # emergency exit halt kexec list-jobs list-units # list-unit-files poweroff reboot rescue show-environment' -# [NAME]='snapshot' _systemctl_caching_policy() { diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run index 8d6957fa9b..c425085cd8 100644 --- a/shell-completion/zsh/_systemd-run +++ b/shell-completion/zsh/_systemd-run @@ -26,7 +26,21 @@ _arguments \ {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \ '--scope[Run this as scope rather than service]' \ '--unit=[Run under the specified unit name]:unit name' \ - {-p+,--property=}'[Set unit property]:NAME=VALUE' \ + {-p+,--property=}'[Set unit property]:NAME=VALUE:(( \ + CPUAccounting= MemoryAccounting= BlockIOAccounting= SendSIGHUP= \ + SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \ + DevicePolicy= KillMode= DeviceAllow= BlockIOReadBandwidth= \ + BlockIOWriteBandwidth= BlockIODeviceWeight= Nice= Environment= \ + KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= \ + LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= \ + LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= \ + LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \ + PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= \ + TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= \ + SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= \ + ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= \ + ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment= \ + ))' \ '--description=[Description for unit]:description' \ '--slice=[Run in the specified slice]:slices:__slices' \ {-r,--remain-after-exit}'[Leave service around until explicitly stopped]' \ diff --git a/src/activate/activate.c b/src/activate/activate.c index 4ece1367c1..b7e6255f49 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -28,10 +28,13 @@ #include "sd-daemon.h" +#include "alloc-util.h" +#include "fd-util.h" #include "log.h" #include "macro.h" #include "signal-util.h" #include "socket-util.h" +#include "string-util.h" #include "strv.h" static char** arg_listen = NULL; diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index f4255f979e..deb102c22c 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -21,12 +21,15 @@ #include <stdlib.h> -#include "manager.h" +#include "alloc-util.h" +#include "analyze-verify.h" +#include "bus-error.h" #include "bus-util.h" #include "log.h" -#include "strv.h" +#include "manager.h" #include "pager.h" -#include "analyze-verify.h" +#include "path-util.h" +#include "strv.h" static int generate_path(char **var, char **filenames) { char **filename; @@ -162,7 +165,6 @@ static int verify_documentation(Unit *u, bool check_man) { static int verify_unit(Unit *u, bool check_man) { _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; - Job *j; int r, k; assert(u); @@ -171,11 +173,9 @@ static int verify_unit(Unit *u, bool check_man) { unit_dump(u, stdout, "\t"); log_unit_debug(u, "Creating %s/start job", u->id); - r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, false, &err, &j); - if (sd_bus_error_is_set(&err)) - log_unit_error(u, "Error: %s: %s", err.name, err.message); + r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL); if (r < 0) - log_unit_error_errno(u, r, "Failed to create %s/start: %m", u->id); + log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r)); k = verify_socket(u); if (k < 0 && r == 0) diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 4bf83eb329..e922d6fb32 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -27,12 +27,16 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "analyze-verify.h" #include "bus-error.h" #include "bus-util.h" +#include "glob-util.h" #include "hashmap.h" +#include "locale-util.h" #include "log.h" #include "pager.h" +#include "parse-util.h" #include "special.h" #include "strv.h" #include "strxcpyx.h" @@ -1062,20 +1066,17 @@ static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *fro assert(bus); assert(u); - if (arg_dot == DEP_ORDER ||arg_dot == DEP_ALL) { + if (IN_SET(arg_dot, DEP_ORDER, DEP_ALL)) { r = graph_one_property(bus, u, "After", "green", patterns, from_patterns, to_patterns); if (r < 0) return r; } - if (arg_dot == DEP_REQUIRE ||arg_dot == DEP_ALL) { + if (IN_SET(arg_dot, DEP_REQUIRE, DEP_ALL)) { r = graph_one_property(bus, u, "Requires", "black", patterns, from_patterns, to_patterns); if (r < 0) return r; - r = graph_one_property(bus, u, "RequiresOverridable", "black", patterns, from_patterns, to_patterns); - if (r < 0) - return r; - r = graph_one_property(bus, u, "RequisiteOverridable", "darkblue", patterns, from_patterns, to_patterns); + r = graph_one_property(bus, u, "Requisite", "darkblue", patterns, from_patterns, to_patterns); if (r < 0) return r; r = graph_one_property(bus, u, "Wants", "grey66", patterns, from_patterns, to_patterns); @@ -1084,9 +1085,6 @@ static int graph_one(sd_bus *bus, const UnitInfo *u, char *patterns[], char *fro r = graph_one_property(bus, u, "Conflicts", "red", patterns, from_patterns, to_patterns); if (r < 0) return r; - r = graph_one_property(bus, u, "ConflictedBy", "red", patterns, from_patterns, to_patterns); - if (r < 0) - return r; } return 0; diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index 1a69d15908..a544866000 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -144,7 +144,7 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_strv_free_ char **l = NULL; + _cleanup_strv_free_erase_ char **l = NULL; usec_t timeout; char **p; int r; diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index c8961de946..b0fa079fec 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -19,12 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "mkdir.h" -#include "fileio.h" #include "libudev.h" -#include "udev-util.h" + +#include "alloc-util.h" #include "def.h" +#include "escape.h" +#include "fileio.h" +#include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "string-util.h" +#include "udev-util.h" +#include "util.h" static struct udev_device *find_pci_or_platform_parent(struct udev_device *device) { struct udev_device *parent; @@ -375,7 +381,7 @@ int main(int argc, char *argv[]) { _cleanup_free_ char *value = NULL; const char *clamp; - if (!shall_restore_state()) + if (shall_restore_state() == 0) return EXIT_SUCCESS; if (!validate_device(udev, device)) diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c new file mode 100644 index 0000000000..48183e381f --- /dev/null +++ b/src/basic/alloc-util.c @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "util.h" + +void* memdup(const void *p, size_t l) { + void *r; + + assert(p); + + r = malloc(l); + if (!r) + return NULL; + + memcpy(r, p, l); + return r; +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { + size_t a, newalloc; + void *q; + + assert(p); + assert(allocated); + + if (*allocated >= need) + return *p; + + newalloc = MAX(need * 2, 64u / size); + a = newalloc * size; + + /* check for overflows */ + if (a < size * need) + return NULL; + + q = realloc(*p, a); + if (!q) + return NULL; + + *p = q; + *allocated = newalloc; + return q; +} + +void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { + size_t prev; + uint8_t *q; + + assert(p); + assert(allocated); + + prev = *allocated; + + q = greedy_realloc(p, allocated, need, size); + if (!q) + return NULL; + + if (*allocated > prev) + memzero(q + prev * size, (*allocated - prev) * size); + + return q; +} diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h new file mode 100644 index 0000000000..12b602e185 --- /dev/null +++ b/src/basic/alloc-util.h @@ -0,0 +1,108 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <alloca.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h" + +#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) + +#define new0(t, n) ((t*) calloc((n), sizeof(t))) + +#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) + +#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) + +#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) + +#define malloc0(n) (calloc(1, (n))) + +static inline void *mfree(void *memory) { + free(memory); + return NULL; +} + +void* memdup(const void *p, size_t l) _alloc_(2); + +static inline void freep(void *p) { + free(*(void**) p); +} + +#define _cleanup_free_ _cleanup_(freep) + +_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return malloc(a * b); +} + +_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return realloc(p, a * b); +} + +_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return memdup(p, a * b); +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); +void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); + +#define GREEDY_REALLOC(array, allocated, need) \ + greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define GREEDY_REALLOC0(array, allocated, need) \ + greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define alloca0(n) \ + ({ \ + char *_new_; \ + size_t _len_ = n; \ + _new_ = alloca(_len_); \ + (void *) memset(_new_, 0, _len_); \ + }) + +/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ +#define alloca_align(size, align) \ + ({ \ + void *_ptr_; \ + size_t _mask_ = (align) - 1; \ + _ptr_ = alloca((size) + _mask_); \ + (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ + }) + +#define alloca0_align(size, align) \ + ({ \ + void *_new_; \ + size_t _size_ = (size); \ + _new_ = alloca_align(_size_, (align)); \ + (void*)memset(_new_, 0, _size_); \ + }) diff --git a/src/basic/async.c b/src/basic/async.c index 7725e6d7d3..c3135f0efe 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -23,6 +23,7 @@ #include <unistd.h> #include "async.h" +#include "fd-util.h" #include "log.h" #include "util.h" diff --git a/src/basic/audit.c b/src/basic/audit-util.c index 1f593aa813..4612297334 100644 --- a/src/basic/audit.c +++ b/src/basic/audit-util.c @@ -22,11 +22,15 @@ #include <errno.h> #include <stdio.h> +#include "alloc-util.h" +#include "audit-util.h" +#include "fd-util.h" +#include "fileio.h" #include "macro.h" -#include "audit.h" -#include "util.h" +#include "parse-util.h" #include "process-util.h" -#include "fileio.h" +#include "user-util.h" +#include "util.h" int audit_session_from_pid(pid_t pid, uint32_t *id) { _cleanup_free_ char *s = NULL; diff --git a/src/basic/audit.h b/src/basic/audit-util.h index 6de331c73e..6de331c73e 100644 --- a/src/basic/audit.h +++ b/src/basic/audit-util.h diff --git a/src/basic/barrier.c b/src/basic/barrier.c index 436ba95989..2d55bab4ab 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -30,6 +30,7 @@ #include <unistd.h> #include "barrier.h" +#include "fd-util.h" #include "macro.h" #include "util.h" diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index 2eabf3e1c1..1449e2ea85 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" - +#include "alloc-util.h" #include "bitmap.h" +#include "util.h" struct Bitmap { uint64_t *bitmaps; diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 074deeccda..290fabdeff 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -20,23 +20,26 @@ ***/ #include <stdlib.h> -#include <sys/vfs.h> #include <sys/stat.h> - +#include <sys/vfs.h> #ifdef HAVE_LINUX_BTRFS_H #include <linux/btrfs.h> #endif +#include "alloc-util.h" +#include "btrfs-ctree.h" +#include "btrfs-util.h" +#include "copy.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" #include "missing.h" -#include "util.h" #include "path-util.h" -#include "macro.h" -#include "copy.h" #include "selinux-util.h" #include "smack-util.h" -#include "fileio.h" -#include "btrfs-ctree.h" -#include "btrfs-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "util.h" /* WARNING: Be careful with file system ioctls! When we get an fd, we * need to make sure it either refers to only a regular file or @@ -59,13 +62,13 @@ static int validate_subvolume_name(const char *name) { static int open_parent(const char *path, int flags) { _cleanup_free_ char *parent = NULL; - int r, fd; + int fd; assert(path); - r = path_get_parent(path, &parent); - if (r < 0) - return r; + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; fd = open(parent, flags); if (fd < 0) @@ -436,7 +439,7 @@ static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \ ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header))) -int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) { +int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) { struct btrfs_ioctl_search_args args = { /* Tree of tree roots */ .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, @@ -453,16 +456,23 @@ int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) { .key.max_transid = (uint64_t) -1, }; - uint64_t subvol_id; bool found = false; int r; assert(fd >= 0); assert(ret); - r = btrfs_subvol_get_id_fd(fd, &subvol_id); - if (r < 0) - return r; + if (subvol_id == 0) { + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } args.key.min_objectid = args.key.max_objectid = subvol_id; @@ -521,7 +531,7 @@ finish: return 0; } -int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { +int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) { struct btrfs_ioctl_search_args args = { /* Tree of quota items */ @@ -540,26 +550,37 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { .key.max_transid = (uint64_t) -1, }; - uint64_t subvol_id; bool found_info = false, found_limit = false; int r; assert(fd >= 0); assert(ret); - r = btrfs_subvol_get_id_fd(fd, &subvol_id); - if (r < 0) - return r; + if (qgroupid == 0) { + r = btrfs_subvol_get_id_fd(fd, &qgroupid); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } - args.key.min_offset = args.key.max_offset = subvol_id; + args.key.min_offset = args.key.max_offset = qgroupid; while (btrfs_ioctl_search_args_compare(&args) <= 0) { const struct btrfs_ioctl_search_header *sh; unsigned i; args.key.nr_items = 256; - if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) { + if (errno == ENOENT) /* quota tree is missing: quota disabled */ + break; + return -errno; + } if (args.key.nr_items <= 0) break; @@ -571,7 +592,7 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { if (sh->objectid != 0) continue; - if (sh->offset != subvol_id) + if (sh->offset != qgroupid) continue; if (sh->type == BTRFS_QGROUP_INFO_KEY) { @@ -585,12 +606,14 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) { const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh); - ret->referenced_max = le64toh(qli->max_rfer); - ret->exclusive_max = le64toh(qli->max_excl); - - if (ret->referenced_max == 0) + if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER) + ret->referenced_max = le64toh(qli->max_rfer); + else ret->referenced_max = (uint64_t) -1; - if (ret->exclusive_max == 0) + + if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_EXCL) + ret->exclusive_max = le64toh(qli->max_excl); + else ret->exclusive_max = (uint64_t) -1; found_limit = true; @@ -622,6 +645,109 @@ finish: return 0; } +int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *ret) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret); +} + +int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) { + uint64_t level, lowest = (uint64_t) -1, lowest_qgroupid = 0; + _cleanup_free_ uint64_t *qgroups = NULL; + int r, n, i; + + assert(fd >= 0); + assert(ret); + + /* This finds the "subtree" qgroup for a specific + * subvolume. This only works for subvolumes that have been + * prepared with btrfs_subvol_auto_qgroup_fd() with + * insert_intermediary_qgroup=true (or equivalent). For others + * it will return the leaf qgroup instead. The two cases may + * be distuingished via the return value, which is 1 in case + * an appropriate "subtree" qgroup was found, and 0 + * otherwise. */ + + if (subvol_id == 0) { + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } + + r = btrfs_qgroupid_split(subvol_id, &level, NULL); + if (r < 0) + return r; + if (level != 0) /* Input must be a leaf qgroup */ + return -EINVAL; + + n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups); + if (n < 0) + return n; + + for (i = 0; i < n; i++) { + uint64_t id; + + r = btrfs_qgroupid_split(qgroups[i], &level, &id); + if (r < 0) + return r; + + if (id != subvol_id) + continue; + + if (lowest == (uint64_t) -1 || level < lowest) { + lowest_qgroupid = qgroups[i]; + lowest = level; + } + } + + if (lowest == (uint64_t) -1) { + /* No suitable higher-level qgroup found, let's return + * the leaf qgroup instead, and indicate that with the + * return value. */ + + *ret = subvol_id; + return 0; + } + + *ret = lowest_qgroupid; + return 1; +} + +int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *ret) { + uint64_t qgroupid; + int r; + + assert(fd >= 0); + assert(ret); + + /* This determines the quota data of the qgroup with the + * lowest level, that shares the id part with the specified + * subvolume. This is useful for determining the quota data + * for entire subvolume subtrees, as long as the subtrees have + * been set up with btrfs_qgroup_subvol_auto_fd() or in a + * compatible way */ + + r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid); + if (r < 0) + return r; + + return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret); +} + +int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *ret) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret); +} + int btrfs_defrag_fd(int fd) { struct stat st; @@ -679,37 +805,79 @@ int btrfs_quota_enable(const char *path, bool b) { return btrfs_quota_enable_fd(fd, b); } -int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) { +int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max) { + struct btrfs_ioctl_qgroup_limit_args args = { - .lim.max_rfer = - referenced_max == (uint64_t) -1 ? 0 : - referenced_max == 0 ? 1 : referenced_max, + .lim.max_rfer = referenced_max, .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER, }; + unsigned c; int r; assert(fd >= 0); - r = btrfs_is_filesystem(fd); - if (r < 0) - return r; - if (!r) - return -ENOTTY; + if (qgroupid == 0) { + r = btrfs_subvol_get_id_fd(fd, &qgroupid); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } - if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) - return -errno; + args.qgroupid = qgroupid; + + for (c = 0;; c++) { + if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) { + + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + + return -errno; + } + + break; + } return 0; } -int btrfs_quota_limit(const char *path, uint64_t referenced_max) { +int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max); +} + +int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max) { + uint64_t qgroupid; + int r; + + assert(fd >= 0); + + r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid); + if (r < 0) + return r; + + return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max); +} + +int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max) { _cleanup_close_ int fd = -1; fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fd < 0) return -errno; - return btrfs_quota_limit_fd(fd, referenced_max); + return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max); } int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { @@ -799,7 +967,192 @@ int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) { return btrfs_resize_loopback_fd(fd, new_size, grow_only); } -static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) { +int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) { + assert(ret); + + if (level >= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT))) + return -EINVAL; + + if (id >= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT)) + return -EINVAL; + + *ret = (level << BTRFS_QGROUP_LEVEL_SHIFT) | id; + return 0; +} + +int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id) { + assert(level || id); + + if (level) + *level = qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT; + + if (id) + *id = qgroupid & ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT) - 1); + + return 0; +} + +static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) { + + struct btrfs_ioctl_qgroup_create_args args = { + .create = b, + .qgroupid = qgroupid, + }; + unsigned c; + int r; + + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (r == 0) + return -ENOTTY; + + for (c = 0;; c++) { + if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) { + + /* If quota is not enabled, we get EINVAL. Turn this into a recognizable error */ + if (errno == EINVAL) + return -ENOPROTOOPT; + + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + + return -errno; + } + + break; + } + + return 0; +} + +int btrfs_qgroup_create(int fd, uint64_t qgroupid) { + return qgroup_create_or_destroy(fd, true, qgroupid); +} + +int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) { + return qgroup_create_or_destroy(fd, false, qgroupid); +} + +int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) { + _cleanup_free_ uint64_t *qgroups = NULL; + uint64_t subvol_id; + int i, n, r; + + /* Destroys the specified qgroup, but unassigns it from all + * its parents first. Also, it recursively destroys all + * qgroups it is assgined to that have the same id part of the + * qgroupid as the specified group. */ + + r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id); + if (r < 0) + return r; + + n = btrfs_qgroup_find_parents(fd, qgroupid, &qgroups); + if (n < 0) + return n; + + for (i = 0; i < n; i++) { + uint64_t id; + + r = btrfs_qgroupid_split(qgroups[i], NULL, &id); + if (r < 0) + return r; + + r = btrfs_qgroup_unassign(fd, qgroupid, qgroups[i]); + if (r < 0) + return r; + + if (id != subvol_id) + continue; + + /* The parent qgroupid shares the same id part with + * us? If so, destroy it too. */ + + (void) btrfs_qgroup_destroy_recursive(fd, qgroups[i]); + } + + return btrfs_qgroup_destroy(fd, qgroupid); +} + +int btrfs_quota_scan_start(int fd) { + struct btrfs_ioctl_quota_rescan_args args = {}; + + assert(fd >= 0); + + if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0) + return -errno; + + return 0; +} + +int btrfs_quota_scan_wait(int fd) { + assert(fd >= 0); + + if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0) + return -errno; + + return 0; +} + +int btrfs_quota_scan_ongoing(int fd) { + struct btrfs_ioctl_quota_rescan_args args = {}; + + assert(fd >= 0); + + if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_STATUS, &args) < 0) + return -errno; + + return !!args.flags; +} + +static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t parent) { + struct btrfs_ioctl_qgroup_assign_args args = { + .assign = b, + .src = child, + .dst = parent, + }; + unsigned c; + int r; + + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (r == 0) + return -ENOTTY; + + for (c = 0;; c++) { + r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args); + if (r < 0) { + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + + return -errno; + } + + if (r == 0) + return 0; + + /* If the return value is > 0, we need to request a rescan */ + + (void) btrfs_quota_scan_start(fd); + return 1; + } +} + +int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent) { + return qgroup_assign_or_unassign(fd, true, child, parent); +} + +int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent) { + return qgroup_assign_or_unassign(fd, false, child, parent); +} + +static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, BtrfsRemoveFlags flags) { struct btrfs_ioctl_search_args args = { .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, @@ -828,16 +1181,6 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (!S_ISDIR(st.st_mode)) return -EINVAL; - /* First, try to remove the subvolume. If it happens to be - * already empty, this will just work. */ - strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1); - if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) - return 0; - if (!recursive || errno != ENOTEMPTY) - return -errno; - - /* OK, the subvolume is not empty, let's look for child - * subvolumes, and remove them, first */ subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); if (subvol_fd < 0) return -errno; @@ -848,6 +1191,19 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol return r; } + /* First, try to remove the subvolume. If it happens to be + * already empty, this will just work. */ + strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1); + if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) { + (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */ + return 0; + } + if (!(flags & BTRFS_REMOVE_RECURSIVE) || errno != ENOTEMPTY) + return -errno; + + /* OK, the subvolume is not empty, let's look for child + * subvolumes, and remove them, first */ + args.key.min_offset = args.key.max_offset = subvol_id; while (btrfs_ioctl_search_args_compare(&args) <= 0) { @@ -897,7 +1253,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (isempty(ino_args.name)) /* Subvolume is in the top-level * directory of the subvolume. */ - r = subvol_remove_children(subvol_fd, p, sh->objectid, recursive); + r = subvol_remove_children(subvol_fd, p, sh->objectid, flags); else { _cleanup_close_ int child_fd = -1; @@ -909,7 +1265,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (child_fd < 0) return -errno; - r = subvol_remove_children(child_fd, p, sh->objectid, recursive); + r = subvol_remove_children(child_fd, p, sh->objectid, flags); } if (r < 0) return r; @@ -925,10 +1281,11 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0) return -errno; + (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); return 0; } -int btrfs_subvol_remove(const char *path, bool recursive) { +int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) { _cleanup_close_ int fd = -1; const char *subvolume; int r; @@ -943,11 +1300,198 @@ int btrfs_subvol_remove(const char *path, bool recursive) { if (fd < 0) return fd; - return subvol_remove_children(fd, subvolume, 0, recursive); + return subvol_remove_children(fd, subvolume, 0, flags); +} + +int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) { + return subvol_remove_children(fd, subvolume, 0, flags); +} + +int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid) { + + struct btrfs_ioctl_search_args args = { + /* Tree of quota items */ + .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID, + + /* The object ID is always 0 */ + .key.min_objectid = 0, + .key.max_objectid = 0, + + /* Look precisely for the quota items */ + .key.min_type = BTRFS_QGROUP_LIMIT_KEY, + .key.max_type = BTRFS_QGROUP_LIMIT_KEY, + + /* For our qgroup */ + .key.min_offset = old_qgroupid, + .key.max_offset = old_qgroupid, + + /* No restrictions on the other components */ + .key.min_transid = 0, + .key.max_transid = (uint64_t) -1, + }; + + int r; + + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + + while (btrfs_ioctl_search_args_compare(&args) <= 0) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; + + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) { + if (errno == ENOENT) /* quota tree missing: quota is not enabled, hence nothing to copy */ + break; + + return -errno; + } + + if (args.key.nr_items <= 0) + break; + + FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) { + const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh); + struct btrfs_ioctl_qgroup_limit_args qargs; + unsigned c; + + /* Make sure we start the next search at least from this entry */ + btrfs_ioctl_search_args_set(&args, sh); + + if (sh->objectid != 0) + continue; + if (sh->type != BTRFS_QGROUP_LIMIT_KEY) + continue; + if (sh->offset != old_qgroupid) + continue; + + /* We found the entry, now copy things over. */ + + qargs = (struct btrfs_ioctl_qgroup_limit_args) { + .qgroupid = new_qgroupid, + + .lim.max_rfer = le64toh(qli->max_rfer), + .lim.max_excl = le64toh(qli->max_excl), + .lim.rsv_rfer = le64toh(qli->rsv_rfer), + .lim.rsv_excl = le64toh(qli->rsv_excl), + + .lim.flags = le64toh(qli->flags) & (BTRFS_QGROUP_LIMIT_MAX_RFER| + BTRFS_QGROUP_LIMIT_MAX_EXCL| + BTRFS_QGROUP_LIMIT_RSV_RFER| + BTRFS_QGROUP_LIMIT_RSV_EXCL), + }; + + for (c = 0;; c++) { + if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &qargs) < 0) { + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + return -errno; + } + + break; + } + + return 1; + } + + /* Increase search key by one, to read the next item, if we can. */ + if (!btrfs_ioctl_search_args_inc(&args)) + break; + } + + return 0; +} + +static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) { + _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL; + bool copy_from_parent = false, insert_intermediary_qgroup = false; + int n_old_qgroups, n_old_parent_qgroups, r, i; + uint64_t old_parent_id; + + assert(fd >= 0); + + /* Copies a reduced form of quota information from the old to + * the new subvolume. */ + + n_old_qgroups = btrfs_qgroup_find_parents(fd, old_subvol_id, &old_qgroups); + if (n_old_qgroups <= 0) /* Nothing to copy */ + return n_old_qgroups; + + r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id); + if (r < 0) + return r; + + n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups); + if (n_old_parent_qgroups < 0) + return n_old_parent_qgroups; + + for (i = 0; i < n_old_qgroups; i++) { + uint64_t id; + int j; + + r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id); + if (r < 0) + return r; + + if (id == old_subvol_id) { + /* The old subvolume was member of a qgroup + * that had the same id, but a different level + * as it self. Let's set up something similar + * in the destination. */ + insert_intermediary_qgroup = true; + break; + } + + for (j = 0; j < n_old_parent_qgroups; j++) + if (old_parent_qgroups[j] == old_qgroups[i]) { + /* The old subvolume shared a common + * parent qgroup with its parent + * subvolume. Let's set up something + * similar in the destination. */ + copy_from_parent = true; + } + } + + if (!insert_intermediary_qgroup && !copy_from_parent) + return 0; + + return btrfs_subvol_auto_qgroup_fd(fd, new_subvol_id, insert_intermediary_qgroup); } -int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive) { - return subvol_remove_children(fd, subvolume, 0, recursive); +static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_subvol) { + uint64_t old_subtree_qgroup, new_subtree_qgroup; + bool changed; + int r; + + /* First copy the leaf limits */ + r = btrfs_qgroup_copy_limits(fd, old_subvol, new_subvol); + if (r < 0) + return r; + changed = r > 0; + + /* Then, try to copy the subtree limits, if there are any. */ + r = btrfs_subvol_find_subtree_qgroup(fd, old_subvol, &old_subtree_qgroup); + if (r < 0) + return r; + if (r == 0) + return changed; + + r = btrfs_subvol_find_subtree_qgroup(fd, new_subvol, &new_subtree_qgroup); + if (r < 0) + return r; + if (r == 0) + return changed; + + r = btrfs_qgroup_copy_limits(fd, old_subtree_qgroup, new_subtree_qgroup); + if (r != 0) + return r; + + return changed; } static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) { @@ -978,12 +1522,12 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum assert(subvolume); strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1); - vol_args.fd = old_fd; if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0) return -errno; - if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) + if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) && + !(flags & BTRFS_SNAPSHOT_QUOTA)) return 0; if (old_subvol_id == 0) { @@ -996,6 +1540,17 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum if (r < 0) return r; + if (flags & BTRFS_SNAPSHOT_QUOTA) + (void) copy_quota_hierarchy(new_fd, old_subvol_id, new_subvol_id); + + if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) { + + if (flags & BTRFS_SNAPSHOT_QUOTA) + (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id); + + return 0; + } + args.key.min_offset = args.key.max_offset = old_subvol_id; while (btrfs_ioctl_search_args_compare(&args) <= 0) { @@ -1113,6 +1668,9 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum break; } + if (flags & BTRFS_SNAPSHOT_QUOTA) + (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id); + return 0; } @@ -1137,14 +1695,14 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag r = copy_directory_fd(old_fd, new_path, true); if (r < 0) { - btrfs_subvol_remove(new_path, false); + (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA); return r; } if (flags & BTRFS_SNAPSHOT_READ_ONLY) { r = btrfs_subvol_set_read_only(new_path, true); if (r < 0) { - btrfs_subvol_remove(new_path, false); + (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA); return r; } } @@ -1175,3 +1733,306 @@ int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnaps return btrfs_subvol_snapshot_fd(old_fd, new_path, flags); } + +int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) { + + struct btrfs_ioctl_search_args args = { + /* Tree of quota items */ + .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID, + + /* Look precisely for the quota relation items */ + .key.min_type = BTRFS_QGROUP_RELATION_KEY, + .key.max_type = BTRFS_QGROUP_RELATION_KEY, + + /* No restrictions on the other components */ + .key.min_offset = 0, + .key.max_offset = (uint64_t) -1, + + .key.min_transid = 0, + .key.max_transid = (uint64_t) -1, + }; + + _cleanup_free_ uint64_t *items = NULL; + size_t n_items = 0, n_allocated = 0; + int r; + + assert(fd >= 0); + assert(ret); + + if (qgroupid == 0) { + r = btrfs_subvol_get_id_fd(fd, &qgroupid); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } + + args.key.min_objectid = args.key.max_objectid = qgroupid; + + while (btrfs_ioctl_search_args_compare(&args) <= 0) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; + + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) { + if (errno == ENOENT) /* quota tree missing: quota is disabled */ + break; + + return -errno; + } + + if (args.key.nr_items <= 0) + break; + + FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) { + + /* Make sure we start the next search at least from this entry */ + btrfs_ioctl_search_args_set(&args, sh); + + if (sh->type != BTRFS_QGROUP_RELATION_KEY) + continue; + if (sh->offset < sh->objectid) + continue; + if (sh->objectid != qgroupid) + continue; + + if (!GREEDY_REALLOC(items, n_allocated, n_items+1)) + return -ENOMEM; + + items[n_items++] = sh->offset; + } + + /* Increase search key by one, to read the next item, if we can. */ + if (!btrfs_ioctl_search_args_inc(&args)) + break; + } + + if (n_items <= 0) { + *ret = NULL; + return 0; + } + + *ret = items; + items = NULL; + + return (int) n_items; +} + +int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) { + _cleanup_free_ uint64_t *qgroups = NULL; + uint64_t parent_subvol; + bool changed = false; + int n = 0, r; + + assert(fd >= 0); + + /* + * Sets up the specified subvolume's qgroup automatically in + * one of two ways: + * + * If insert_intermediary_qgroup is false, the subvolume's + * leaf qgroup will be assigned to the same parent qgroups as + * the subvolume's parent subvolume. + * + * If insert_intermediary_qgroup is true a new intermediary + * higher-level qgroup is created, with a higher level number, + * but reusing the id of the subvolume. The level number is + * picked as one smaller than the lowest level qgroup the + * parent subvolume is a member of. If the parent subvolume's + * leaf qgroup is assigned to no higher-level qgroup a new + * qgroup of level 255 is created instead. Either way, the new + * qgroup is then assigned to the parent's higher-level + * qgroup, and the subvolume itself is assigned to it. + * + * If the subvolume is already assigned to a higher level + * qgroup, no operation is executed. + * + * Effectively this means: regardless if + * insert_intermediary_qgroup is true or not, after this + * function is invoked the subvolume will be accounted within + * the same qgroups as the parent. However, if it is true, it + * will also get its own higher-level qgroup, which may in + * turn be used by subvolumes created beneath this subvolume + * later on. + * + * This hence defines a simple default qgroup setup for + * subvolumes, as long as this function is invoked on each + * created subvolume: each subvolume is always accounting + * together with its immediate parents. Optionally, if + * insert_intermediary_qgroup is true, it will also get a + * qgroup that then includes all its own child subvolumes. + */ + + if (subvol_id == 0) { + r = btrfs_is_subvol(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } + + n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups); + if (n < 0) + return n; + if (n > 0) /* already parent qgroups set up, let's bail */ + return 0; + + r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol); + if (r < 0) + return r; + + qgroups = mfree(qgroups); + n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups); + if (n < 0) + return n; + + if (insert_intermediary_qgroup) { + uint64_t lowest = 256, new_qgroupid; + bool created = false; + int i; + + /* Determine the lowest qgroup that the parent + * subvolume is assigned to. */ + + for (i = 0; i < n; i++) { + uint64_t level; + + r = btrfs_qgroupid_split(qgroups[i], &level, NULL); + if (r < 0) + return r; + + if (level < lowest) + lowest = level; + } + + if (lowest <= 1) /* There are no levels left we could use insert an intermediary qgroup at */ + return -EBUSY; + + r = btrfs_qgroupid_make(lowest - 1, subvol_id, &new_qgroupid); + if (r < 0) + return r; + + /* Create the new intermediary group, unless it already exists */ + r = btrfs_qgroup_create(fd, new_qgroupid); + if (r < 0 && r != -EEXIST) + return r; + if (r >= 0) + changed = created = true; + + for (i = 0; i < n; i++) { + r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]); + if (r < 0 && r != -EEXIST) { + if (created) + (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid); + + return r; + } + if (r >= 0) + changed = true; + } + + r = btrfs_qgroup_assign(fd, subvol_id, new_qgroupid); + if (r < 0 && r != -EEXIST) { + if (created) + (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid); + return r; + } + if (r >= 0) + changed = true; + + } else { + int i; + + /* Assign our subvolume to all the same qgroups as the parent */ + + for (i = 0; i < n; i++) { + r = btrfs_qgroup_assign(fd, subvol_id, qgroups[i]); + if (r < 0 && r != -EEXIST) + return r; + if (r >= 0) + changed = true; + } + } + + return changed; +} + +int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (fd < 0) + return -errno; + + return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup); +} + +int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) { + + struct btrfs_ioctl_search_args args = { + /* Tree of tree roots */ + .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, + + /* Look precisely for the subvolume items */ + .key.min_type = BTRFS_ROOT_BACKREF_KEY, + .key.max_type = BTRFS_ROOT_BACKREF_KEY, + + /* No restrictions on the other components */ + .key.min_offset = 0, + .key.max_offset = (uint64_t) -1, + + .key.min_transid = 0, + .key.max_transid = (uint64_t) -1, + }; + int r; + + assert(fd >= 0); + assert(ret); + + if (subvol_id == 0) { + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } + + args.key.min_objectid = args.key.max_objectid = subvol_id; + + while (btrfs_ioctl_search_args_compare(&args) <= 0) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; + + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) + return -errno; + + if (args.key.nr_items <= 0) + break; + + FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) { + + if (sh->type != BTRFS_ROOT_BACKREF_KEY) + continue; + if (sh->objectid != subvol_id) + continue; + + *ret = sh->offset; + return 0; + } + } + + return -ENXIO; +} diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 8632c3638c..fc9efd72d5 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -47,42 +47,82 @@ typedef enum BtrfsSnapshotFlags { BTRFS_SNAPSHOT_FALLBACK_COPY = 1, BTRFS_SNAPSHOT_READ_ONLY = 2, BTRFS_SNAPSHOT_RECURSIVE = 4, + BTRFS_SNAPSHOT_QUOTA = 8, } BtrfsSnapshotFlags; +typedef enum BtrfsRemoveFlags { + BTRFS_REMOVE_RECURSIVE = 1, + BTRFS_REMOVE_QUOTA = 2, +} BtrfsRemoveFlags; + int btrfs_is_filesystem(int fd); int btrfs_is_subvol(int fd); +int btrfs_reflink(int infd, int outfd); +int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz); + +int btrfs_get_block_device_fd(int fd, dev_t *dev); +int btrfs_get_block_device(const char *path, dev_t *dev); + +int btrfs_defrag_fd(int fd); +int btrfs_defrag(const char *p); + +int btrfs_quota_enable_fd(int fd, bool b); +int btrfs_quota_enable(const char *path, bool b); + +int btrfs_quota_scan_start(int fd); +int btrfs_quota_scan_wait(int fd); +int btrfs_quota_scan_ongoing(int fd); + +int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only); +int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only); + int btrfs_subvol_make(const char *path); int btrfs_subvol_make_label(const char *path); int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags); int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags); +int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags); +int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags); + int btrfs_subvol_set_read_only_fd(int fd, bool b); int btrfs_subvol_set_read_only(const char *path, bool b); int btrfs_subvol_get_read_only_fd(int fd); + int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret); int btrfs_subvol_get_id_fd(int fd, uint64_t *ret); -int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *info); -int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota); +int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret); -int btrfs_reflink(int infd, int outfd); -int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz); +int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *info); -int btrfs_get_block_device_fd(int fd, dev_t *dev); -int btrfs_get_block_device(const char *path, dev_t *dev); +int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret); -int btrfs_defrag_fd(int fd); -int btrfs_defrag(const char *p); +int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *quota); +int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *quota); -int btrfs_quota_enable_fd(int fd, bool b); -int btrfs_quota_enable(const char *path, bool b); +int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max); +int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max); -int btrfs_quota_limit_fd(int fd, uint64_t referenced_max); -int btrfs_quota_limit(const char *path, uint64_t referenced_max); +int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool new_qgroup); +int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup); -int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only); -int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only); +int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret); +int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id); + +int btrfs_qgroup_create(int fd, uint64_t qgroupid); +int btrfs_qgroup_destroy(int fd, uint64_t qgroupid); +int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid); + +int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max); +int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max); + +int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid); + +int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent); +int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent); + +int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret); -int btrfs_subvol_remove(const char *path, bool recursive); -int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive); +int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota); +int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota); diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c index ccc9f2bf8e..c1534657ac 100644 --- a/src/basic/bus-label.c +++ b/src/basic/bus-label.c @@ -21,10 +21,11 @@ #include <stdlib.h> -#include "util.h" -#include "macro.h" - +#include "alloc-util.h" #include "bus-label.h" +#include "hexdecoct.h" +#include "macro.h" +#include "util.h" char *bus_label_escape(const char *s) { char *r, *t; diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 2dcc9c5575..7151fc3d0c 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -22,7 +22,10 @@ #include <stdlib.h> #include <string.h> +#include "alloc-util.h" +#include "string-util.h" #include "calendarspec.h" +#include "fileio.h" #define BITS_WEEKDAYS 127 @@ -279,6 +282,9 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { fputc(':', f); format_chain(f, 2, c->second); + if (c->utc) + fputs(" UTC", f); + r = fflush_and_check(f); if (r < 0) { free(buf); @@ -556,7 +562,7 @@ static int parse_date(const char **p, CalendarSpec *c) { return -EINVAL; } -static int parse_time(const char **p, CalendarSpec *c) { +static int parse_calendar_time(const char **p, CalendarSpec *c) { CalendarComponent *h = NULL, *m = NULL, *s = NULL; const char *t; int r; @@ -646,6 +652,7 @@ fail: int calendar_spec_from_string(const char *p, CalendarSpec **spec) { CalendarSpec *c; int r; + const char *utc; assert(p); assert(spec); @@ -657,6 +664,12 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (!c) return -ENOMEM; + utc = endswith_no_case(p, " UTC"); + if (utc) { + c->utc = true; + p = strndupa(p, utc - p); + } + if (strcaseeq(p, "minutely")) { r = const_chain(0, &c->second); if (r < 0) @@ -789,7 +802,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (r < 0) goto fail; - r = parse_time(&p, c); + r = parse_calendar_time(&p, c); if (r < 0) goto fail; @@ -859,13 +872,13 @@ static int find_matching_component(const CalendarComponent *c, int *val) { return r; } -static bool tm_out_of_bounds(const struct tm *tm) { +static bool tm_out_of_bounds(const struct tm *tm, bool utc) { struct tm t; assert(tm); t = *tm; - if (mktime(&t) == (time_t) -1) + if (mktime_or_timegm(&t, utc) == (time_t) -1) return true; /* Did any normalization take place? If so, it was out of bounds before */ @@ -878,7 +891,7 @@ static bool tm_out_of_bounds(const struct tm *tm) { t.tm_sec != tm->tm_sec; } -static bool matches_weekday(int weekdays_bits, const struct tm *tm) { +static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { struct tm t; int k; @@ -886,7 +899,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) { return true; t = *tm; - if (mktime(&t) == (time_t) -1) + if (mktime_or_timegm(&t, utc) == (time_t) -1) return false; k = t.tm_wday == 0 ? 6 : t.tm_wday - 1; @@ -904,7 +917,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { for (;;) { /* Normalize the current date */ - mktime(&c); + mktime_or_timegm(&c, spec->utc); c.tm_isdst = -1; c.tm_year += 1900; @@ -916,7 +929,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = 0; } - if (r < 0 || tm_out_of_bounds(&c)) + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) return r; c.tm_mon += 1; @@ -927,7 +940,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = 0; } - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_year ++; c.tm_mon = 0; c.tm_mday = 1; @@ -938,14 +951,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { r = find_matching_component(spec->day, &c.tm_mday); if (r > 0) c.tm_hour = c.tm_min = c.tm_sec = 0; - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_mon ++; c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = 0; continue; } - if (!matches_weekday(spec->weekdays_bits, &c)) { + if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) { c.tm_mday++; c.tm_hour = c.tm_min = c.tm_sec = 0; continue; @@ -954,7 +967,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { r = find_matching_component(spec->hour, &c.tm_hour); if (r > 0) c.tm_min = c.tm_sec = 0; - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_mday ++; c.tm_hour = c.tm_min = c.tm_sec = 0; continue; @@ -963,14 +976,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { r = find_matching_component(spec->minute, &c.tm_min); if (r > 0) c.tm_sec = 0; - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_hour ++; c.tm_min = c.tm_sec = 0; continue; } r = find_matching_component(spec->second, &c.tm_sec); - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_min ++; c.tm_sec = 0; continue; @@ -991,13 +1004,13 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) assert(next); t = (time_t) (usec / USEC_PER_SEC) + 1; - assert_se(localtime_r(&t, &tm)); + assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc)); r = find_next(spec, &tm); if (r < 0) return r; - t = mktime(&tm); + t = mktime_or_timegm(&tm, spec->utc); if (t == (time_t) -1) return -EINVAL; diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h index 7baf318249..56dc02f391 100644 --- a/src/basic/calendarspec.h +++ b/src/basic/calendarspec.h @@ -36,6 +36,7 @@ typedef struct CalendarComponent { typedef struct CalendarSpec { int weekdays_bits; + bool utc; CalendarComponent *year; CalendarComponent *month; diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index bd5bffbfa5..4d391510bc 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -21,9 +21,10 @@ #include <string.h> -#include "util.h" #include "cap-list.h" #include "missing.h" +#include "parse-util.h" +#include "util.h" static const struct capability_name* lookup_capability(register const char *str, register unsigned int len); diff --git a/src/basic/capability.c b/src/basic/capability-util.c index 8dbe4da5bb..0eb5c03d65 100644 --- a/src/basic/capability.c +++ b/src/basic/capability-util.c @@ -19,18 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> +#include <grp.h> #include <stdio.h> #include <sys/capability.h> #include <sys/prctl.h> -#include "grp.h" +#include <unistd.h> +#include "alloc-util.h" +#include "capability-util.h" +#include "fileio.h" +#include "log.h" #include "macro.h" +#include "parse-util.h" #include "util.h" -#include "log.h" -#include "fileio.h" -#include "capability.h" int have_effective_cap(int value) { _cleanup_cap_free_ cap_t cap; @@ -276,10 +278,8 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) { assert(keep_capabilities & (1ULL << (i - 1))); if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 || - cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0) { - log_error_errno(errno, "Failed to enable capabilities bits: %m"); - return -errno; - } + cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0) + return log_error_errno(errno, "Failed to enable capabilities bits: %m"); if (cap_set_proc(d) < 0) return log_error_errno(errno, "Failed to increase capabilities: %m"); diff --git a/src/basic/capability.h b/src/basic/capability-util.h index 4eb5c2a835..4eb5c2a835 100644 --- a/src/basic/capability.h +++ b/src/basic/capability-util.h diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 95fc2b9e5d..f7fc2c2c97 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -19,28 +19,39 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <dirent.h> #include <errno.h> -#include <unistd.h> +#include <ftw.h> #include <signal.h> -#include <string.h> #include <stdlib.h> -#include <dirent.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> -#include <ftw.h> +#include <unistd.h> -#include "set.h" -#include "macro.h" -#include "util.h" +#include "alloc-util.h" +#include "cgroup-util.h" +#include "dirent-util.h" +#include "extract-word.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" -#include "process-util.h" +#include "fs-util.h" +#include "login-util.h" +#include "macro.h" +#include "mkdir.h" +#include "parse-util.h" #include "path-util.h" -#include "unit-name.h" -#include "fileio.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "set.h" #include "special.h" -#include "mkdir.h" -#include "login-util.h" -#include "cgroup-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "unit-name.h" +#include "user-util.h" +#include "util.h" int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { _cleanup_free_ char *fs = NULL; diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c new file mode 100644 index 0000000000..d49ca0537a --- /dev/null +++ b/src/basic/chattr-util.c @@ -0,0 +1,107 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <linux/fs.h> + +#include "chattr-util.h" +#include "fd-util.h" +#include "util.h" + +int chattr_fd(int fd, unsigned value, unsigned mask) { + unsigned old_attr, new_attr; + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + /* Explicitly check whether this is a regular file or + * directory. If it is anything else (such as a device node or + * fifo), then the ioctl will not hit the file systems but + * possibly drivers, where the ioctl might have different + * effects. Notably, DRM is using the same ioctl() number. */ + + if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) + return -ENOTTY; + + if (mask == 0) + return 0; + + if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) + return -errno; + + new_attr = (old_attr & ~mask) | (value & mask); + if (new_attr == old_attr) + return 0; + + if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) + return -errno; + + return 1; +} + +int chattr_path(const char *p, unsigned value, unsigned mask) { + _cleanup_close_ int fd = -1; + + assert(p); + + if (mask == 0) + return 0; + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return chattr_fd(fd, value, mask); +} + +int read_attr_fd(int fd, unsigned *ret) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) + return -ENOTTY; + + if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) + return -errno; + + return 0; +} + +int read_attr_path(const char *p, unsigned *ret) { + _cleanup_close_ int fd = -1; + + assert(p); + assert(ret); + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return read_attr_fd(fd, ret); +} diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h new file mode 100644 index 0000000000..ba6b8eb5c1 --- /dev/null +++ b/src/basic/chattr-util.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +int chattr_fd(int fd, unsigned value, unsigned mask); +int chattr_path(const char *p, unsigned value, unsigned mask); + +int read_attr_fd(int fd, unsigned *ret); +int read_attr_path(const char *p, unsigned *ret); diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index e4e03df1e4..00ee4c2796 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -20,15 +20,17 @@ ***/ #include <errno.h> -#include <stdio.h> #include <fcntl.h> +#include <linux/rtc.h> +#include <stdio.h> #include <sys/ioctl.h> #include <sys/time.h> -#include <linux/rtc.h> +#include "clock-util.h" +#include "fd-util.h" #include "macro.h" +#include "string-util.h" #include "util.h" -#include "clock-util.h" int clock_get_hwclock(struct tm *tm) { _cleanup_close_ int fd = -1; diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index 8c2d235430..fef2d471a6 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -21,6 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <time.h> int clock_is_localtime(void); int clock_set_timezone(int *min); diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index da8745b284..be9972ffff 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -19,20 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> +#include <dirent.h> #include <errno.h> -#include <stdlib.h> #include <stdio.h> -#include <dirent.h> +#include <stdlib.h> +#include <string.h> +#include "conf-files.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "hashmap.h" +#include "log.h" #include "macro.h" -#include "util.h" #include "missing.h" -#include "log.h" -#include "strv.h" #include "path-util.h" -#include "hashmap.h" -#include "conf-files.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { _cleanup_closedir_ DIR *dir = NULL; diff --git a/src/basic/copy.c b/src/basic/copy.c index b20c178727..a187ae08fe 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -22,10 +22,20 @@ #include <sys/sendfile.h> #include <sys/xattr.h> -#include "util.h" +#include "alloc-util.h" #include "btrfs-util.h" -#include "strv.h" +#include "chattr-util.h" #include "copy.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "string-util.h" +#include "strv.h" +#include "umask-util.h" +#include "util.h" +#include "xattr-util.h" #define COPY_BUFFER_SIZE (16*1024) diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c index 519583c167..e2ec4ca83f 100644 --- a/src/basic/cpu-set-util.c +++ b/src/basic/cpu-set-util.c @@ -20,8 +20,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" #include "cpu-set-util.h" +#include "extract-word.h" +#include "parse-util.h" +#include "string-util.h" +#include "util.h" cpu_set_t* cpu_set_malloc(unsigned *ncpus) { cpu_set_t *c; @@ -69,14 +73,12 @@ int parse_cpu_set_and_warn( for (;;) { _cleanup_free_ char *word = NULL; - unsigned cpu; + unsigned cpu, cpu_lower, cpu_upper; int r; - r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); - return r; - } + r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); if (r == 0) break; @@ -86,13 +88,17 @@ int parse_cpu_set_and_warn( return log_oom(); } - r = safe_atou(word, &cpu); - if (r < 0 || cpu >= ncpus) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", rvalue); - return -EINVAL; - } - - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); + r = parse_range(word, &cpu_lower, &cpu_upper); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word); + if (cpu_lower >= ncpus || cpu_upper >= ncpus) + return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus); + + if (cpu_lower > cpu_upper) + log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper); + else + for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) + CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); } /* On success, sets *cpu_set and returns ncpus for the system. */ diff --git a/src/basic/def.h b/src/basic/def.h index 7c4161eb72..0657ac7367 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -35,17 +35,14 @@ * the watchdog pings will keep the loop busy. */ #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC) +/* The default value for the net.unix.max_dgram_qlen sysctl */ +#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL + #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT #define SIGNALS_IGNORE SIGPIPE -#define DIGITS "0123456789" -#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" -#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS -#define ALPHANUMERICAL LETTERS DIGITS - #define REBOOT_PARAM_FILE "/run/systemd/reboot-param" #ifdef HAVE_SPLIT_USR @@ -78,3 +75,20 @@ #define NOTIFY_FD_MAX 768 #define NOTIFY_BUFFER_MAX PIPE_BUF + +#ifdef HAVE_SPLIT_USR +#define _CONF_PATHS_SPLIT_USR(n) "/lib/" n "\0" +#else +#define _CONF_PATHS_SPLIT_USR(n) +#endif + +/* Return a nulstr for a standard cascade of configuration paths, + * suitable to pass to conf_files_list_nulstr() or config_parse_many() + * to implement drop-in directories for extending configuration + * files. */ +#define CONF_PATHS_NULSTR(n) \ + "/etc/" n "\0" \ + "/run/" n "\0" \ + "/usr/local/lib/" n "\0" \ + "/usr/lib/" n "\0" \ + _CONF_PATHS_SPLIT_USR(n) diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h index 04ba4897e5..7db81f3d52 100644 --- a/src/basic/device-nodes.h +++ b/src/basic/device-nodes.h @@ -21,5 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <sys/types.h> + int encode_devnode_name(const char *str, char *str_enc, size_t len); int whitelisted_char_for_devnode(char c, const char *additional); diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c new file mode 100644 index 0000000000..c433d5844a --- /dev/null +++ b/src/basic/dirent-util.c @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "dirent-util.h" +#include "string-util.h" + +int dirent_ensure_type(DIR *d, struct dirent *de) { + struct stat st; + + assert(d); + assert(de); + + if (de->d_type != DT_UNKNOWN) + return 0; + + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + return -errno; + + de->d_type = + S_ISREG(st.st_mode) ? DT_REG : + S_ISDIR(st.st_mode) ? DT_DIR : + S_ISLNK(st.st_mode) ? DT_LNK : + S_ISFIFO(st.st_mode) ? DT_FIFO : + S_ISSOCK(st.st_mode) ? DT_SOCK : + S_ISCHR(st.st_mode) ? DT_CHR : + S_ISBLK(st.st_mode) ? DT_BLK : + DT_UNKNOWN; + + return 0; +} + +bool dirent_is_file(const struct dirent *de) { + assert(de); + + if (hidden_file(de->d_name)) + return false; + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + return false; + + return true; +} + +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { + assert(de); + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + return false; + + if (hidden_file_allow_backup(de->d_name)) + return false; + + return endswith(de->d_name, suffix); +} diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h new file mode 100644 index 0000000000..5866a755f4 --- /dev/null +++ b/src/basic/dirent-util.h @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <dirent.h> + +#include "path-util.h" + +int dirent_ensure_type(DIR *d, struct dirent *de); + +bool dirent_is_file(const struct dirent *de) _pure_; +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; + +#define FOREACH_DIRENT(de, d, on_error) \ + for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ + if (!de) { \ + if (errno > 0) { \ + on_error; \ + } \ + break; \ + } else if (hidden_file((de)->d_name)) \ + continue; \ + else + +#define FOREACH_DIRENT_ALL(de, d, on_error) \ + for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ + if (!de) { \ + if (errno > 0) { \ + on_error; \ + } \ + break; \ + } else diff --git a/src/basic/env-util.c b/src/basic/env-util.c index ecb2192c4d..441169db31 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -22,11 +22,14 @@ #include <limits.h> #include <unistd.h> +#include "alloc-util.h" +#include "def.h" +#include "env-util.h" +#include "parse-util.h" +#include "string-util.h" #include "strv.h" #include "utf8.h" #include "util.h" -#include "env-util.h" -#include "def.h" #define VALID_CHARS_ENV_NAME \ DIGITS LETTERS \ @@ -135,6 +138,21 @@ bool strv_env_is_valid(char **e) { return true; } +bool strv_env_name_is_valid(char **l) { + char **p, **q; + + STRV_FOREACH(p, l) { + if (!env_name_is_valid(*p)) + return false; + + STRV_FOREACH(q, p + 1) + if (streq(*p, *q)) + return false; + } + + return true; +} + bool strv_env_name_or_assignment_is_valid(char **l) { char **p, **q; @@ -592,3 +610,13 @@ char **replace_env_argv(char **argv, char **env) { ret[k] = NULL; return ret; } + +int getenv_bool(const char *p) { + const char *e; + + e = getenv(p); + if (!e) + return -ENXIO; + + return parse_boolean(e); +} diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 803aa61cad..5efffa3dc7 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -36,6 +36,7 @@ bool strv_env_is_valid(char **e); #define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL) char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata); +bool strv_env_name_is_valid(char **l); bool strv_env_name_or_assignment_is_valid(char **l); char **strv_env_merge(unsigned n_lists, ...); @@ -47,3 +48,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_; char *strv_env_get_n(char **l, const char *name, size_t k) _pure_; char *strv_env_get(char **x, const char *n) _pure_; + +int getenv_bool(const char *p); diff --git a/src/basic/escape.c b/src/basic/escape.c new file mode 100644 index 0000000000..4815161b09 --- /dev/null +++ b/src/basic/escape.c @@ -0,0 +1,482 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "hexdecoct.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" + +size_t cescape_char(char c, char *buf) { + char * buf_old = buf; + + switch (c) { + + case '\a': + *(buf++) = '\\'; + *(buf++) = 'a'; + break; + case '\b': + *(buf++) = '\\'; + *(buf++) = 'b'; + break; + case '\f': + *(buf++) = '\\'; + *(buf++) = 'f'; + break; + case '\n': + *(buf++) = '\\'; + *(buf++) = 'n'; + break; + case '\r': + *(buf++) = '\\'; + *(buf++) = 'r'; + break; + case '\t': + *(buf++) = '\\'; + *(buf++) = 't'; + break; + case '\v': + *(buf++) = '\\'; + *(buf++) = 'v'; + break; + case '\\': + *(buf++) = '\\'; + *(buf++) = '\\'; + break; + case '"': + *(buf++) = '\\'; + *(buf++) = '"'; + break; + case '\'': + *(buf++) = '\\'; + *(buf++) = '\''; + break; + + default: + /* For special chars we prefer octal over + * hexadecimal encoding, simply because glib's + * g_strescape() does the same */ + if ((c < ' ') || (c >= 127)) { + *(buf++) = '\\'; + *(buf++) = octchar((unsigned char) c >> 6); + *(buf++) = octchar((unsigned char) c >> 3); + *(buf++) = octchar((unsigned char) c); + } else + *(buf++) = c; + break; + } + + return buf - buf_old; +} + +char *cescape(const char *s) { + char *r, *t; + const char *f; + + assert(s); + + /* Does C style string escaping. May be reversed with + * cunescape(). */ + + r = new(char, strlen(s)*4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) + t += cescape_char(*f, t); + + *t = 0; + + return r; +} + +int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { + int r = 1; + + assert(p); + assert(*p); + assert(ret); + + /* Unescapes C style. Returns the unescaped character in ret, + * unless we encountered a \u sequence in which case the full + * unicode character is returned in ret_unicode, instead. */ + + if (length != (size_t) -1 && length < 1) + return -EINVAL; + + switch (p[0]) { + + case 'a': + *ret = '\a'; + break; + case 'b': + *ret = '\b'; + break; + case 'f': + *ret = '\f'; + break; + case 'n': + *ret = '\n'; + break; + case 'r': + *ret = '\r'; + break; + case 't': + *ret = '\t'; + break; + case 'v': + *ret = '\v'; + break; + case '\\': + *ret = '\\'; + break; + case '"': + *ret = '"'; + break; + case '\'': + *ret = '\''; + break; + + case 's': + /* This is an extension of the XDG syntax files */ + *ret = ' '; + break; + + case 'x': { + /* hexadecimal encoding */ + int a, b; + + if (length != (size_t) -1 && length < 3) + return -EINVAL; + + a = unhexchar(p[1]); + if (a < 0) + return -EINVAL; + + b = unhexchar(p[2]); + if (b < 0) + return -EINVAL; + + /* Don't allow NUL bytes */ + if (a == 0 && b == 0) + return -EINVAL; + + *ret = (char) ((a << 4U) | b); + r = 3; + break; + } + + case 'u': { + /* C++11 style 16bit unicode */ + + int a[4]; + unsigned i; + uint32_t c; + + if (length != (size_t) -1 && length < 5) + return -EINVAL; + + for (i = 0; i < 4; i++) { + a[i] = unhexchar(p[1 + i]); + if (a[i] < 0) + return a[i]; + } + + c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; + + /* Don't allow 0 chars */ + if (c == 0) + return -EINVAL; + + if (c < 128) + *ret = c; + else { + if (!ret_unicode) + return -EINVAL; + + *ret = 0; + *ret_unicode = c; + } + + r = 5; + break; + } + + case 'U': { + /* C++11 style 32bit unicode */ + + int a[8]; + unsigned i; + uint32_t c; + + if (length != (size_t) -1 && length < 9) + return -EINVAL; + + for (i = 0; i < 8; i++) { + a[i] = unhexchar(p[1 + i]); + if (a[i] < 0) + return a[i]; + } + + c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | + ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; + + /* Don't allow 0 chars */ + if (c == 0) + return -EINVAL; + + /* Don't allow invalid code points */ + if (!unichar_is_valid(c)) + return -EINVAL; + + if (c < 128) + *ret = c; + else { + if (!ret_unicode) + return -EINVAL; + + *ret = 0; + *ret_unicode = c; + } + + r = 9; + break; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + /* octal encoding */ + int a, b, c; + uint32_t m; + + if (length != (size_t) -1 && length < 3) + return -EINVAL; + + a = unoctchar(p[0]); + if (a < 0) + return -EINVAL; + + b = unoctchar(p[1]); + if (b < 0) + return -EINVAL; + + c = unoctchar(p[2]); + if (c < 0) + return -EINVAL; + + /* don't allow NUL bytes */ + if (a == 0 && b == 0 && c == 0) + return -EINVAL; + + /* Don't allow bytes above 255 */ + m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; + if (m > 255) + return -EINVAL; + + *ret = m; + r = 3; + break; + } + + default: + return -EINVAL; + } + + return r; +} + +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) { + char *r, *t; + const char *f; + size_t pl; + + assert(s); + assert(ret); + + /* Undoes C style string escaping, and optionally prefixes it. */ + + pl = prefix ? strlen(prefix) : 0; + + r = new(char, pl+length+1); + if (!r) + return -ENOMEM; + + if (prefix) + memcpy(r, prefix, pl); + + for (f = s, t = r + pl; f < s + length; f++) { + size_t remaining; + uint32_t u; + char c; + int k; + + remaining = s + length - f; + assert(remaining > 0); + + if (*f != '\\') { + /* A literal literal, copy verbatim */ + *(t++) = *f; + continue; + } + + if (remaining == 1) { + if (flags & UNESCAPE_RELAX) { + /* A trailing backslash, copy verbatim */ + *(t++) = *f; + continue; + } + + free(r); + return -EINVAL; + } + + k = cunescape_one(f + 1, remaining - 1, &c, &u); + if (k < 0) { + if (flags & UNESCAPE_RELAX) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + continue; + } + + free(r); + return k; + } + + if (c != 0) + /* Non-Unicode? Let's encode this directly */ + *(t++) = c; + else + /* Unicode? Then let's encode this in UTF-8 */ + t += utf8_encode_unichar(t, u); + + f += k; + } + + *t = 0; + + *ret = r; + return t - r; +} + +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { + return cunescape_length_with_prefix(s, length, NULL, flags, ret); +} + +int cunescape(const char *s, UnescapeFlags flags, char **ret) { + return cunescape_length(s, strlen(s), flags, ret); +} + +char *xescape(const char *s, const char *bad) { + char *r, *t; + const char *f; + + /* Escapes all chars in bad, in addition to \ and all special + * chars, in \xFF style escaping. May be reversed with + * cunescape(). */ + + r = new(char, strlen(s) * 4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) { + + if ((*f < ' ') || (*f >= 127) || + (*f == '\\') || strchr(bad, *f)) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = hexchar(*f >> 4); + *(t++) = hexchar(*f); + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} + +static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { + assert(bad); + + for (; *s; s++) { + if (*s == '\\' || strchr(bad, *s)) + *(t++) = '\\'; + + *(t++) = *s; + } + + return t; +} + +char *shell_escape(const char *s, const char *bad) { + char *r, *t; + + r = new(char, strlen(s)*2+1); + if (!r) + return NULL; + + t = strcpy_backslash_escaped(r, s, bad); + *t = 0; + + return r; +} + +char *shell_maybe_quote(const char *s) { + const char *p; + char *r, *t; + + assert(s); + + /* Encloses a string in double quotes if necessary to make it + * OK as shell string. */ + + for (p = s; *p; p++) + if (*p <= ' ' || + *p >= 127 || + strchr(SHELL_NEED_QUOTES, *p)) + break; + + if (!*p) + return strdup(s); + + r = new(char, 1+strlen(s)*2+1+1); + if (!r) + return NULL; + + t = r; + *(t++) = '"'; + t = mempcpy(t, s, p - s); + + t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); + + *(t++)= '"'; + *t = 0; + + return r; +} diff --git a/src/basic/escape.h b/src/basic/escape.h new file mode 100644 index 0000000000..85ba909081 --- /dev/null +++ b/src/basic/escape.h @@ -0,0 +1,48 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/types.h> +#include <inttypes.h> + +/* What characters are special in the shell? */ +/* must be escaped outside and inside double-quotes */ +#define SHELL_NEED_ESCAPE "\"\\`$" +/* can be escaped or double-quoted */ +#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;" + +typedef enum UnescapeFlags { + UNESCAPE_RELAX = 1, +} UnescapeFlags; + +char *cescape(const char *s); +size_t cescape_char(char c, char *buf); + +int cunescape(const char *s, UnescapeFlags flags, char **ret); +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); +int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode); + +char *xescape(const char *s, const char *bad); + +char *shell_escape(const char *s, const char *bad); +char *shell_maybe_quote(const char *s); diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c new file mode 100644 index 0000000000..2bf3bfec1d --- /dev/null +++ b/src/basic/ether-addr-util.c @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdio.h> + +#include "ether-addr-util.h" +#include "macro.h" + +char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { + assert(addr); + assert(buffer); + + /* Like ether_ntoa() but uses %02x instead of %x to print + * ethernet addresses, which makes them look less funny. Also, + * doesn't use a static buffer. */ + + sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", + addr->ether_addr_octet[0], + addr->ether_addr_octet[1], + addr->ether_addr_octet[2], + addr->ether_addr_octet[3], + addr->ether_addr_octet[4], + addr->ether_addr_octet[5]); + + return buffer; +} diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 7033138788..008f3b893e 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -25,3 +25,7 @@ #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] + +#define ETHER_ADDR_TO_STRING_MAX (3*6) + +char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c new file mode 100644 index 0000000000..fd495692fa --- /dev/null +++ b/src/basic/extract-word.c @@ -0,0 +1,289 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "extract-word.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" + +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { + _cleanup_free_ char *s = NULL; + size_t allocated = 0, sz = 0; + char c; + int r; + + char quote = 0; /* 0 or ' or " */ + bool backslash = false; /* whether we've just seen a backslash */ + + assert(p); + assert(ret); + + /* Bail early if called after last value or with no input */ + if (!*p) + goto finish_force_terminate; + c = **p; + + if (!separators) + separators = WHITESPACE; + + /* Parses the first word of a string, and returns it in + * *ret. Removes all quotes in the process. When parsing fails + * (because of an uneven number of quotes or similar), leaves + * the pointer *p at the first invalid character. */ + + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + + for (;; (*p) ++, c = **p) { + if (c == 0) + goto finish_force_terminate; + else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } + } else { + /* We found a non-blank character, so we will always + * want to return a string (even if it is empty), + * allocate it here. */ + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + break; + } + } + + for (;; (*p) ++, c = **p) { + if (backslash) { + if (!GREEDY_REALLOC(s, allocated, sz+7)) + return -ENOMEM; + + if (c == 0) { + if ((flags & EXTRACT_CUNESCAPE_RELAX) && + (!quote || flags & EXTRACT_RELAX)) { + /* If we find an unquoted trailing backslash and we're in + * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the + * output. + * + * Unbalanced quotes will only be allowed in EXTRACT_RELAX + * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. + */ + s[sz++] = '\\'; + goto finish_force_terminate; + } + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; + return -EINVAL; + } + + if (flags & EXTRACT_CUNESCAPE) { + uint32_t u; + + r = cunescape_one(*p, (size_t) -1, &c, &u); + if (r < 0) { + if (flags & EXTRACT_CUNESCAPE_RELAX) { + s[sz++] = '\\'; + s[sz++] = c; + } else + return -EINVAL; + } else { + (*p) += r - 1; + + if (c != 0) + s[sz++] = c; /* normal explicit char */ + else + sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ + } + } else + s[sz++] = c; + + backslash = false; + + } else if (quote) { /* inside either single or double quotes */ + for (;; (*p) ++, c = **p) { + if (c == 0) { + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; + return -EINVAL; + } else if (c == quote) { /* found the end quote */ + quote = 0; + break; + } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { + backslash = true; + break; + } else { + if (!GREEDY_REALLOC(s, allocated, sz+2)) + return -ENOMEM; + + s[sz++] = c; + } + } + + } else { + for (;; (*p) ++, c = **p) { + if (c == 0) + goto finish_force_terminate; + else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) { + quote = c; + break; + } else if (c == '\\' && !(flags & EXTRACT_RETAIN_ESCAPE)) { + backslash = true; + break; + } else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } + /* Skip additional coalesced separators. */ + for (;; (*p) ++, c = **p) { + if (c == 0) + goto finish_force_terminate; + if (!strchr(separators, c)) + break; + } + goto finish; + + } else { + if (!GREEDY_REALLOC(s, allocated, sz+2)) + return -ENOMEM; + + s[sz++] = c; + } + } + } + } + +finish_force_terminate: + *p = NULL; +finish: + if (!s) { + *p = NULL; + *ret = NULL; + return 0; + } + +finish_force_next: + s[sz] = 0; + *ret = s; + s = NULL; + + return 1; +} + +int extract_first_word_and_warn( + const char **p, + char **ret, + const char *separators, + ExtractFlags flags, + const char *unit, + const char *filename, + unsigned line, + const char *rvalue) { + + /* Try to unquote it, if it fails, warn about it and try again + * but this time using EXTRACT_CUNESCAPE_RELAX to keep the + * backslashes verbatim in invalid escape sequences. */ + + const char *save; + int r; + + save = *p; + r = extract_first_word(p, ret, separators, flags); + if (r >= 0) + return r; + + if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) { + + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ + *p = save; + r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); + if (r >= 0) { + /* It worked this time, hence it must have been an invalid escape sequence we could correct. */ + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue); + return r; + } + + /* If it's still EINVAL; then it must be unbalanced quoting, report this. */ + if (r == -EINVAL) + return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue); + } + + /* Can be any error, report it */ + return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue); +} + +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { + va_list ap; + char **l; + int n = 0, i, c, r; + + /* Parses a number of words from a string, stripping any + * quotes if necessary. */ + + assert(p); + + /* Count how many words are expected */ + va_start(ap, flags); + for (;;) { + if (!va_arg(ap, char **)) + break; + n++; + } + va_end(ap); + + if (n <= 0) + return 0; + + /* Read all words into a temporary array */ + l = newa0(char*, n); + for (c = 0; c < n; c++) { + + r = extract_first_word(p, &l[c], separators, flags); + if (r < 0) { + int j; + + for (j = 0; j < c; j++) + free(l[j]); + + return r; + } + + if (r == 0) + break; + } + + /* If we managed to parse all words, return them in the passed + * in parameters */ + va_start(ap, flags); + for (i = 0; i < n; i++) { + char **v; + + v = va_arg(ap, char **); + assert(v); + + *v = l[i]; + } + va_end(ap); + + return c; +} diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h new file mode 100644 index 0000000000..9606ab64b3 --- /dev/null +++ b/src/basic/extract-word.h @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "macro.h" + +typedef enum ExtractFlags { + EXTRACT_RELAX = 1, + EXTRACT_CUNESCAPE = 2, + EXTRACT_CUNESCAPE_RELAX = 4, + EXTRACT_QUOTES = 8, + EXTRACT_DONT_COALESCE_SEPARATORS = 16, + EXTRACT_RETAIN_ESCAPE = 32, +} ExtractFlags; + +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); +int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c new file mode 100644 index 0000000000..d1b1db3a4d --- /dev/null +++ b/src/basic/fd-util.c @@ -0,0 +1,351 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "dirent-util.h" +#include "fd-util.h" +#include "parse-util.h" +#include "socket-util.h" +#include "util.h" + +int close_nointr(int fd) { + assert(fd >= 0); + + if (close(fd) >= 0) + return 0; + + /* + * Just ignore EINTR; a retry loop is the wrong thing to do on + * Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (errno == EINTR) + return 0; + + return -errno; +} + +int safe_close(int fd) { + + /* + * Like close_nointr() but cannot fail. Guarantees errno is + * unchanged. Is a NOP with negative fds passed, and returns + * -1, so that it can be used in this syntax: + * + * fd = safe_close(fd); + */ + + if (fd >= 0) { + PROTECT_ERRNO; + + /* The kernel might return pretty much any error code + * via close(), but the fd will be closed anyway. The + * only condition we want to check for here is whether + * the fd was invalid at all... */ + + assert_se(close_nointr(fd) != -EBADF); + } + + return -1; +} + +void safe_close_pair(int p[]) { + assert(p); + + if (p[0] == p[1]) { + /* Special case pairs which use the same fd in both + * directions... */ + p[0] = p[1] = safe_close(p[0]); + return; + } + + p[0] = safe_close(p[0]); + p[1] = safe_close(p[1]); +} + +void close_many(const int fds[], unsigned n_fd) { + unsigned i; + + assert(fds || n_fd <= 0); + + for (i = 0; i < n_fd; i++) + safe_close(fds[i]); +} + +int fclose_nointr(FILE *f) { + assert(f); + + /* Same as close_nointr(), but for fclose() */ + + if (fclose(f) == 0) + return 0; + + if (errno == EINTR) + return 0; + + return -errno; +} + +FILE* safe_fclose(FILE *f) { + + /* Same as safe_close(), but for fclose() */ + + if (f) { + PROTECT_ERRNO; + + assert_se(fclose_nointr(f) != EBADF); + } + + return NULL; +} + +DIR* safe_closedir(DIR *d) { + + if (d) { + PROTECT_ERRNO; + + assert_se(closedir(d) >= 0 || errno != EBADF); + } + + return NULL; +} + +int fd_nonblock(int fd, bool nonblock) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) + return -errno; + + if (nonblock) + nflags = flags | O_NONBLOCK; + else + nflags = flags & ~O_NONBLOCK; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFL, nflags) < 0) + return -errno; + + return 0; +} + +int fd_cloexec(int fd, bool cloexec) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFD, 0); + if (flags < 0) + return -errno; + + if (cloexec) + nflags = flags | FD_CLOEXEC; + else + nflags = flags & ~FD_CLOEXEC; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFD, nflags) < 0) + return -errno; + + return 0; +} + +_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { + unsigned i; + + assert(n_fdset == 0 || fdset); + + for (i = 0; i < n_fdset; i++) + if (fdset[i] == fd) + return true; + + return false; +} + +int close_all_fds(const int except[], unsigned n_except) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(n_except == 0 || except); + + d = opendir("/proc/self/fd"); + if (!d) { + int fd; + struct rlimit rl; + + /* When /proc isn't available (for example in chroots) + * the fallback is brute forcing through the fd + * table */ + + assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); + for (fd = 3; fd < (int) rl.rlim_max; fd ++) { + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) + if (errno != EBADF && r == 0) + r = -errno; + } + + return r; + } + + while ((de = readdir(d))) { + int fd = -1; + + if (hidden_file(de->d_name)) + continue; + + if (safe_atoi(de->d_name, &fd) < 0) + /* Let's better ignore this, just in case */ + continue; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) { + /* Valgrind has its own FD and doesn't want to have it closed */ + if (errno != EBADF && r == 0) + r = -errno; + } + } + + return r; +} + +int same_fd(int a, int b) { + struct stat sta, stb; + pid_t pid; + int r, fa, fb; + + assert(a >= 0); + assert(b >= 0); + + /* Compares two file descriptors. Note that semantics are + * quite different depending on whether we have kcmp() or we + * don't. If we have kcmp() this will only return true for + * dup()ed file descriptors, but not otherwise. If we don't + * have kcmp() this will also return true for two fds of the same + * file, created by separate open() calls. Since we use this + * call mostly for filtering out duplicates in the fd store + * this difference hopefully doesn't matter too much. */ + + if (a == b) + return true; + + /* Try to use kcmp() if we have it. */ + pid = getpid(); + r = kcmp(pid, pid, KCMP_FILE, a, b); + if (r == 0) + return true; + if (r > 0) + return false; + if (errno != ENOSYS) + return -errno; + + /* We don't have kcmp(), use fstat() instead. */ + if (fstat(a, &sta) < 0) + return -errno; + + if (fstat(b, &stb) < 0) + return -errno; + + if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) + return false; + + /* We consider all device fds different, since two device fds + * might refer to quite different device contexts even though + * they share the same inode and backing dev_t. */ + + if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) + return false; + + if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) + return false; + + /* The fds refer to the same inode on disk, let's also check + * if they have the same fd flags. This is useful to + * distinguish the read and write side of a pipe created with + * pipe(). */ + fa = fcntl(a, F_GETFL); + if (fa < 0) + return -errno; + + fb = fcntl(b, F_GETFL); + if (fb < 0) + return -errno; + + return fa == fb; +} + +void cmsg_close_all(struct msghdr *mh) { + struct cmsghdr *cmsg; + + assert(mh); + + CMSG_FOREACH(cmsg, mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) + close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); +} + +bool fdname_is_valid(const char *s) { + const char *p; + + /* Validates a name for $LISTEN_FDNAMES. We basically allow + * everything ASCII that's not a control character. Also, as + * special exception the ":" character is not allowed, as we + * use that as field separator in $LISTEN_FDNAMES. + * + * Note that the empty string is explicitly allowed + * here. However, we limit the length of the names to 255 + * characters. */ + + if (!s) + return false; + + for (p = s; *p; p++) { + if (*p < ' ') + return false; + if (*p >= 127) + return false; + if (*p == ':') + return false; + } + + return p - s < 256; +} diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h new file mode 100644 index 0000000000..1ca10f0383 --- /dev/null +++ b/src/basic/fd-util.h @@ -0,0 +1,71 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdio.h> +#include <dirent.h> +#include <stdbool.h> +#include <sys/socket.h> + +#include "macro.h" + +int close_nointr(int fd); +int safe_close(int fd); +void safe_close_pair(int p[]); + +void close_many(const int fds[], unsigned n_fd); + +int fclose_nointr(FILE *f); +FILE* safe_fclose(FILE *f); +DIR* safe_closedir(DIR *f); + +static inline void closep(int *fd) { + safe_close(*fd); +} + +static inline void close_pairp(int (*p)[2]) { + safe_close_pair(*p); +} + +static inline void fclosep(FILE **f) { + safe_fclose(*f); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); + +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_pclose_ _cleanup_(pclosep) +#define _cleanup_closedir_ _cleanup_(closedirp) +#define _cleanup_close_pair_ _cleanup_(close_pairp) + +int fd_nonblock(int fd, bool nonblock); +int fd_cloexec(int fd, bool cloexec); + +int close_all_fds(const int except[], unsigned n_except); + +int same_fd(int a, int b); + +void cmsg_close_all(struct msghdr *mh); + +bool fdname_is_valid(const char *s); diff --git a/src/basic/fdset.c b/src/basic/fdset.c index d70fe156a2..42b0b2b98f 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -23,11 +23,15 @@ #include <dirent.h> #include <fcntl.h> +#include "sd-daemon.h" + +#include "dirent-util.h" +#include "fd-util.h" +#include "fdset.h" +#include "macro.h" +#include "parse-util.h" #include "set.h" #include "util.h" -#include "macro.h" -#include "fdset.h" -#include "sd-daemon.h" #define MAKE_SET(s) ((Set*) s) #define MAKE_FDSET(s) ((FDSet*) s) @@ -40,7 +44,7 @@ FDSet *fdset_new(void) { return MAKE_FDSET(set_new(NULL)); } -int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds) { +int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) { unsigned i; FDSet *s; int r; diff --git a/src/basic/fdset.h b/src/basic/fdset.h index 340438d7c4..70d8acbcff 100644 --- a/src/basic/fdset.h +++ b/src/basic/fdset.h @@ -35,7 +35,7 @@ int fdset_consume(FDSet *s, int fd); bool fdset_contains(FDSet *s, int fd); int fdset_remove(FDSet *s, int fd); -int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds); +int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds); int fdset_new_fill(FDSet **ret); int fdset_new_listen_fds(FDSet **ret, bool unset); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 13a85e1158..10aacdc56d 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -21,11 +21,22 @@ #include <unistd.h> -#include "util.h" -#include "strv.h" -#include "utf8.h" +#include "alloc-util.h" #include "ctype.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "path-util.h" +#include "random-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" +#include "umask-util.h" +#include "utf8.h" +#include "util.h" int write_string_stream(FILE *f, const char *line, bool enforce_newline) { @@ -51,7 +62,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor if (r < 0) return r; - fchmod_umask(fileno(f), 0644); + (void) fchmod_umask(fileno(f), 0644); r = write_string_stream(f, line, enforce_newline); if (r >= 0) { @@ -60,13 +71,14 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor } if (r < 0) - unlink(p); + (void) unlink(p); return r; } int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { _cleanup_fclose_ FILE *f = NULL; + int q, r; assert(fn); assert(line); @@ -74,30 +86,58 @@ int write_string_file(const char *fn, const char *line, WriteStringFileFlags fla if (flags & WRITE_STRING_FILE_ATOMIC) { assert(flags & WRITE_STRING_FILE_CREATE); - return write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + if (r < 0) + goto fail; + + return r; } if (flags & WRITE_STRING_FILE_CREATE) { f = fopen(fn, "we"); - if (!f) - return -errno; + if (!f) { + r = -errno; + goto fail; + } } else { int fd; /* We manually build our own version of fopen(..., "we") that * works without O_CREAT */ fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; + if (fd < 0) { + r = -errno; + goto fail; + } f = fdopen(fd, "we"); if (!f) { + r = -errno; safe_close(fd); - return -errno; + goto fail; } } - return write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + if (r < 0) + goto fail; + + return 0; + +fail: + if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE)) + return r; + + f = safe_fclose(f); + + /* OK, the operation failed, but let's see if the right + * contents in place already. If so, eat up the error. */ + + q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + if (q <= 0) + return r; + + return 0; } int read_one_line_file(const char *fn, char **line) { @@ -128,15 +168,41 @@ int read_one_line_file(const char *fn, char **line) { return 0; } -int verify_one_line_file(const char *fn, const char *line) { - _cleanup_free_ char *value = NULL; - int r; +int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *buf = NULL; + size_t l, k; - r = read_one_line_file(fn, &value); - if (r < 0) - return r; + assert(fn); + assert(blob); + + l = strlen(blob); + + if (accept_extra_nl && endswith(blob, "\n")) + accept_extra_nl = false; + + buf = malloc(l + accept_extra_nl + 1); + if (!buf) + return -ENOMEM; - return streq(value, line); + f = fopen(fn, "re"); + if (!f) + return -errno; + + /* We try to read one byte more than we need, so that we know whether we hit eof */ + errno = 0; + k = fread(buf, 1, l + accept_extra_nl + 1, f); + if (ferror(f)) + return errno > 0 ? -errno : -EIO; + + if (k != l && k != l + accept_extra_nl) + return 0; + if (memcmp(buf, blob, l) != 0) + return 0; + if (k > l && buf[l] != '\n') + return 0; + + return 1; } int read_full_stream(FILE *f, char **contents, size_t *size) { @@ -845,3 +911,332 @@ int get_proc_field(const char *filename, const char *pattern, const char *termin *field = f; return 0; } + +DIR *xopendirat(int fd, const char *name, int flags) { + int nfd; + DIR *d; + + assert(!(flags & O_CREAT)); + + nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); + if (nfd < 0) + return NULL; + + d = fdopendir(nfd); + if (!d) { + safe_close(nfd); + return NULL; + } + + return d; +} + +static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) { + char **i; + + assert(path); + assert(mode); + assert(_f); + + if (!path_strv_resolve_uniq(search, root)) + return -ENOMEM; + + STRV_FOREACH(i, search) { + _cleanup_free_ char *p = NULL; + FILE *f; + + if (root) + p = strjoin(root, *i, "/", path, NULL); + else + p = strjoin(*i, "/", path, NULL); + if (!p) + return -ENOMEM; + + f = fopen(p, mode); + if (f) { + *_f = f; + return 0; + } + + if (errno != ENOENT) + return -errno; + } + + return -ENOENT; +} + +int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) { + _cleanup_strv_free_ char **copy = NULL; + + assert(path); + assert(mode); + assert(_f); + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + copy = strv_copy((char**) search); + if (!copy) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, root, copy, _f); +} + +int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) { + _cleanup_strv_free_ char **s = NULL; + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + s = strv_split_nulstr(search); + if (!s) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, root, s, _f); +} + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { + FILE *f; + char *t; + int r, fd; + + assert(path); + assert(_f); + assert(_temp_path); + + r = tempfn_xxxxxx(path, NULL, &t); + if (r < 0) + return r; + + fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + free(t); + return -errno; + } + + f = fdopen(fd, "we"); + if (!f) { + unlink_noerrno(t); + free(t); + safe_close(fd); + return -errno; + } + + *_f = f; + *_temp_path = t; + + return 0; +} + +int fflush_and_check(FILE *f) { + assert(f); + + errno = 0; + fflush(f); + + if (ferror(f)) + return errno ? -errno : -EIO; + + return 0; +} + +/* This is much like like mkostemp() but is subject to umask(). */ +int mkostemp_safe(char *pattern, int flags) { + _cleanup_umask_ mode_t u; + int fd; + + assert(pattern); + + u = umask(077); + + fd = mkostemp(pattern, flags); + if (fd < 0) + return -errno; + + return fd; +} + +int open_tmpfile(const char *path, int flags) { + char *p; + int fd; + + assert(path); + +#ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ + fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + + /* Fall back to unguessable name + unlinking */ + p = strjoina(path, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, flags); + if (fd < 0) + return fd; + + unlink(p); + return fd; +} + +int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { + const char *fn; + char *t; + + assert(p); + assert(ret); + + /* + * Turns this: + * /foo/bar/waldo + * + * Into this: + * /foo/bar/.#<extra>waldoXXXXXX + */ + + fn = basename(p); + if (!filename_is_valid(fn)) + return -EINVAL; + + if (extra == NULL) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); + if (!t) + return -ENOMEM; + + strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); + + *ret = path_kill_slashes(t); + return 0; +} + +int tempfn_random(const char *p, const char *extra, char **ret) { + const char *fn; + char *t, *x; + uint64_t u; + unsigned i; + + assert(p); + assert(ret); + + /* + * Turns this: + * /foo/bar/waldo + * + * Into this: + * /foo/bar/.#<extra>waldobaa2a261115984a9 + */ + + fn = basename(p); + if (!filename_is_valid(fn)) + return -EINVAL; + + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); + if (!t) + return -ENOMEM; + + x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn); + + u = random_u64(); + for (i = 0; i < 16; i++) { + *(x++) = hexchar(u & 0xF); + u >>= 4; + } + + *x = 0; + + *ret = path_kill_slashes(t); + return 0; +} + +int tempfn_random_child(const char *p, const char *extra, char **ret) { + char *t, *x; + uint64_t u; + unsigned i; + + assert(p); + assert(ret); + + /* Turns this: + * /foo/bar/waldo + * Into this: + * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0 + */ + + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1); + if (!t) + return -ENOMEM; + + x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); + + u = random_u64(); + for (i = 0; i < 16; i++) { + *(x++) = hexchar(u & 0xF); + u >>= 4; + } + + *x = 0; + + *ret = path_kill_slashes(t); + return 0; +} + +int write_timestamp_file_atomic(const char *fn, usec_t n) { + char ln[DECIMAL_STR_MAX(n)+2]; + + /* Creates a "timestamp" file, that contains nothing but a + * usec_t timestamp, formatted in ASCII. */ + + if (n <= 0 || n >= USEC_INFINITY) + return -ERANGE; + + xsprintf(ln, USEC_FMT "\n", n); + + return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); +} + +int read_timestamp_file(const char *fn, usec_t *ret) { + _cleanup_free_ char *ln = NULL; + uint64_t t; + int r; + + r = read_one_line_file(fn, &ln); + if (r < 0) + return r; + + r = safe_atou64(ln, &t); + if (r < 0) + return r; + + if (t <= 0 || t >= (uint64_t) USEC_INFINITY) + return -ERANGE; + + *ret = (usec_t) t; + return 0; +} diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 4998d4d042..95e8698941 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -20,15 +20,21 @@ You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ + +#include <dirent.h> +#include <stdbool.h> #include <stddef.h> #include <stdio.h> +#include <sys/types.h> #include "macro.h" +#include "time-util.h" typedef enum { WRITE_STRING_FILE_CREATE = 1, WRITE_STRING_FILE_ATOMIC = 2, WRITE_STRING_FILE_AVOID_NEWLINE = 4, + WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8, } WriteStringFileFlags; int write_string_stream(FILE *f, const char *line, bool enforce_newline); @@ -38,7 +44,7 @@ int read_one_line_file(const char *fn, char **line); int read_full_file(const char *fn, char **contents, size_t *size); int read_full_stream(FILE *f, char **contents, size_t *size); -int verify_one_line_file(const char *fn, const char *line); +int verify_file(const char *fn, const char *blob, bool accept_extra_nl); int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); @@ -49,3 +55,30 @@ int write_env_file(const char *fname, char **l); int executable_is_script(const char *path, char **interpreter); int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); + +DIR *xopendirat(int dirfd, const char *name, int flags); + +int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); +int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); + +#define FOREACH_LINE(line, f, on_error) \ + for (;;) \ + if (!fgets(line, sizeof(line), f)) { \ + if (ferror(f)) { \ + on_error; \ + } \ + break; \ + } else + +int fflush_and_check(FILE *f); + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path); +int mkostemp_safe(char *pattern, int flags); +int open_tmpfile(const char *path, int flags); + +int tempfn_xxxxxx(const char *p, const char *extra, char **ret); +int tempfn_random(const char *p, const char *extra, char **ret); +int tempfn_random_child(const char *p, const char *extra, char **ret); + +int write_timestamp_file_atomic(const char *fn, usec_t n); +int read_timestamp_file(const char *fn, usec_t *ret); diff --git a/src/shared/formats-util.h b/src/basic/formats-util.h index ce516b117d..ce516b117d 100644 --- a/src/shared/formats-util.h +++ b/src/basic/formats-util.h diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c new file mode 100644 index 0000000000..2b6189ad90 --- /dev/null +++ b/src/basic/fs-util.c @@ -0,0 +1,500 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" + +int unlink_noerrno(const char *path) { + PROTECT_ERRNO; + int r; + + r = unlink(path); + if (r < 0) + return -errno; + + return 0; +} + +int rmdir_parents(const char *path, const char *stop) { + size_t l; + int r = 0; + + assert(path); + assert(stop); + + l = strlen(path); + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + while (l > 0) { + char *t; + + /* Skip last component */ + while (l > 0 && path[l-1] != '/') + l--; + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + if (l <= 0) + break; + + t = strndup(path, l); + if (!t) + return -ENOMEM; + + if (path_startswith(stop, t)) { + free(t); + return 0; + } + + r = rmdir(t); + free(t); + + if (r < 0) + if (errno != ENOENT) + return -errno; + } + + return 0; +} + + +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { + struct stat buf; + int ret; + + ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE); + if (ret >= 0) + return 0; + + /* renameat2() exists since Linux 3.15, btrfs added support for it later. + * If it is not implemented, fallback to another method. */ + if (!IN_SET(errno, EINVAL, ENOSYS)) + return -errno; + + /* The link()/unlink() fallback does not work on directories. But + * renameat() without RENAME_NOREPLACE gives the same semantics on + * directories, except when newpath is an *empty* directory. This is + * good enough. */ + ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW); + if (ret >= 0 && S_ISDIR(buf.st_mode)) { + ret = renameat(olddirfd, oldpath, newdirfd, newpath); + return ret >= 0 ? 0 : -errno; + } + + /* If it is not a directory, use the link()/unlink() fallback. */ + ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0); + if (ret < 0) + return -errno; + + ret = unlinkat(olddirfd, oldpath, 0); + if (ret < 0) { + /* backup errno before the following unlinkat() alters it */ + ret = errno; + (void) unlinkat(newdirfd, newpath, 0); + errno = ret; + return -errno; + } + + return 0; +} + +int readlinkat_malloc(int fd, const char *p, char **ret) { + size_t l = 100; + int r; + + assert(p); + assert(ret); + + for (;;) { + char *c; + ssize_t n; + + c = new(char, l); + if (!c) + return -ENOMEM; + + n = readlinkat(fd, p, c, l-1); + if (n < 0) { + r = -errno; + free(c); + return r; + } + + if ((size_t) n < l-1) { + c[n] = 0; + *ret = c; + return 0; + } + + free(c); + l *= 2; + } +} + +int readlink_malloc(const char *p, char **ret) { + return readlinkat_malloc(AT_FDCWD, p, ret); +} + +int readlink_value(const char *p, char **ret) { + _cleanup_free_ char *link = NULL; + char *value; + int r; + + r = readlink_malloc(p, &link); + if (r < 0) + return r; + + value = basename(link); + if (!value) + return -ENOENT; + + value = strdup(value); + if (!value) + return -ENOMEM; + + *ret = value; + + return 0; +} + +int readlink_and_make_absolute(const char *p, char **r) { + _cleanup_free_ char *target = NULL; + char *k; + int j; + + assert(p); + assert(r); + + j = readlink_malloc(p, &target); + if (j < 0) + return j; + + k = file_in_same_dir(p, target); + if (!k) + return -ENOMEM; + + *r = k; + return 0; +} + +int readlink_and_canonicalize(const char *p, char **r) { + char *t, *s; + int j; + + assert(p); + assert(r); + + j = readlink_and_make_absolute(p, &t); + if (j < 0) + return j; + + s = canonicalize_file_name(t); + if (s) { + free(t); + *r = s; + } else + *r = t; + + path_kill_slashes(*r); + + return 0; +} + +int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) { + _cleanup_free_ char *target = NULL, *t = NULL; + const char *full; + int r; + + full = prefix_roota(root, path); + r = readlink_malloc(full, &target); + if (r < 0) + return r; + + t = file_in_same_dir(path, target); + if (!t) + return -ENOMEM; + + *ret = t; + t = NULL; + + return 0; +} + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { + assert(path); + + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (chmod(path, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (chown(path, uid, gid) < 0) + return -errno; + + return 0; +} + +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { + assert(fd >= 0); + + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (fchmod(fd, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (fchown(fd, uid, gid) < 0) + return -errno; + + return 0; +} + +int fchmod_umask(int fd, mode_t m) { + mode_t u; + int r; + + u = umask(0777); + r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; + umask(u); + + return r; +} + +int fd_warn_permissions(const char *path, int fd) { + struct stat st; + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st.st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid() == 1 && (st.st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + +int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { + _cleanup_close_ int fd; + int r; + + assert(path); + + if (parents) + mkdir_parents(path, 0755); + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); + if (fd < 0) + return -errno; + + if (mode != MODE_INVALID) { + r = fchmod(fd, mode); + if (r < 0) + return -errno; + } + + if (uid != UID_INVALID || gid != GID_INVALID) { + r = fchown(fd, uid, gid); + if (r < 0) + return -errno; + } + + if (stamp != USEC_INFINITY) { + struct timespec ts[2]; + + timespec_store(&ts[0], stamp); + ts[1] = ts[0]; + r = futimens(fd, ts); + } else + r = futimens(fd, NULL); + if (r < 0) + return -errno; + + return 0; +} + +int touch(const char *path) { + return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); +} + +int symlink_idempotent(const char *from, const char *to) { + _cleanup_free_ char *p = NULL; + int r; + + assert(from); + assert(to); + + if (symlink(from, to) < 0) { + if (errno != EEXIST) + return -errno; + + r = readlink_malloc(to, &p); + if (r < 0) + return r; + + if (!streq(p, from)) + return -EINVAL; + } + + return 0; +} + +int symlink_atomic(const char *from, const char *to) { + _cleanup_free_ char *t = NULL; + int r; + + assert(from); + assert(to); + + r = tempfn_random(to, NULL, &t); + if (r < 0) + return r; + + if (symlink(from, t) < 0) + return -errno; + + if (rename(t, to) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int mknod_atomic(const char *path, mode_t mode, dev_t dev) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + r = tempfn_random(path, NULL, &t); + if (r < 0) + return r; + + if (mknod(t, mode, dev) < 0) + return -errno; + + if (rename(t, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int mkfifo_atomic(const char *path, mode_t mode) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + r = tempfn_random(path, NULL, &t); + if (r < 0) + return r; + + if (mkfifo(t, mode) < 0) + return -errno; + + if (rename(t, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int get_files_in_directory(const char *path, char ***list) { + _cleanup_closedir_ DIR *d = NULL; + size_t bufsize = 0, n = 0; + _cleanup_strv_free_ char **l = NULL; + + assert(path); + + /* Returns all files in a directory in *list, and the number + * of files as return value. If list is NULL returns only the + * number. */ + + d = opendir(path); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + if (!de) + break; + + dirent_ensure_type(d, de); + + if (!dirent_is_file(de)) + continue; + + if (list) { + /* one extra slot is needed for the terminating NULL */ + if (!GREEDY_REALLOC(l, bufsize, n + 2)) + return -ENOMEM; + + l[n] = strdup(de->d_name); + if (!l[n]) + return -ENOMEM; + + l[++n] = NULL; + } else + n++; + } + + if (list) { + *list = l; + l = NULL; /* avoid freeing */ + } + + return n; +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h new file mode 100644 index 0000000000..902c7e295b --- /dev/null +++ b/src/basic/fs-util.h @@ -0,0 +1,75 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <sys/inotify.h> +#include <sys/types.h> +#include <unistd.h> +#include <limits.h> + +#include "time-util.h" + +int unlink_noerrno(const char *path); + +int rmdir_parents(const char *path, const char *stop); + +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); + +int readlinkat_malloc(int fd, const char *p, char **ret); +int readlink_malloc(const char *p, char **r); +int readlink_value(const char *p, char **ret); +int readlink_and_make_absolute(const char *p, char **r); +int readlink_and_canonicalize(const char *p, char **r); +int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid); + +int fchmod_umask(int fd, mode_t mode); + +int fd_warn_permissions(const char *path, int fd); + +#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) + +int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); +int touch(const char *path); + +int symlink_idempotent(const char *from, const char *to); + +int symlink_atomic(const char *from, const char *to); +int mknod_atomic(const char *path, mode_t mode, dev_t dev); +int mkfifo_atomic(const char *path, mode_t mode); + +int get_files_in_directory(const char *path, char ***list); + +#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) + +#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ + for ((e) = &buffer.ev; \ + (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \ + (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len)) + +union inotify_event_buffer { + struct inotify_event ev; + uint8_t raw[INOTIFY_EVENT_MAX]; +}; diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c new file mode 100644 index 0000000000..0bfbcb1d37 --- /dev/null +++ b/src/basic/glob-util.c @@ -0,0 +1,72 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <glob.h> + +#include "glob-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +int glob_exists(const char *path) { + _cleanup_globfree_ glob_t g = {}; + int k; + + assert(path); + + errno = 0; + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + + if (k == GLOB_NOMATCH) + return 0; + if (k == GLOB_NOSPACE) + return -ENOMEM; + if (k != 0) + return errno ? -errno : -EIO; + + return !strv_isempty(g.gl_pathv); +} + +int glob_extend(char ***strv, const char *path) { + _cleanup_globfree_ glob_t g = {}; + int k; + char **p; + + errno = 0; + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + + if (k == GLOB_NOMATCH) + return -ENOENT; + if (k == GLOB_NOSPACE) + return -ENOMEM; + if (k != 0) + return errno ? -errno : -EIO; + if (strv_isempty(g.gl_pathv)) + return -ENOENT; + + STRV_FOREACH(p, g.gl_pathv) { + k = strv_extend(strv, *p); + if (k < 0) + return k; + } + + return 0; +} diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h new file mode 100644 index 0000000000..793adf4a6c --- /dev/null +++ b/src/basic/glob-util.h @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <string.h> + +#include "macro.h" +#include "string-util.h" + +int glob_exists(const char *path); +int glob_extend(char ***strv, const char *path); + +#define _cleanup_globfree_ _cleanup_(globfree) + +_pure_ static inline bool string_is_glob(const char *p) { + /* Check if a string contains any glob patterns. */ + return !!strpbrk(p, GLOB_CHARS); +} diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 20e7e51d9e..4109a08c6c 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -20,18 +20,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> #include <pthread.h> +#include <stdlib.h> -#include "util.h" +#include "alloc-util.h" #include "hashmap.h" -#include "set.h" #include "macro.h" -#include "siphash24.h" -#include "strv.h" #include "mempool.h" +#include "process-util.h" #include "random-util.h" +#include "set.h" +#include "siphash24.h" +#include "strv.h" +#include "util.h" #ifdef ENABLE_DEBUG_HASHMAP #include "list.h" diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c new file mode 100644 index 0000000000..4eb566b15a --- /dev/null +++ b/src/basic/hexdecoct.c @@ -0,0 +1,698 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <ctype.h> +#include <inttypes.h> + +#include "alloc-util.h" +#include "hexdecoct.h" +#include "util.h" + +char octchar(int x) { + return '0' + (x & 7); +} + +int unoctchar(char c) { + + if (c >= '0' && c <= '7') + return c - '0'; + + return -EINVAL; +} + +char decchar(int x) { + return '0' + (x % 10); +} + +int undecchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + return -EINVAL; +} + +char hexchar(int x) { + static const char table[16] = "0123456789abcdef"; + + return table[x & 15]; +} + +int unhexchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -EINVAL; +} + +char *hexmem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + z = r = malloc(l * 2 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + l; x++) { + *(z++) = hexchar(*x >> 4); + *(z++) = hexchar(*x & 15); + } + + *z = 0; + return r; +} + +int unhexmem(const char *p, size_t l, void **mem, size_t *len) { + _cleanup_free_ uint8_t *r = NULL; + uint8_t *z; + const char *x; + + assert(mem); + assert(len); + assert(p); + + z = r = malloc((l + 1) / 2 + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + l; x += 2) { + int a, b; + + a = unhexchar(x[0]); + if (a < 0) + return a; + else if (x+1 < p + l) { + b = unhexchar(x[1]); + if (b < 0) + return b; + } else + b = 0; + + *(z++) = (uint8_t) a << 4 | (uint8_t) b; + } + + *z = 0; + + *mem = r; + r = NULL; + *len = (l + 1) / 2; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-6 + * Notice that base32hex differs from base32 in the alphabet it uses. + * The distinction is that the base32hex representation preserves the + * order of the underlying data when compared as bytestrings, this is + * useful when representing NSEC3 hashes, as one can then verify the + * order of hashes directly from their representation. */ +char base32hexchar(int x) { + static const char table[32] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUV"; + + return table[x & 31]; +} + +int unbase32hexchar(char c) { + unsigned offset; + + if (c >= '0' && c <= '9') + return c - '0'; + + offset = '9' - '0' + 1; + + if (c >= 'A' && c <= 'V') + return c - 'A' + offset; + + return -EINVAL; +} + +char *base32hexmem(const void *p, size_t l, bool padding) { + char *r, *z; + const uint8_t *x; + size_t len; + + if (padding) + /* five input bytes makes eight output bytes, padding is added so we must round up */ + len = 8 * (l + 4) / 5; + else { + /* same, but round down as there is no padding */ + len = 8 * l / 5; + + switch (l % 5) { + case 4: + len += 7; + break; + case 3: + len += 5; + break; + case 2: + len += 4; + break; + case 1: + len += 2; + break; + } + } + + z = r = malloc(len + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ + x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */ + *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */ + } + + switch (l % 5) { + case 4: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */ + if (padding) + *(z++) = '='; + + break; + + case 3: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 2: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 1: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + } + + *z = 0; + return r; +} + +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d, e, f, g, h; + uint8_t *z; + const char *x; + size_t len; + unsigned pad = 0; + + assert(p); + + /* padding ensures any base32hex input has input divisible by 8 */ + if (padding && l % 8 != 0) + return -EINVAL; + + if (padding) { + /* strip the padding */ + while (l > 0 && p[l - 1] == '=' && pad < 7) { + pad ++; + l --; + } + } + + /* a group of eight input bytes needs five output bytes, in case of + padding we need to add some extra bytes */ + len = (l / 8) * 5; + + switch (l % 8) { + case 7: + len += 4; + break; + case 5: + len += 3; + break; + case 4: + len += 2; + break; + case 2: + len += 1; + break; + case 0: + break; + default: + return -EINVAL; + } + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 8) * 8; x += 8) { + /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW + e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + h = unbase32hexchar(x[7]); + if (h < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */ + } + + switch (l % 8) { + case 7: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + /* g == 000VV000 */ + if (g & 7) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + + break; + case 5: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + /* e == 000SSSS0 */ + if (e & 1) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + + break; + case 4: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + /* d == 000W0000 */ + if (d & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + + break; + case 2: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 000YYY00 */ + if (b & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + + break; + case 0: + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-4 */ +char base64char(int x) { + static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + return table[x & 63]; +} + +int unbase64char(char c) { + unsigned offset; + + if (c >= 'A' && c <= 'Z') + return c - 'A'; + + offset = 'Z' - 'A' + 1; + + if (c >= 'a' && c <= 'z') + return c - 'a' + offset; + + offset += 'z' - 'a' + 1; + + if (c >= '0' && c <= '9') + return c - '0' + offset; + + offset += '9' - '0' + 1; + + if (c == '+') + return offset; + + offset ++; + + if (c == '/') + return offset; + + return -EINVAL; +} + +char *base64mem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + /* three input bytes makes four output bytes, padding is added so we must round up */ + z = r = malloc(4 * (l + 2) / 3 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ + *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ + } + + switch (l % 3) { + case 2: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ + *(z++) = '='; + + break; + case 1: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ + *(z++) = '='; + *(z++) = '='; + + break; + } + + *z = 0; + return r; +} + +int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d; + uint8_t *z; + const char *x; + size_t len; + + assert(p); + + /* padding ensures any base63 input has input divisible by 4 */ + if (l % 4 != 0) + return -EINVAL; + + /* strip the padding */ + if (l > 0 && p[l - 1] == '=') + l --; + if (l > 0 && p[l - 1] == '=') + l --; + + /* a group of four input bytes needs three output bytes, in case of + padding we need to add two or three extra bytes */ + len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 4) * 4; x += 4) { + /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase64char(x[3]); + if (d < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + } + + switch (l % 4) { + case 3: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + /* c == 00ZZZZ00 */ + if (c & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + + break; + case 2: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 00YY0000 */ + if (b & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + + break; + case 0: + + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +void hexdump(FILE *f, const void *p, size_t s) { + const uint8_t *b = p; + unsigned n = 0; + + assert(s == 0 || b); + + while (s > 0) { + size_t i; + + fprintf(f, "%04x ", n); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputs(" ", f); + else + fprintf(f, "%02x ", b[i]); + + if (i == 7) + fputc(' ', f); + } + + fputc(' ', f); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputc(' ', f); + else + fputc(isprint(b[i]) ? (char) b[i] : '.', f); + } + + fputc('\n', f); + + if (s < 16) + break; + + n += 16; + b += 16; + s -= 16; + } +} diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h new file mode 100644 index 0000000000..4aeb4c3bdc --- /dev/null +++ b/src/basic/hexdecoct.h @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <stdio.h> +#include <sys/types.h> + +#include "macro.h" + +char octchar(int x) _const_; +int unoctchar(char c) _const_; + +char decchar(int x) _const_; +int undecchar(char c) _const_; + +char hexchar(int x) _const_; +int unhexchar(char c) _const_; + +char *hexmem(const void *p, size_t l); +int unhexmem(const char *p, size_t l, void **mem, size_t *len); + +char base32hexchar(int x) _const_; +int unbase32hexchar(char c) _const_; + +char base64char(int x) _const_; +int unbase64char(char c) _const_; + +char *base32hexmem(const void *p, size_t l, bool padding); +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); + +char *base64mem(const void *p, size_t l); +int unbase64mem(const char *p, size_t l, void **mem, size_t *len); + +void hexdump(FILE *f, const void *p, size_t s); diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 1b816fb77a..ea0528c6fc 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/utsname.h> #include <ctype.h> +#include <sys/utsname.h> -#include "util.h" +#include "fd-util.h" +#include "fileio.h" #include "hostname-util.h" +#include "string-util.h" +#include "util.h" bool hostname_is_set(void) { struct utsname u; diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index d88864b598..f4e24121e7 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -21,6 +21,7 @@ #include <arpa/inet.h> +#include "alloc-util.h" #include "in-addr-util.h" int in_addr_is_null(int family, const union in_addr_union *u) { diff --git a/src/basic/io-util.c b/src/basic/io-util.c new file mode 100644 index 0000000000..ac8f93ff57 --- /dev/null +++ b/src/basic/io-util.c @@ -0,0 +1,261 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <poll.h> +#include <unistd.h> + +#include "io-util.h" + +int flush_fd(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + + for (;;) { + char buf[LINE_MAX]; + ssize_t l; + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; + + return -errno; + + } else if (r == 0) + return 0; + + l = read(fd, buf, sizeof(buf)); + if (l < 0) { + + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + return 0; + + return -errno; + } else if (l == 0) + return 0; + } +} + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { + uint8_t *p = buf; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + /* If called with nbytes == 0, let's call read() at least + * once, to validate the operation */ + + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; + + do { + ssize_t k; + + k = read(fd, p, nbytes); + if (k < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN && do_poll) { + + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ + + (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); + continue; + } + + return n > 0 ? n : -errno; + } + + if (k == 0) + return n; + + assert((size_t) k <= nbytes); + + p += k; + nbytes -= k; + n += k; + } while (nbytes > 0); + + return n; +} + +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { + ssize_t n; + + n = loop_read(fd, buf, nbytes, do_poll); + if (n < 0) + return (int) n; + if ((size_t) n != nbytes) + return -EIO; + + return 0; +} + +int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { + const uint8_t *p = buf; + + assert(fd >= 0); + assert(buf); + + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; + + do { + ssize_t k; + + k = write(fd, p, nbytes); + if (k < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN && do_poll) { + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via write() */ + + (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); + continue; + } + + return -errno; + } + + if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */ + return -EIO; + + assert((size_t) k <= nbytes); + + p += k; + nbytes -= k; + } while (nbytes > 0); + + return 0; +} + +int pipe_eof(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN|POLLHUP, + }; + + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents & POLLHUP; +} + +int fd_wait_for_event(int fd, int event, usec_t t) { + + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; + + struct timespec ts; + int r; + + r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents; +} + +static size_t nul_length(const uint8_t *p, size_t sz) { + size_t n = 0; + + while (sz > 0) { + if (*p != 0) + break; + + n++; + p++; + sz--; + } + + return n; +} + +ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { + const uint8_t *q, *w, *e; + ssize_t l; + + q = w = p; + e = q + sz; + while (q < e) { + size_t n; + + n = nul_length(q, e - q); + + /* If there are more than the specified run length of + * NUL bytes, or if this is the beginning or the end + * of the buffer, then seek instead of write */ + if ((n > run_length) || + (n > 0 && q == p) || + (n > 0 && q + n >= e)) { + if (q > w) { + l = write(fd, w, q - w); + if (l < 0) + return -errno; + if (l != q -w) + return -EIO; + } + + if (lseek(fd, n, SEEK_CUR) == (off_t) -1) + return -errno; + + q += n; + w = q; + } else if (n > 0) + q += n; + else + q ++; + } + + if (q > w) { + l = write(fd, w, q - w); + if (l < 0) + return -errno; + if (l != q - w) + return -EIO; + } + + return q - (const uint8_t*) p; +} diff --git a/src/basic/io-util.h b/src/basic/io-util.h new file mode 100644 index 0000000000..cd2aa75ad2 --- /dev/null +++ b/src/basic/io-util.h @@ -0,0 +1,76 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/types.h> +#include <sys/uio.h> + +#include "time-util.h" + +int flush_fd(int fd); + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); +int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); + +int pipe_eof(int fd); + +int fd_wait_for_event(int fd, int event, usec_t timeout); + +ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); + +#define IOVEC_SET_STRING(i, s) \ + do { \ + struct iovec *_i = &(i); \ + char *_s = (char *)(s); \ + _i->iov_base = _s; \ + _i->iov_len = strlen(_s); \ + } while(false) + +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { + unsigned j; + size_t r = 0; + + for (j = 0; j < n; j++) + r += i[j].iov_len; + + return r; +} + +static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { + unsigned j; + + for (j = 0; j < n; j++) { + size_t sub; + + if (_unlikely_(k <= 0)) + break; + + sub = MIN(i[j].iov_len, k); + i[j].iov_len -= sub; + i[j].iov_base = (uint8_t*) i[j].iov_base + sub; + k -= sub; + } + + return k; +} diff --git a/src/basic/json.c b/src/basic/json.c index be40a0d203..716705e5ff 100644 --- a/src/basic/json.c +++ b/src/basic/json.c @@ -19,11 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <math.h> +#include <sys/types.h> + +#include "alloc-util.h" +#include "json.h" #include "macro.h" +#include "hexdecoct.h" +#include "string-util.h" #include "utf8.h" -#include "json.h" int json_variant_new(JsonVariant **ret, JsonVariantType type) { JsonVariant *v; diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 61db9a8125..b87fd7670b 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -19,14 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <langinfo.h> +#include <locale.h> #include <sys/mman.h> +#include "dirent-util.h" +#include "fd-util.h" +#include "locale-util.h" +#include "path-util.h" #include "set.h" -#include "util.h" -#include "utf8.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" - -#include "locale-util.h" +#include "utf8.h" +#include "util.h" static int add_locales_from_archive(Set *locales) { /* Stolen from glibc... */ @@ -204,6 +210,88 @@ bool locale_is_valid(const char *name) { return true; } +void init_gettext(void) { + setlocale(LC_ALL, ""); + textdomain(GETTEXT_PACKAGE); +} + +bool is_locale_utf8(void) { + const char *set; + static int cached_answer = -1; + + /* Note that we default to 'true' here, since today UTF8 is + * pretty much supported everywhere. */ + + if (cached_answer >= 0) + goto out; + + if (!setlocale(LC_ALL, "")) { + cached_answer = true; + goto out; + } + + set = nl_langinfo(CODESET); + if (!set) { + cached_answer = true; + goto out; + } + + if (streq(set, "UTF-8")) { + cached_answer = true; + goto out; + } + + /* For LC_CTYPE=="C" return true, because CTYPE is effectly + * unset and everything can do to UTF-8 nowadays. */ + set = setlocale(LC_CTYPE, NULL); + if (!set) { + cached_answer = true; + goto out; + } + + /* Check result, but ignore the result if C was set + * explicitly. */ + cached_answer = + STR_IN_SET(set, "C", "POSIX") && + !getenv("LC_ALL") && + !getenv("LC_CTYPE") && + !getenv("LANG"); + +out: + return (bool) cached_answer; +} + + +const char *draw_special_char(DrawSpecialChar ch) { + + static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { + + /* UTF-8 */ { + [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */ + [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ + [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ + [DRAW_TREE_SPACE] = " ", /* */ + [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ + [DRAW_BLACK_CIRCLE] = "\342\227\217", /* â— */ + [DRAW_ARROW] = "\342\206\222", /* → */ + [DRAW_DASH] = "\342\200\223", /* – */ + }, + + /* ASCII fallback */ { + [DRAW_TREE_VERTICAL] = "| ", + [DRAW_TREE_BRANCH] = "|-", + [DRAW_TREE_RIGHT] = "`-", + [DRAW_TREE_SPACE] = " ", + [DRAW_TRIANGULAR_BULLET] = ">", + [DRAW_BLACK_CIRCLE] = "*", + [DRAW_ARROW] = "->", + [DRAW_DASH] = "-", + } + }; + + return draw_table[!is_locale_utf8()][ch]; +} + static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { [VARIABLE_LANG] = "LANG", [VARIABLE_LANGUAGE] = "LANGUAGE", diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index e48aa3d9af..c71d145139 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -21,6 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <libintl.h> #include <stdbool.h> #include "macro.h" @@ -50,5 +51,25 @@ typedef enum LocaleVariable { int get_locales(char ***l); bool locale_is_valid(const char *name); +#define _(String) gettext(String) +#define N_(String) String +void init_gettext(void); + +bool is_locale_utf8(void); + +typedef enum DrawSpecialChar { + DRAW_TREE_VERTICAL, + DRAW_TREE_BRANCH, + DRAW_TREE_RIGHT, + DRAW_TREE_SPACE, + DRAW_TRIANGULAR_BULLET, + DRAW_BLACK_CIRCLE, + DRAW_ARROW, + DRAW_DASH, + _DRAW_SPECIAL_CHAR_MAX +} DrawSpecialChar; + +const char *draw_special_char(DrawSpecialChar ch); + const char* locale_variable_to_string(LocaleVariable i) _const_; LocaleVariable locale_variable_from_string(const char *s) _pure_; diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index f3ec6a3e52..87c3aef7af 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -27,9 +27,13 @@ #include <limits.h> #include <sys/file.h> -#include "util.h" -#include "lockfile-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "lockfile-util.h" +#include "path-util.h" +#include "util.h" int make_lock_file(const char *p, int operation, LockFile *ret) { _cleanup_close_ int fd = -1; diff --git a/src/basic/log.c b/src/basic/log.c index e6d7d15182..fe29cacd9e 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -19,26 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdarg.h> -#include <stdio.h> #include <errno.h> -#include <unistd.h> #include <fcntl.h> +#include <printf.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> #include <sys/socket.h> #include <sys/un.h> -#include <stddef.h> -#include <printf.h> +#include <unistd.h> #include "sd-messages.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" #include "log.h" -#include "util.h" -#include "missing.h" #include "macro.h" -#include "socket-util.h" -#include "formats-util.h" +#include "missing.h" +#include "parse-util.h" +#include "proc-cmdline.h" #include "process-util.h" -#include "terminal-util.h" #include "signal-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" +#include "syslog-util.h" +#include "terminal-util.h" +#include "util.h" #define SNDBUF_SIZE (8*1024*1024) @@ -435,7 +445,7 @@ static int write_to_syslog( static int write_to_kmsg( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, @@ -506,7 +516,7 @@ static int log_do_header( static int write_to_journal( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, @@ -640,7 +650,7 @@ int log_dump_internal( int log_internalv( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *format, @@ -667,7 +677,7 @@ int log_internalv( int log_internal( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *format, ...) { @@ -685,7 +695,7 @@ int log_internal( int log_object_internalv( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, @@ -729,7 +739,7 @@ int log_object_internalv( int log_object_internal( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, diff --git a/src/basic/log.h b/src/basic/log.h index 369d6b1127..cda1e45cc8 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -21,14 +21,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> +#include <errno.h> #include <stdarg.h> +#include <stdbool.h> #include <stdlib.h> -#include <syslog.h> #include <sys/signalfd.h> -#include <errno.h> +#include <syslog.h> #include "sd-id128.h" + #include "macro.h" typedef enum LogTarget{ diff --git a/src/basic/login-util.c b/src/basic/login-util.c index e25437f0f4..832f477bd2 100644 --- a/src/basic/login-util.c +++ b/src/basic/login-util.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "login-util.h" #include "def.h" +#include "string-util.h" +#include "login-util.h" bool session_id_valid(const char *id) { diff --git a/src/basic/login-util.h b/src/basic/login-util.h index a79f20c1b1..be5bb64870 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -22,5 +22,10 @@ #pragma once #include <stdbool.h> +#include <unistd.h> bool session_id_valid(const char *id); + +static inline bool logind_running(void) { + return access("/run/systemd/seats/", F_OK) >= 0; +} diff --git a/src/basic/macro.h b/src/basic/macro.h index f55d65e2f1..5088e6720d 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -22,11 +22,10 @@ ***/ #include <assert.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/uio.h> #include <inttypes.h> #include <stdbool.h> +#include <sys/param.h> +#include <sys/types.h> #define _printf_(a,b) __attribute__ ((format (printf, a, b))) #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) @@ -295,111 +294,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) #define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) -/* The following macros add 1 when converting things, since UID 0 is a - * valid UID, while the pointer NULL is special */ -#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1)) -#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) - -#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) -#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) - -#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) -#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) - -#define memzero(x,l) (memset((x), 0, (l))) -#define zero(x) (memzero(&(x), sizeof(x))) - #define CHAR_TO_STR(x) ((char[2]) { x, 0 }) #define char_array_0(x) x[sizeof(x)-1] = 0; -#define IOVEC_SET_STRING(i, s) \ - do { \ - struct iovec *_i = &(i); \ - char *_s = (char *)(s); \ - _i->iov_base = _s; \ - _i->iov_len = strlen(_s); \ - } while(false) - -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; - - for (j = 0; j < n; j++) - r += i[j].iov_len; - - return r; -} - -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; - - for (j = 0; j < n; j++) { - size_t sub; - - if (_unlikely_(k <= 0)) - break; - - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t*) i[j].iov_base + sub; - k -= sub; - } - - return k; -} - -#define VA_FORMAT_ADVANCE(format, ap) \ -do { \ - int _argtypes[128]; \ - size_t _i, _k; \ - _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ - assert(_k < ELEMENTSOF(_argtypes)); \ - for (_i = 0; _i < _k; _i++) { \ - if (_argtypes[_i] & PA_FLAG_PTR) { \ - (void) va_arg(ap, void*); \ - continue; \ - } \ - \ - switch (_argtypes[_i]) { \ - case PA_INT: \ - case PA_INT|PA_FLAG_SHORT: \ - case PA_CHAR: \ - (void) va_arg(ap, int); \ - break; \ - case PA_INT|PA_FLAG_LONG: \ - (void) va_arg(ap, long int); \ - break; \ - case PA_INT|PA_FLAG_LONG_LONG: \ - (void) va_arg(ap, long long int); \ - break; \ - case PA_WCHAR: \ - (void) va_arg(ap, wchar_t); \ - break; \ - case PA_WSTRING: \ - case PA_STRING: \ - case PA_POINTER: \ - (void) va_arg(ap, void*); \ - break; \ - case PA_FLOAT: \ - case PA_DOUBLE: \ - (void) va_arg(ap, double); \ - break; \ - case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ - (void) va_arg(ap, long double); \ - break; \ - default: \ - assert_not_reached("Unknown format string argument."); \ - } \ - } \ -} while(false) - - /* Because statfs.t_type can be int on some architectures, we have to cast - * the const magic to the type, otherwise the compiler warns about - * signed/unsigned comparison, because the magic can be 32 bit unsigned. - */ -#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) - /* Returns the number of chars needed to format variables of the * specified type as a decimal string. Adds in extra space for a * negative '-' prefix (hence works correctly on signed @@ -410,6 +308,15 @@ do { \ sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) +#define DECIMAL_STR_WIDTH(x) \ + ({ \ + typeof(x) _x_ = (x); \ + unsigned ans = 1; \ + while (_x_ /= 10) \ + ans++; \ + ans; \ + }) + #define SET_FLAG(v, flag, b) \ (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) @@ -427,21 +334,6 @@ do { \ _found; \ }) -/* Return a nulstr for a standard cascade of configuration directories, - * suitable to pass to conf_files_list_nulstr or config_parse_many. */ -#define CONF_DIRS_NULSTR(n) \ - "/etc/" n ".d\0" \ - "/run/" n ".d\0" \ - "/usr/local/lib/" n ".d\0" \ - "/usr/lib/" n ".d\0" \ - CONF_DIR_SPLIT_USR(n) - -#ifdef HAVE_SPLIT_USR -#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0" -#else -#define CONF_DIR_SPLIT_USR(n) -#endif - /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local @@ -466,10 +358,6 @@ do { \ #endif #endif -#define UID_INVALID ((uid_t) -1) -#define GID_INVALID ((gid_t) -1) -#define MODE_INVALID ((mode_t) -1) - #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ @@ -477,7 +365,4 @@ do { \ } \ struct __useless_struct_to_allow_trailing_semicolon__ -#define CMSG_FOREACH(cmsg, mh) \ - for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) - #include "log.h" diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index e99a738e1f..92630f6b25 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -19,19 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <fcntl.h> -#include <sys/mman.h> -#include <sys/prctl.h> - #ifdef HAVE_LINUX_MEMFD_H -# include <linux/memfd.h> +#include <linux/memfd.h> #endif +#include <stdio.h> +#include <sys/mman.h> +#include <sys/prctl.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "memfd-util.h" -#include "utf8.h" #include "missing.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" int memfd_new(const char *name) { _cleanup_free_ char *g = NULL; diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 3ed551fb37..2cb404ea81 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -21,7 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - +#include <sys/types.h> +#include <inttypes.h> int memfd_new(const char *name); int memfd_new_and_map(const char *name, size_t sz, void **p); diff --git a/src/basic/missing.h b/src/basic/missing.h index 59e835a466..d539ed00e4 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -23,19 +23,20 @@ /* Missing glibc definitions to access certain kernel APIs */ -#include <sys/resource.h> -#include <sys/syscall.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> #include <errno.h> -#include <linux/oom.h> -#include <linux/input.h> -#include <linux/if_link.h> -#include <linux/loop.h> +#include <fcntl.h> #include <linux/audit.h> #include <linux/capability.h> +#include <linux/if_link.h> +#include <linux/input.h> +#include <linux/loop.h> #include <linux/neighbour.h> +#include <linux/oom.h> +#include <linux/rtnetlink.h> +#include <stdlib.h> +#include <sys/resource.h> +#include <sys/syscall.h> +#include <unistd.h> #ifdef HAVE_AUDIT #include <libaudit.h> @@ -126,6 +127,10 @@ #define SOL_NETLINK 270 #endif +#ifndef NETLINK_LIST_MEMBERSHIPS +#define NETLINK_LIST_MEMBERSHIPS 9 +#endif + #if !HAVE_DECL_PIVOT_ROOT static inline int pivot_root(const char *new_root, const char *put_old) { return syscall(SYS_pivot_root, new_root, put_old); @@ -248,6 +253,10 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) { #define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) #endif +#ifndef BTRFS_QGROUP_LEVEL_SHIFT +#define BTRFS_QGROUP_LEVEL_SHIFT 48 +#endif + #ifndef HAVE_LINUX_BTRFS_H struct btrfs_ioctl_vol_args { int64_t fd; @@ -486,6 +495,10 @@ struct btrfs_ioctl_quota_ctl_args { #define BTRFS_QGROUP_LIMIT_KEY 244 #endif +#ifndef BTRFS_QGROUP_RELATION_KEY +#define BTRFS_QGROUP_RELATION_KEY 246 +#endif + #ifndef BTRFS_ROOT_BACKREF_KEY #define BTRFS_ROOT_BACKREF_KEY 144 #endif @@ -888,6 +901,10 @@ static inline int setns(int fd, int nstype) { #define NDA_MAX (__NDA_MAX - 1) #endif +#ifndef RTA_PREF +#define RTA_PREF 20 +#endif + #ifndef IPV6_UNICAST_IF #define IPV6_UNICAST_IF 76 #endif diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 7ee4546988..0214c4627e 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -22,9 +22,12 @@ #include <string.h> #include <errno.h> -#include "util.h" -#include "path-util.h" +#include "fs-util.h" #include "mkdir.h" +#include "path-util.h" +#include "stat-util.h" +#include "user-util.h" +#include "util.h" int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) { struct stat st; diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c new file mode 100644 index 0000000000..29997b1ce7 --- /dev/null +++ b/src/basic/mount-util.c @@ -0,0 +1,529 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <string.h> +#include <sys/mount.h> +#include <sys/statvfs.h> + +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "set.h" +#include "stdio-util.h" +#include "string-util.h" +#include "util.h" + +static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { + char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; + _cleanup_free_ char *fdinfo = NULL; + _cleanup_close_ int subfd = -1; + char *p; + int r; + + if ((flags & AT_EMPTY_PATH) && isempty(filename)) + xsprintf(path, "/proc/self/fdinfo/%i", fd); + else { + subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); + if (subfd < 0) + return -errno; + + xsprintf(path, "/proc/self/fdinfo/%i", subfd); + } + + r = read_full_file(path, &fdinfo, NULL); + if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ + return -EOPNOTSUPP; + if (r < 0) + return -errno; + + p = startswith(fdinfo, "mnt_id:"); + if (!p) { + p = strstr(fdinfo, "\nmnt_id:"); + if (!p) /* The mnt_id field is a relatively new addition */ + return -EOPNOTSUPP; + + p += 8; + } + + p += strspn(p, WHITESPACE); + p[strcspn(p, WHITESPACE)] = 0; + + return safe_atoi(p, mnt_id); +} + + +int fd_is_mount_point(int fd, const char *filename, int flags) { + union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; + int mount_id = -1, mount_id_parent = -1; + bool nosupp = false, check_st_dev = true; + struct stat a, b; + int r; + + assert(fd >= 0); + assert(filename); + + /* First we will try the name_to_handle_at() syscall, which + * tells us the mount id and an opaque file "handle". It is + * not supported everywhere though (kernel compile-time + * option, not all file systems are hooked up). If it works + * the mount id is usually good enough to tell us whether + * something is a mount point. + * + * If that didn't work we will try to read the mount id from + * /proc/self/fdinfo/<fd>. This is almost as good as + * name_to_handle_at(), however, does not return the + * opaque file handle. The opaque file handle is pretty useful + * to detect the root directory, which we should always + * consider a mount point. Hence we use this only as + * fallback. Exporting the mnt_id in fdinfo is a pretty recent + * kernel addition. + * + * As last fallback we do traditional fstat() based st_dev + * comparisons. This is how things were traditionally done, + * but unionfs breaks breaks this since it exposes file + * systems with a variety of st_dev reported. Also, btrfs + * subvolumes have different st_dev, even though they aren't + * real mounts of their own. */ + + r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); + if (r < 0) { + if (errno == ENOSYS) + /* This kernel does not support name_to_handle_at() + * fall back to simpler logic. */ + goto fallback_fdinfo; + else if (errno == EOPNOTSUPP) + /* This kernel or file system does not support + * name_to_handle_at(), hence let's see if the + * upper fs supports it (in which case it is a + * mount point), otherwise fallback to the + * traditional stat() logic */ + nosupp = true; + else + return -errno; + } + + r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); + if (r < 0) { + if (errno == EOPNOTSUPP) { + if (nosupp) + /* Neither parent nor child do name_to_handle_at()? + We have no choice but to fall back. */ + goto fallback_fdinfo; + else + /* The parent can't do name_to_handle_at() but the + * directory we are interested in can? + * If so, it must be a mount point. */ + return 1; + } else + return -errno; + } + + /* The parent can do name_to_handle_at() but the + * directory we are interested in can't? If so, it + * must be a mount point. */ + if (nosupp) + return 1; + + /* If the file handle for the directory we are + * interested in and its parent are identical, we + * assume this is the root directory, which is a mount + * point. */ + + if (h.handle.handle_bytes == h_parent.handle.handle_bytes && + h.handle.handle_type == h_parent.handle.handle_type && + memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) + return 1; + + return mount_id != mount_id_parent; + +fallback_fdinfo: + r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); + if (r == -EOPNOTSUPP) + goto fallback_fstat; + if (r < 0) + return r; + + r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); + if (r < 0) + return r; + + if (mount_id != mount_id_parent) + return 1; + + /* Hmm, so, the mount ids are the same. This leaves one + * special case though for the root file system. For that, + * let's see if the parent directory has the same inode as we + * are interested in. Hence, let's also do fstat() checks now, + * too, but avoid the st_dev comparisons, since they aren't + * that useful on unionfs mounts. */ + check_st_dev = false; + +fallback_fstat: + /* yay for fstatat() taking a different set of flags than the other + * _at() above */ + if (flags & AT_SYMLINK_FOLLOW) + flags &= ~AT_SYMLINK_FOLLOW; + else + flags |= AT_SYMLINK_NOFOLLOW; + if (fstatat(fd, filename, &a, flags) < 0) + return -errno; + + if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) + return -errno; + + /* A directory with same device and inode as its parent? Must + * be the root directory */ + if (a.st_dev == b.st_dev && + a.st_ino == b.st_ino) + return 1; + + return check_st_dev && (a.st_dev != b.st_dev); +} + +/* flags can be AT_SYMLINK_FOLLOW or 0 */ +int path_is_mount_point(const char *t, int flags) { + _cleanup_close_ int fd = -1; + _cleanup_free_ char *canonical = NULL, *parent = NULL; + + assert(t); + + if (path_equal(t, "/")) + return 1; + + /* we need to resolve symlinks manually, we can't just rely on + * fd_is_mount_point() to do that for us; if we have a structure like + * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we + * look at needs to be /usr, not /. */ + if (flags & AT_SYMLINK_FOLLOW) { + canonical = canonicalize_file_name(t); + if (!canonical) + return -errno; + + t = canonical; + } + + parent = dirname_malloc(t); + if (!parent) + return -ENOMEM; + + fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); + if (fd < 0) + return -errno; + + return fd_is_mount_point(fd, basename(t), flags); +} + +int umount_recursive(const char *prefix, int flags) { + bool again; + int n = 0, r; + + /* Try to umount everything recursively below a + * directory. Also, take care of stacked mounts, and keep + * unmounting them until they are gone. */ + + do { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + + again = false; + r = 0; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *path = NULL, *p = NULL; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%*s " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%*s" /* (11) mount options 2 */ + "%*[^\n]", /* some rubbish at the end */ + &path); + if (k != 1) { + if (k == EOF) + break; + + continue; + } + + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; + + if (!path_startswith(p, prefix)) + continue; + + if (umount2(p, flags) < 0) { + r = -errno; + continue; + } + + again = true; + n++; + + break; + } + + } while (again); + + return r ? r : n; +} + +static int get_mount_flags(const char *path, unsigned long *flags) { + struct statvfs buf; + + if (statvfs(path, &buf) < 0) + return -errno; + *flags = buf.f_flag; + return 0; +} + +int bind_remount_recursive(const char *prefix, bool ro) { + _cleanup_set_free_free_ Set *done = NULL; + _cleanup_free_ char *cleaned = NULL; + int r; + + /* Recursively remount a directory (and all its submounts) + * read-only or read-write. If the directory is already + * mounted, we reuse the mount and simply mark it + * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write + * operation). If it isn't we first make it one. Afterwards we + * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all + * submounts we can access, too. When mounts are stacked on + * the same mount point we only care for each individual + * "top-level" mount on each point, as we cannot + * influence/access the underlying mounts anyway. We do not + * have any effect on future submounts that might get + * propagated, they migt be writable. This includes future + * submounts that have been triggered via autofs. */ + + cleaned = strdup(prefix); + if (!cleaned) + return -ENOMEM; + + path_kill_slashes(cleaned); + + done = set_new(&string_hash_ops); + if (!done) + return -ENOMEM; + + for (;;) { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + _cleanup_set_free_free_ Set *todo = NULL; + bool top_autofs = false; + char *x; + unsigned long orig_flags; + + todo = set_new(&string_hash_ops); + if (!todo) + return -ENOMEM; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options (superblock) */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%ms " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%*s" /* (11) mount options (bind mount) */ + "%*[^\n]", /* some rubbish at the end */ + &path, + &type); + if (k != 2) { + if (k == EOF) + break; + + continue; + } + + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; + + /* Let's ignore autofs mounts. If they aren't + * triggered yet, we want to avoid triggering + * them, as we don't make any guarantees for + * future submounts anyway. If they are + * already triggered, then we will find + * another entry for this. */ + if (streq(type, "autofs")) { + top_autofs = top_autofs || path_equal(cleaned, p); + continue; + } + + if (path_startswith(p, cleaned) && + !set_contains(done, p)) { + + r = set_consume(todo, p); + p = NULL; + + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } + } + + /* If we have no submounts to process anymore and if + * the root is either already done, or an autofs, we + * are done */ + if (set_isempty(todo) && + (top_autofs || set_contains(done, cleaned))) + return 0; + + if (!set_contains(done, cleaned) && + !set_contains(todo, cleaned)) { + /* The prefix directory itself is not yet a + * mount, make it one. */ + if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0) + return -errno; + + orig_flags = 0; + (void) get_mount_flags(cleaned, &orig_flags); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) + return -errno; + + x = strdup(cleaned); + if (!x) + return -ENOMEM; + + r = set_consume(done, x); + if (r < 0) + return r; + } + + while ((x = set_steal_first(todo))) { + + r = set_consume(done, x); + if (r == -EEXIST || r == 0) + continue; + if (r < 0) + return r; + + /* Try to reuse the original flag set, but + * don't care for errors, in case of + * obstructed mounts */ + orig_flags = 0; + (void) get_mount_flags(x, &orig_flags); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { + + /* Deal with mount points that are + * obstructed by a later mount */ + + if (errno != ENOENT) + return -errno; + } + + } + } +} + +int mount_move_root(const char *path) { + assert(path); + + if (chdir(path) < 0) + return -errno; + + if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + + if (chdir("/") < 0) + return -errno; + + return 0; +} + +bool fstype_is_network(const char *fstype) { + static const char table[] = + "afs\0" + "cifs\0" + "smbfs\0" + "sshfs\0" + "ncpfs\0" + "ncp\0" + "nfs\0" + "nfs4\0" + "gfs\0" + "gfs2\0" + "glusterfs\0"; + + const char *x; + + x = startswith(fstype, "fuse."); + if (x) + fstype = x; + + return nulstr_contains(table, fstype); +} + +int repeat_unmount(const char *path, int flags) { + bool done = false; + + assert(path); + + /* If there are multiple mounts on a mount point, this + * removes them all */ + + for (;;) { + if (umount2(path, flags) < 0) { + + if (errno == EINVAL) + return done; + + return -errno; + } + + done = true; + } +} diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h new file mode 100644 index 0000000000..48954c2d67 --- /dev/null +++ b/src/basic/mount-util.h @@ -0,0 +1,52 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <mntent.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "missing.h" + +int fd_is_mount_point(int fd, const char *filename, int flags); +int path_is_mount_point(const char *path, int flags); + +int repeat_unmount(const char *path, int flags); + +int umount_recursive(const char *target, int flags); +int bind_remount_recursive(const char *prefix, bool ro); + +int mount_move_root(const char *path); + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); +#define _cleanup_endmntent_ _cleanup_(endmntentp) + +bool fstype_is_network(const char *fstype); + +union file_handle_union { + struct file_handle handle; + char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; +}; + +#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c new file mode 100644 index 0000000000..151067e916 --- /dev/null +++ b/src/basic/parse-util.c @@ -0,0 +1,492 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "extract-word.h" +#include "parse-util.h" +#include "string-util.h" +#include "util.h" + +int parse_boolean(const char *v) { + assert(v); + + if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on")) + return 1; + else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off")) + return 0; + + return -EINVAL; +} + +int parse_pid(const char *s, pid_t* ret_pid) { + unsigned long ul = 0; + pid_t pid; + int r; + + assert(s); + assert(ret_pid); + + r = safe_atolu(s, &ul); + if (r < 0) + return r; + + pid = (pid_t) ul; + + if ((unsigned long) pid != ul) + return -ERANGE; + + if (pid <= 0) + return -ERANGE; + + *ret_pid = pid; + return 0; +} + +int parse_mode(const char *s, mode_t *ret) { + char *x; + long l; + + assert(s); + assert(ret); + + s += strspn(s, WHITESPACE); + if (s[0] == '-') + return -ERANGE; + + errno = 0; + l = strtol(s, &x, 8); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (l < 0 || l > 07777) + return -ERANGE; + + *ret = (mode_t) l; + return 0; +} + +int parse_ifindex(const char *s, int *ret) { + int ifi, r; + + r = safe_atoi(s, &ifi); + if (r < 0) + return r; + if (ifi <= 0) + return -EINVAL; + + *ret = ifi; + return 0; +} + +int parse_size(const char *t, uint64_t base, uint64_t *size) { + + /* Soo, sometimes we want to parse IEC binary suffixes, and + * sometimes SI decimal suffixes. This function can parse + * both. Which one is the right way depends on the + * context. Wikipedia suggests that SI is customary for + * hardware metrics and network speeds, while IEC is + * customary for most data sizes used by software and volatile + * (RAM) memory. Hence be careful which one you pick! + * + * In either case we use just K, M, G as suffix, and not Ki, + * Mi, Gi or so (as IEC would suggest). That's because that's + * frickin' ugly. But this means you really need to make sure + * to document which base you are parsing when you use this + * call. */ + + struct table { + const char *suffix; + unsigned long long factor; + }; + + static const struct table iec[] = { + { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "G", 1024ULL*1024ULL*1024ULL }, + { "M", 1024ULL*1024ULL }, + { "K", 1024ULL }, + { "B", 1ULL }, + { "", 1ULL }, + }; + + static const struct table si[] = { + { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, + { "G", 1000ULL*1000ULL*1000ULL }, + { "M", 1000ULL*1000ULL }, + { "K", 1000ULL }, + { "B", 1ULL }, + { "", 1ULL }, + }; + + const struct table *table; + const char *p; + unsigned long long r = 0; + unsigned n_entries, start_pos = 0; + + assert(t); + assert(base == 1000 || base == 1024); + assert(size); + + if (base == 1000) { + table = si; + n_entries = ELEMENTSOF(si); + } else { + table = iec; + n_entries = ELEMENTSOF(iec); + } + + p = t; + do { + unsigned long long l, tmp; + double frac = 0; + char *e; + unsigned i; + + p += strspn(p, WHITESPACE); + + errno = 0; + l = strtoull(p, &e, 10); + if (errno != 0) + return -errno; + if (e == p) + return -EINVAL; + if (*p == '-') + return -ERANGE; + + if (*e == '.') { + e++; + + /* strtoull() itself would accept space/+/- */ + if (*e >= '0' && *e <= '9') { + unsigned long long l2; + char *e2; + + l2 = strtoull(e, &e2, 10); + if (errno != 0) + return -errno; + + /* Ignore failure. E.g. 10.M is valid */ + frac = l2; + for (; e < e2; e++) + frac /= 10; + } + } + + e += strspn(e, WHITESPACE); + + for (i = start_pos; i < n_entries; i++) + if (startswith(e, table[i].suffix)) + break; + + if (i >= n_entries) + return -EINVAL; + + if (l + (frac > 0) > ULLONG_MAX / table[i].factor) + return -ERANGE; + + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); + if (tmp > ULLONG_MAX - r) + return -ERANGE; + + r += tmp; + if ((unsigned long long) (uint64_t) r != r) + return -ERANGE; + + p = e + strlen(table[i].suffix); + + start_pos = i + 1; + + } while (*p); + + *size = r; + + return 0; +} + +int parse_range(const char *t, unsigned *lower, unsigned *upper) { + _cleanup_free_ char *word = NULL; + unsigned l, u; + int r; + + assert(lower); + assert(upper); + + /* Extract the lower bound. */ + r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + r = safe_atou(word, &l); + if (r < 0) + return r; + + /* Check for the upper bound and extract it if needed */ + if (!t) + /* Single number with no dashes. */ + u = l; + else if (!*t) + /* Trailing dash is an error. */ + return -EINVAL; + else { + r = safe_atou(t, &u); + if (r < 0) + return r; + } + + *lower = l; + *upper = u; + return 0; +} + +char *format_bytes(char *buf, size_t l, uint64_t t) { + unsigned i; + + /* This only does IEC units so far */ + + static const struct { + const char *suffix; + uint64_t factor; + } table[] = { + { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "M", UINT64_C(1024)*UINT64_C(1024) }, + { "K", UINT64_C(1024) }, + }; + + if (t == (uint64_t) -1) + return NULL; + + for (i = 0; i < ELEMENTSOF(table); i++) { + + if (t >= table[i].factor) { + snprintf(buf, l, + "%" PRIu64 ".%" PRIu64 "%s", + t / table[i].factor, + ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), + table[i].suffix); + + goto finish; + } + } + + snprintf(buf, l, "%" PRIu64 "B", t); + +finish: + buf[l-1] = 0; + return buf; + +} + +int safe_atou(const char *s, unsigned *ret_u) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + /* strtoul() is happy to parse negative values, and silently + * converts them to unsigned values without generating an + * error. We want a clean error, hence let's look for the "-" + * prefix on our own, and generate an error. But let's do so + * only after strtoul() validated that the string is clean + * otherwise, so that we return EINVAL preferably over + * ERANGE. */ + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; + if ((unsigned long) (unsigned) l != l) + return -ERANGE; + + *ret_u = (unsigned) l; + return 0; +} + +int safe_atoi(const char *s, int *ret_i) { + char *x = NULL; + long l; + + assert(s); + assert(ret_i); + + errno = 0; + l = strtol(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if ((long) (int) l != l) + return -ERANGE; + + *ret_i = (int) l; + return 0; +} + +int safe_atollu(const char *s, long long unsigned *ret_llu) { + char *x = NULL; + unsigned long long l; + + assert(s); + assert(ret_llu); + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoull(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (*s == '-') + return -ERANGE; + + *ret_llu = l; + return 0; +} + +int safe_atolli(const char *s, long long int *ret_lli) { + char *x = NULL; + long long l; + + assert(s); + assert(ret_lli); + + errno = 0; + l = strtoll(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + + *ret_lli = l; + return 0; +} + +int safe_atou8(const char *s, uint8_t *ret) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret); + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; + if ((unsigned long) (uint8_t) l != l) + return -ERANGE; + + *ret = (uint8_t) l; + return 0; +} + +int safe_atou16(const char *s, uint16_t *ret) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret); + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; + if ((unsigned long) (uint16_t) l != l) + return -ERANGE; + + *ret = (uint16_t) l; + return 0; +} + +int safe_atoi16(const char *s, int16_t *ret) { + char *x = NULL; + long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtol(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if ((long) (int16_t) l != l) + return -ERANGE; + + *ret = (int16_t) l; + return 0; +} + +int safe_atod(const char *s, double *ret_d) { + char *x = NULL; + double d = 0; + locale_t loc; + + assert(s); + assert(ret_d); + + loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); + if (loc == (locale_t) 0) + return -errno; + + errno = 0; + d = strtod_l(s, &x, loc); + if (errno != 0) { + freelocale(loc); + return -errno; + } + if (!x || x == s || *x) { + freelocale(loc); + return -EINVAL; + } + + freelocale(loc); + *ret_d = (double) d; + return 0; +} diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h new file mode 100644 index 0000000000..408690d0b3 --- /dev/null +++ b/src/basic/parse-util.h @@ -0,0 +1,92 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <inttypes.h> +#include <sys/types.h> + +#include "macro.h" + +#define MODE_INVALID ((mode_t) -1) + +int parse_boolean(const char *v) _pure_; +int parse_pid(const char *s, pid_t* ret_pid); +int parse_mode(const char *s, mode_t *ret); +int parse_ifindex(const char *s, int *ret); + +int parse_size(const char *t, uint64_t base, uint64_t *size); +int parse_range(const char *t, unsigned *lower, unsigned *upper); + +#define FORMAT_BYTES_MAX 8 +char *format_bytes(char *buf, size_t l, uint64_t t); + +int safe_atou(const char *s, unsigned *ret_u); +int safe_atoi(const char *s, int *ret_i); +int safe_atollu(const char *s, unsigned long long *ret_u); +int safe_atolli(const char *s, long long int *ret_i); + +int safe_atou8(const char *s, uint8_t *ret); + +int safe_atou16(const char *s, uint16_t *ret); +int safe_atoi16(const char *s, int16_t *ret); + +static inline int safe_atou32(const char *s, uint32_t *ret_u) { + assert_cc(sizeof(uint32_t) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} + +static inline int safe_atoi32(const char *s, int32_t *ret_i) { + assert_cc(sizeof(int32_t) == sizeof(int)); + return safe_atoi(s, (int*) ret_i); +} + +static inline int safe_atou64(const char *s, uint64_t *ret_u) { + assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} + +static inline int safe_atoi64(const char *s, int64_t *ret_i) { + assert_cc(sizeof(int64_t) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_i); +} + +#if LONG_MAX == INT_MAX +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(int)); + return safe_atoi(s, (int*) ret_u); +} +#else +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_u); +} +#endif + +int safe_atod(const char *s, double *ret_d); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 5cbfc145a4..ec90c432a4 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -19,21 +19,33 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> #include <errno.h> -#include <stdlib.h> -#include <stdio.h> #include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/statvfs.h> +#include <unistd.h> -#include "macro.h" -#include "util.h" +/* When we include libgen.h because we need dirname() we immediately + * undefine basename() since libgen.h defines it as a macro to the + * POSIX version which is really broken. We prefer GNU basename(). */ +#include <libgen.h> +#undef basename + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "log.h" -#include "strv.h" -#include "path-util.h" +#include "macro.h" #include "missing.h" -#include "fileio.h" +#include "parse-util.h" +#include "path-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" bool path_is_absolute(const char *p) { return p[0] == '/'; @@ -43,61 +55,25 @@ bool is_path(const char *p) { return !!strchr(p, '/'); } -int path_get_parent(const char *path, char **_r) { - const char *e, *a = NULL, *b = NULL, *p; - char *r; - bool slash = false; - - assert(path); - assert(_r); - - if (!*path) - return -EINVAL; - - for (e = path; *e; e++) { - - if (!slash && *e == '/') { - a = b; - b = e; - slash = true; - } else if (slash && *e != '/') - slash = false; - } - - if (*(e-1) == '/') - p = a; - else - p = b; - - if (!p) - return -EINVAL; - - if (p == path) - r = strdup("/"); - else - r = strndup(path, p-path); - - if (!r) - return -ENOMEM; - - *_r = r; - return 0; -} - -char **path_split_and_make_absolute(const char *p) { +int path_split_and_make_absolute(const char *p, char ***ret) { char **l; + int r; + assert(p); + assert(ret); l = strv_split(p, ":"); if (!l) - return NULL; + return -ENOMEM; - if (!path_strv_make_absolute_cwd(l)) { + r = path_strv_make_absolute_cwd(l); + if (r < 0) { strv_free(l); - return NULL; + return r; } - return l; + *ret = l; + return r; } char *path_make_absolute(const char *p, const char *prefix) { @@ -112,22 +88,31 @@ char *path_make_absolute(const char *p, const char *prefix) { return strjoin(prefix, "/", p, NULL); } -char *path_make_absolute_cwd(const char *p) { - _cleanup_free_ char *cwd = NULL; +int path_make_absolute_cwd(const char *p, char **ret) { + char *c; assert(p); + assert(ret); /* Similar to path_make_absolute(), but prefixes with the * current working directory. */ if (path_is_absolute(p)) - return strdup(p); + c = strdup(p); + else { + _cleanup_free_ char *cwd = NULL; - cwd = get_current_dir_name(); - if (!cwd) - return NULL; + cwd = get_current_dir_name(); + if (!cwd) + return -errno; + + c = strjoin(cwd, "/", p, NULL); + } + if (!c) + return -ENOMEM; - return strjoin(cwd, "/", p, NULL); + *ret = c; + return 0; } int path_make_relative(const char *from_dir, const char *to_path, char **_r) { @@ -215,8 +200,9 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) { return 0; } -char **path_strv_make_absolute_cwd(char **l) { +int path_strv_make_absolute_cwd(char **l) { char **s; + int r; /* Goes through every item in the string list and makes it * absolute. This works in place and won't rollback any @@ -225,15 +211,15 @@ char **path_strv_make_absolute_cwd(char **l) { STRV_FOREACH(s, l) { char *t; - t = path_make_absolute_cwd(*s); - if (!t) - return NULL; + r = path_make_absolute_cwd(*s, &t); + if (r < 0) + return r; free(*s); *s = t; } - return l; + return 0; } char **path_strv_resolve(char **l, const char *prefix) { @@ -411,7 +397,7 @@ int path_compare(const char *a, const char *b) { * Which one is sorted before the other does not really matter. * Here a relative path is ordered before an absolute path. */ d = (a[0] == '/') - (b[0] == '/'); - if (d) + if (d != 0) return d; for (;;) { @@ -434,12 +420,12 @@ int path_compare(const char *a, const char *b) { /* Alphabetical sort: "/foo/aaa" before "/foo/b" */ d = memcmp(a, b, MIN(j, k)); - if (d) + if (d != 0) return (d > 0) - (d < 0); /* sign of d */ /* Sort "/foo/a" before "/foo/aaa" */ d = (j > k) - (j < k); /* sign of (j - k) */ - if (d) + if (d != 0) return d; a += j; @@ -471,294 +457,66 @@ char* path_join(const char *root, const char *path, const char *rest) { NULL); } -static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { - char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; - _cleanup_free_ char *fdinfo = NULL; - _cleanup_close_ int subfd = -1; - char *p; - int r; - - if ((flags & AT_EMPTY_PATH) && isempty(filename)) - xsprintf(path, "/proc/self/fdinfo/%i", fd); - else { - subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); - if (subfd < 0) - return -errno; - - xsprintf(path, "/proc/self/fdinfo/%i", subfd); - } - - r = read_full_file(path, &fdinfo, NULL); - if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ - return -EOPNOTSUPP; - if (r < 0) - return -errno; - - p = startswith(fdinfo, "mnt_id:"); - if (!p) { - p = strstr(fdinfo, "\nmnt_id:"); - if (!p) /* The mnt_id field is a relatively new addition */ - return -EOPNOTSUPP; - - p += 8; - } - - p += strspn(p, WHITESPACE); - p[strcspn(p, WHITESPACE)] = 0; - - return safe_atoi(p, mnt_id); -} - -int fd_is_mount_point(int fd, const char *filename, int flags) { - union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; - int mount_id = -1, mount_id_parent = -1; - bool nosupp = false, check_st_dev = true; - struct stat a, b; - int r; +int find_binary(const char *name, char **ret) { + int last_error, r; + const char *p; - assert(fd >= 0); - assert(filename); - - /* First we will try the name_to_handle_at() syscall, which - * tells us the mount id and an opaque file "handle". It is - * not supported everywhere though (kernel compile-time - * option, not all file systems are hooked up). If it works - * the mount id is usually good enough to tell us whether - * something is a mount point. - * - * If that didn't work we will try to read the mount id from - * /proc/self/fdinfo/<fd>. This is almost as good as - * name_to_handle_at(), however, does not return the - * opaque file handle. The opaque file handle is pretty useful - * to detect the root directory, which we should always - * consider a mount point. Hence we use this only as - * fallback. Exporting the mnt_id in fdinfo is a pretty recent - * kernel addition. - * - * As last fallback we do traditional fstat() based st_dev - * comparisons. This is how things were traditionally done, - * but unionfs breaks breaks this since it exposes file - * systems with a variety of st_dev reported. Also, btrfs - * subvolumes have different st_dev, even though they aren't - * real mounts of their own. */ - - r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); - if (r < 0) { - if (errno == ENOSYS) - /* This kernel does not support name_to_handle_at() - * fall back to simpler logic. */ - goto fallback_fdinfo; - else if (errno == EOPNOTSUPP) - /* This kernel or file system does not support - * name_to_handle_at(), hence let's see if the - * upper fs supports it (in which case it is a - * mount point), otherwise fallback to the - * traditional stat() logic */ - nosupp = true; - else - return -errno; - } + assert(name); - r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); - if (r < 0) { - if (errno == EOPNOTSUPP) { - if (nosupp) - /* Neither parent nor child do name_to_handle_at()? - We have no choice but to fall back. */ - goto fallback_fdinfo; - else - /* The parent can't do name_to_handle_at() but the - * directory we are interested in can? - * If so, it must be a mount point. */ - return 1; - } else + if (is_path(name)) { + if (access(name, X_OK) < 0) return -errno; - } - - /* The parent can do name_to_handle_at() but the - * directory we are interested in can't? If so, it - * must be a mount point. */ - if (nosupp) - return 1; - - /* If the file handle for the directory we are - * interested in and its parent are identical, we - * assume this is the root directory, which is a mount - * point. */ - - if (h.handle.handle_bytes == h_parent.handle.handle_bytes && - h.handle.handle_type == h_parent.handle.handle_type && - memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) - return 1; - - return mount_id != mount_id_parent; - -fallback_fdinfo: - r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); - if (r == -EOPNOTSUPP) - goto fallback_fstat; - if (r < 0) - return r; - - r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); - if (r < 0) - return r; - - if (mount_id != mount_id_parent) - return 1; - - /* Hmm, so, the mount ids are the same. This leaves one - * special case though for the root file system. For that, - * let's see if the parent directory has the same inode as we - * are interested in. Hence, let's also do fstat() checks now, - * too, but avoid the st_dev comparisons, since they aren't - * that useful on unionfs mounts. */ - check_st_dev = false; - -fallback_fstat: - /* yay for fstatat() taking a different set of flags than the other - * _at() above */ - if (flags & AT_SYMLINK_FOLLOW) - flags &= ~AT_SYMLINK_FOLLOW; - else - flags |= AT_SYMLINK_NOFOLLOW; - if (fstatat(fd, filename, &a, flags) < 0) - return -errno; - - if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) - return -errno; - - /* A directory with same device and inode as its parent? Must - * be the root directory */ - if (a.st_dev == b.st_dev && - a.st_ino == b.st_ino) - return 1; - - return check_st_dev && (a.st_dev != b.st_dev); -} -/* flags can be AT_SYMLINK_FOLLOW or 0 */ -int path_is_mount_point(const char *t, int flags) { - _cleanup_close_ int fd = -1; - _cleanup_free_ char *canonical = NULL, *parent = NULL; - int r; - - assert(t); - - if (path_equal(t, "/")) - return 1; - - /* we need to resolve symlinks manually, we can't just rely on - * fd_is_mount_point() to do that for us; if we have a structure like - * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we - * look at needs to be /usr, not /. */ - if (flags & AT_SYMLINK_FOLLOW) { - canonical = canonicalize_file_name(t); - if (!canonical) - return -errno; + if (ret) { + r = path_make_absolute_cwd(name, ret); + if (r < 0) + return r; + } - t = canonical; + return 0; } - r = path_get_parent(t, &parent); - if (r < 0) - return r; - - fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); - if (fd < 0) - return -errno; - - return fd_is_mount_point(fd, basename(t), flags); -} - -int path_is_read_only_fs(const char *path) { - struct statvfs st; - - assert(path); - - if (statvfs(path, &st) < 0) - return -errno; - - if (st.f_flag & ST_RDONLY) - return true; - - /* On NFS, statvfs() might not reflect whether we can actually - * write to the remote share. Let's try again with - * access(W_OK) which is more reliable, at least sometimes. */ - if (access(path, W_OK) < 0 && errno == EROFS) - return true; - - return false; -} - -int path_is_os_tree(const char *path) { - char *p; - int r; - - /* We use /usr/lib/os-release as flag file if something is an OS */ - p = strjoina(path, "/usr/lib/os-release"); - r = access(p, F_OK); - - if (r >= 0) - return 1; - - /* Also check for the old location in /etc, just in case. */ - p = strjoina(path, "/etc/os-release"); - r = access(p, F_OK); - - return r >= 0; -} - -int find_binary(const char *name, bool local, char **filename) { - assert(name); + /** + * Plain getenv, not secure_getenv, because we want + * to actually allow the user to pick the binary. + */ + p = getenv("PATH"); + if (!p) + p = DEFAULT_PATH; - if (is_path(name)) { - if (local && access(name, X_OK) < 0) - return -errno; + last_error = -ENOENT; - if (filename) { - char *p; + for (;;) { + _cleanup_free_ char *j = NULL, *element = NULL; - p = path_make_absolute_cwd(name); - if (!p) - return -ENOMEM; + r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + break; - *filename = p; - } + if (!path_is_absolute(element)) + continue; - return 0; - } else { - const char *path; - const char *word, *state; - size_t l; - - /** - * Plain getenv, not secure_getenv, because we want - * to actually allow the user to pick the binary. - */ - path = getenv("PATH"); - if (!path) - path = DEFAULT_PATH; - - FOREACH_WORD_SEPARATOR(word, l, path, ":", state) { - _cleanup_free_ char *p = NULL; - - if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0) - return -ENOMEM; + j = strjoin(element, "/", name, NULL); + if (!j) + return -ENOMEM; - if (access(p, X_OK) < 0) - continue; + if (access(j, X_OK) >= 0) { + /* Found it! */ - if (filename) { - *filename = path_kill_slashes(p); - p = NULL; + if (ret) { + *ret = path_kill_slashes(j); + j = NULL; } return 0; } - return -ENOENT; + last_error = -errno; } + + return last_error; } bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) { @@ -796,14 +554,13 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd return changed; } -int fsck_exists(const char *fstype) { +static int binary_is_good(const char *binary) { _cleanup_free_ char *p = NULL, *d = NULL; - const char *checker; int r; - checker = strjoina("fsck.", fstype); - - r = find_binary(checker, true, &p); + r = find_binary(binary, &p); + if (r == -ENOENT) + return 0; if (r < 0) return r; @@ -811,13 +568,39 @@ int fsck_exists(const char *fstype) { * fsck */ r = readlink_malloc(p, &d); - if (r >= 0 && - (path_equal(d, "/bin/true") || - path_equal(d, "/usr/bin/true") || - path_equal(d, "/dev/null"))) - return -ENOENT; + if (r == -EINVAL) /* not a symlink */ + return 1; + if (r < 0) + return r; - return 0; + return !path_equal(d, "true") && + !path_equal(d, "/bin/true") && + !path_equal(d, "/usr/bin/true") && + !path_equal(d, "/dev/null"); +} + +int fsck_exists(const char *fstype) { + const char *checker; + + assert(fstype); + + if (streq(fstype, "auto")) + return -EINVAL; + + checker = strjoina("fsck.", fstype); + return binary_is_good(checker); +} + +int mkfs_exists(const char *fstype) { + const char *mkfs; + + assert(fstype); + + if (streq(fstype, "auto")) + return -EINVAL; + + mkfs = strjoina("mkfs.", fstype); + return binary_is_good(mkfs); } char *prefix_root(const char *root, const char *path) { @@ -853,3 +636,166 @@ char *prefix_root(const char *root, const char *path) { strcpy(p, path); return n; } + +int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) { + char *p; + int r; + + /* + * This function is intended to be used in command line + * parsers, to handle paths that are passed in. It makes the + * path absolute, and reduces it to NULL if omitted or + * root (the latter optionally). + * + * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON + * SUCCESS! Hence, do not pass in uninitialized pointers. + */ + + if (isempty(path)) { + *arg = mfree(*arg); + return 0; + } + + r = path_make_absolute_cwd(path, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); + + path_kill_slashes(p); + if (suppress_root && path_equal(p, "/")) + p = mfree(p); + + free(*arg); + *arg = p; + return 0; +} + +char* dirname_malloc(const char *path) { + char *d, *dir, *dir2; + + assert(path); + + d = strdup(path); + if (!d) + return NULL; + + dir = dirname(d); + assert(dir); + + if (dir == d) + return d; + + dir2 = strdup(dir); + free(d); + + return dir2; +} + +bool filename_is_valid(const char *p) { + const char *e; + + if (isempty(p)) + return false; + + if (streq(p, ".")) + return false; + + if (streq(p, "..")) + return false; + + e = strchrnul(p, '/'); + if (*e != 0) + return false; + + if (e - p > FILENAME_MAX) + return false; + + return true; +} + +bool path_is_safe(const char *p) { + + if (isempty(p)) + return false; + + if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) + return false; + + if (strlen(p)+1 > PATH_MAX) + return false; + + /* The following two checks are not really dangerous, but hey, they still are confusing */ + if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) + return false; + + if (strstr(p, "//")) + return false; + + return true; +} + +char *file_in_same_dir(const char *path, const char *filename) { + char *e, *ret; + size_t k; + + assert(path); + assert(filename); + + /* This removes the last component of path and appends + * filename, unless the latter is absolute anyway or the + * former isn't */ + + if (path_is_absolute(filename)) + return strdup(filename); + + e = strrchr(path, '/'); + if (!e) + return strdup(filename); + + k = strlen(filename); + ret = new(char, (e + 1 - path) + k + 1); + if (!ret) + return NULL; + + memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1); + return ret; +} + +bool hidden_file_allow_backup(const char *filename) { + assert(filename); + + return + filename[0] == '.' || + streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || + endswith(filename, ".rpmnew") || + endswith(filename, ".rpmsave") || + endswith(filename, ".rpmorig") || + endswith(filename, ".dpkg-old") || + endswith(filename, ".dpkg-new") || + endswith(filename, ".dpkg-tmp") || + endswith(filename, ".dpkg-dist") || + endswith(filename, ".dpkg-bak") || + endswith(filename, ".dpkg-backup") || + endswith(filename, ".dpkg-remove") || + endswith(filename, ".swp"); +} + +bool hidden_file(const char *filename) { + assert(filename); + + if (endswith(filename, "~")) + return true; + + return hidden_file_allow_backup(filename); +} + +bool is_device_path(const char *path) { + + /* Returns true on paths that refer to a device, either in + * sysfs or in /dev */ + + return + path_startswith(path, "/dev/") || + path_startswith(path, "/sys/"); +} diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 1eac89c51b..989e0f9004 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -36,11 +36,10 @@ #endif bool is_path(const char *p) _pure_; -char** path_split_and_make_absolute(const char *p); -int path_get_parent(const char *path, char **parent); +int path_split_and_make_absolute(const char *p, char ***ret); bool path_is_absolute(const char *p) _pure_; char* path_make_absolute(const char *p, const char *prefix); -char* path_make_absolute_cwd(const char *p); +int path_make_absolute_cwd(const char *p, char **ret); int path_make_relative(const char *from_dir, const char *to_path, char **_r); char* path_kill_slashes(char *path); char* path_startswith(const char *path, const char *prefix) _pure_; @@ -49,20 +48,16 @@ bool path_equal(const char *a, const char *b) _pure_; bool path_equal_or_files_same(const char *a, const char *b); char* path_join(const char *root, const char *path, const char *rest); -char** path_strv_make_absolute_cwd(char **l); +int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *prefix); char** path_strv_resolve_uniq(char **l, const char *prefix); -int fd_is_mount_point(int fd, const char *filename, int flags); -int path_is_mount_point(const char *path, int flags); -int path_is_read_only_fs(const char *path); -int path_is_os_tree(const char *path); - -int find_binary(const char *name, bool local, char **filename); +int find_binary(const char *name, char **filename); bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); int fsck_exists(const char *fstype); +int mkfs_exists(const char *fstype); /* Iterates through the path prefixes of the specified path, going up * the tree, to root. Also returns "" (and not "/"!) for the root @@ -100,3 +95,17 @@ char *prefix_root(const char *root, const char *path); } \ _ret; \ }) + +int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg); + +char* dirname_malloc(const char *path); + +bool filename_is_valid(const char *p) _pure_; +bool path_is_safe(const char *p) _pure_; + +char *file_in_same_dir(const char *path, const char *filename); + +bool hidden_file_allow_backup(const char *filename); +bool hidden_file(const char *filename) _pure_; + +bool is_device_path(const char *path); diff --git a/src/basic/prioq.c b/src/basic/prioq.c index d55b348c22..7590698911 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -29,8 +29,9 @@ * The underlying algorithm used in this implementation is a Heap. */ -#include "util.h" +#include "alloc-util.h" #include "prioq.h" +#include "util.h" struct prioq_item { void *data; diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c new file mode 100644 index 0000000000..4464573c5b --- /dev/null +++ b/src/basic/proc-cmdline.c @@ -0,0 +1,174 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "extract-word.h" +#include "fileio.h" +#include "macro.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "special.h" +#include "string-util.h" +#include "util.h" +#include "virt.h" + +int proc_cmdline(char **ret) { + assert(ret); + + if (detect_container() > 0) + return get_process_cmdline(1, 0, false, ret); + else + return read_one_line_file("/proc/cmdline", ret); +} + +int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { + _cleanup_free_ char *line = NULL; + const char *p; + int r; + + assert(parse_item); + + r = proc_cmdline(&line); + if (r < 0) + return r; + + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + char *value = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + if (r < 0) + return r; + if (r == 0) + break; + + /* Filter out arguments that are intended only for the + * initrd */ + if (!in_initrd() && startswith(word, "rd.")) + continue; + + value = strchr(word, '='); + if (value) + *(value++) = 0; + + r = parse_item(word, value); + if (r < 0) + return r; + } + + return 0; +} + +int get_proc_cmdline_key(const char *key, char **value) { + _cleanup_free_ char *line = NULL, *ret = NULL; + bool found = false; + const char *p; + int r; + + assert(key); + + r = proc_cmdline(&line); + if (r < 0) + return r; + + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + const char *e; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + if (r < 0) + return r; + if (r == 0) + break; + + /* Filter out arguments that are intended only for the + * initrd */ + if (!in_initrd() && startswith(word, "rd.")) + continue; + + if (value) { + e = startswith(word, key); + if (!e) + continue; + + r = free_and_strdup(&ret, e); + if (r < 0) + return r; + + found = true; + } else { + if (streq(word, key)) + found = true; + } + } + + if (value) { + *value = ret; + ret = NULL; + } + + return found; + +} + +int shall_restore_state(void) { + _cleanup_free_ char *value = NULL; + int r; + + r = get_proc_cmdline_key("systemd.restore_state=", &value); + if (r < 0) + return r; + if (r == 0) + return true; + + return parse_boolean(value); +} + +static const char * const rlmap[] = { + "emergency", SPECIAL_EMERGENCY_TARGET, + "-b", SPECIAL_EMERGENCY_TARGET, + "rescue", SPECIAL_RESCUE_TARGET, + "single", SPECIAL_RESCUE_TARGET, + "-s", SPECIAL_RESCUE_TARGET, + "s", SPECIAL_RESCUE_TARGET, + "S", SPECIAL_RESCUE_TARGET, + "1", SPECIAL_RESCUE_TARGET, + "2", SPECIAL_MULTI_USER_TARGET, + "3", SPECIAL_MULTI_USER_TARGET, + "4", SPECIAL_MULTI_USER_TARGET, + "5", SPECIAL_GRAPHICAL_TARGET, +}; + +const char* runlevel_to_target(const char *word) { + size_t i; + + if (!word) + return NULL; + + for (i = 0; i < ELEMENTSOF(rlmap); i += 2) + if (streq(word, rlmap[i])) + return rlmap[i+1]; + + return NULL; +} diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h new file mode 100644 index 0000000000..ce6e84995a --- /dev/null +++ b/src/basic/proc-cmdline.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +int proc_cmdline(char **ret); +int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value)); +int get_proc_cmdline_key(const char *parameter, char **value); + +int shall_restore_state(void); +const char* runlevel_to_target(const char *rl); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index d8a94a4572..7631928d5f 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -17,22 +17,33 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> -#include <sys/types.h> -#include <string.h> -#include <stdio.h> #include <assert.h> +#include <ctype.h> #include <errno.h> -#include <unistd.h> -#include <sys/wait.h> +#include <sched.h> #include <signal.h> -#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/personality.h> +#include <sys/prctl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" -#include "util.h" +#include "fs-util.h" +#include "ioprio.h" #include "log.h" -#include "signal-util.h" #include "process-util.h" +#include "signal-util.h" +#include "string-table.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" int get_process_state(pid_t pid) { const char *p; @@ -174,6 +185,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return 0; } +void rename_process(const char name[8]) { + assert(name); + + /* This is a like a poor man's setproctitle(). It changes the + * comm field, argv[0], and also the glibc's internally used + * name of the process. For the first one a limit of 16 chars + * applies, to the second one usually one of 10 (i.e. length + * of "/sbin/init"), to the third one one of 7 (i.e. length of + * "systemd"). If you pass a longer string it will be + * truncated */ + + prctl(PR_SET_NAME, name); + + if (program_invocation_name) + strncpy(program_invocation_name, name, strlen(program_invocation_name)); + + if (saved_argc > 0) { + int i; + + if (saved_argv[0]) + strncpy(saved_argv[0], name, strlen(saved_argv[0])); + + for (i = 1; i < saved_argc; i++) { + if (!saved_argv[i]) + break; + + memzero(saved_argv[i], strlen(saved_argv[i])); + } + } +} + int is_kernel_thread(pid_t pid) { const char *p; size_t count; @@ -364,7 +406,7 @@ int get_process_environ(pid_t pid, char **env) { return 0; } -int get_parent_of_pid(pid_t pid, pid_t *_ppid) { +int get_process_ppid(pid_t pid, pid_t *_ppid) { int r; _cleanup_free_ char *line = NULL; long unsigned ppid; @@ -476,6 +518,16 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod return -EPROTO; } +void sigkill_wait(pid_t *pid) { + if (!pid) + return; + if (*pid <= 1) + return; + + if (kill(*pid, SIGKILL) > 0) + (void) wait_for_terminate(*pid, NULL); +} + int kill_and_sigcont(pid_t pid, int sig) { int r; @@ -547,9 +599,12 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { bool pid_is_unwaited(pid_t pid) { /* Checks whether a PID is still valid at all, including a zombie */ - if (pid <= 0) + if (pid < 0) return false; + if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */ + return true; + if (kill(pid, 0) >= 0) return true; @@ -561,12 +616,141 @@ bool pid_is_alive(pid_t pid) { /* Checks whether a PID is still valid and not a zombie */ - if (pid <= 0) + if (pid < 0) return false; + if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */ + return true; + r = get_process_state(pid); if (r == -ESRCH || r == 'Z') return false; return true; } + +bool is_main_thread(void) { + static thread_local int cached = 0; + + if (_unlikely_(cached == 0)) + cached = getpid() == gettid() ? 1 : -1; + + return cached > 0; +} + +noreturn void freeze(void) { + + /* Make sure nobody waits for us on a socket anymore */ + close_all_fds(NULL, 0); + + sync(); + + for (;;) + pause(); +} + +bool oom_score_adjust_is_valid(int oa) { + return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX; +} + +unsigned long personality_from_string(const char *p) { + + /* Parse a personality specifier. We introduce our own + * identifiers that indicate specific ABIs, rather than just + * hints regarding the register size, since we want to keep + * things open for multiple locally supported ABIs for the + * same register size. We try to reuse the ABI identifiers + * used by libseccomp. */ + +#if defined(__x86_64__) + + if (streq(p, "x86")) + return PER_LINUX32; + + if (streq(p, "x86-64")) + return PER_LINUX; + +#elif defined(__i386__) + + if (streq(p, "x86")) + return PER_LINUX; + +#elif defined(__s390x__) + + if (streq(p, "s390")) + return PER_LINUX32; + + if (streq(p, "s390x")) + return PER_LINUX; + +#elif defined(__s390__) + + if (streq(p, "s390")) + return PER_LINUX; +#endif + + return PERSONALITY_INVALID; +} + +const char* personality_to_string(unsigned long p) { + +#if defined(__x86_64__) + + if (p == PER_LINUX32) + return "x86"; + + if (p == PER_LINUX) + return "x86-64"; + +#elif defined(__i386__) + + if (p == PER_LINUX) + return "x86"; + +#elif defined(__s390x__) + + if (p == PER_LINUX) + return "s390x"; + + if (p == PER_LINUX32) + return "s390"; + +#elif defined(__s390__) + + if (p == PER_LINUX) + return "s390"; + +#endif + + return NULL; +} + +static const char *const ioprio_class_table[] = { + [IOPRIO_CLASS_NONE] = "none", + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", + [IOPRIO_CLASS_IDLE] = "idle" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); + +static const char *const sigchld_code_table[] = { + [CLD_EXITED] = "exited", + [CLD_KILLED] = "killed", + [CLD_DUMPED] = "dumped", + [CLD_TRAPPED] = "trapped", + [CLD_STOPPED] = "stopped", + [CLD_CONTINUED] = "continued", +}; + +DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); + +static const char* const sched_policy_table[] = { + [SCHED_OTHER] = "other", + [SCHED_BATCH] = "batch", + [SCHED_IDLE] = "idle", + [SCHED_FIFO] = "fifo", + [SCHED_RR] = "rr" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 07431d043b..72633ebf70 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -27,6 +27,7 @@ #include <signal.h> #include "formats-util.h" +#include "macro.h" #define procfs_file_alloca(pid, field) \ ({ \ @@ -51,15 +52,48 @@ int get_process_capeff(pid_t pid, char **capeff); int get_process_cwd(pid_t pid, char **cwd); int get_process_root(pid_t pid, char **root); int get_process_environ(pid_t pid, char **environ); +int get_process_ppid(pid_t pid, pid_t *ppid); int wait_for_terminate(pid_t pid, siginfo_t *status); int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code); +void sigkill_wait(pid_t *pid); +#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait) + int kill_and_sigcont(pid_t pid, int sig); -pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); + void rename_process(const char name[8]); int is_kernel_thread(pid_t pid); + int getenv_for_pid(pid_t pid, const char *field, char **_value); bool pid_is_alive(pid_t pid); bool pid_is_unwaited(pid_t pid); + +bool is_main_thread(void); + +noreturn void freeze(void); + +bool oom_score_adjust_is_valid(int oa); + +#ifndef PERSONALITY_INVALID +/* personality(7) documents that 0xffffffffUL is used for querying the + * current personality, hence let's use that here as error + * indicator. */ +#define PERSONALITY_INVALID 0xffffffffLU +#endif + +unsigned long personality_from_string(const char *p); +const char *personality_to_string(unsigned long); + +int ioprio_class_to_string_alloc(int i, char **s); +int ioprio_class_from_string(const char *s); + +const char *sigchld_code_to_string(int i) _const_; +int sigchld_code_from_string(const char *s) _pure_; + +int sched_policy_to_string_alloc(int i, char **s); +int sched_policy_from_string(const char *s); + +#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) +#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) diff --git a/src/basic/random-util.c b/src/basic/random-util.c index b230044f50..2f5c16e2af 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -17,20 +17,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdint.h> #include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> -#include <time.h> +#include <linux/random.h> +#include <stdint.h> #ifdef HAVE_SYS_AUXV_H #include <sys/auxv.h> #endif -#include <linux/random.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include "fd-util.h" +#include "io-util.h" +#include "missing.h" #include "random-util.h" #include "time-util.h" -#include "missing.h" #include "util.h" int dev_urandom(void *p, size_t n) { diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c index 478fc43a38..bf757cbc48 100644 --- a/src/basic/replace-var.c +++ b/src/basic/replace-var.c @@ -21,10 +21,11 @@ #include <string.h> +#include "alloc-util.h" #include "macro.h" -#include "util.h" #include "replace-var.h" -#include "def.h" +#include "string-util.h" +#include "util.h" /* * Generic infrastructure for replacing @FOO@ style variables in diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c new file mode 100644 index 0000000000..2627c813fc --- /dev/null +++ b/src/basic/rlimit-util.c @@ -0,0 +1,70 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "missing.h" +#include "rlimit-util.h" +#include "string-table.h" +#include "util.h" + +int setrlimit_closest(int resource, const struct rlimit *rlim) { + struct rlimit highest, fixed; + + assert(rlim); + + if (setrlimit(resource, rlim) >= 0) + return 0; + + if (errno != EPERM) + return -errno; + + /* So we failed to set the desired setrlimit, then let's try + * to get as close as we can */ + assert_se(getrlimit(resource, &highest) == 0); + + fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); + fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); + + if (setrlimit(resource, &fixed) < 0) + return -errno; + + return 0; +} + +static const char* const rlimit_table[_RLIMIT_MAX] = { + [RLIMIT_CPU] = "LimitCPU", + [RLIMIT_FSIZE] = "LimitFSIZE", + [RLIMIT_DATA] = "LimitDATA", + [RLIMIT_STACK] = "LimitSTACK", + [RLIMIT_CORE] = "LimitCORE", + [RLIMIT_RSS] = "LimitRSS", + [RLIMIT_NOFILE] = "LimitNOFILE", + [RLIMIT_AS] = "LimitAS", + [RLIMIT_NPROC] = "LimitNPROC", + [RLIMIT_MEMLOCK] = "LimitMEMLOCK", + [RLIMIT_LOCKS] = "LimitLOCKS", + [RLIMIT_SIGPENDING] = "LimitSIGPENDING", + [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", + [RLIMIT_NICE] = "LimitNICE", + [RLIMIT_RTPRIO] = "LimitRTPRIO", + [RLIMIT_RTTIME] = "LimitRTTIME" +}; + +DEFINE_STRING_TABLE_LOOKUP(rlimit, int); diff --git a/src/core/snapshot.h b/src/basic/rlimit-util.h index 97747e18bd..262f86dd04 100644 --- a/src/core/snapshot.h +++ b/src/basic/rlimit-util.h @@ -21,17 +21,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -typedef struct Snapshot Snapshot; +#include <sys/resource.h> -struct Snapshot { - Unit meta; +#include "macro.h" - SnapshotState state, deserialized_state; +const char *rlimit_to_string(int i) _const_; +int rlimit_from_string(const char *s) _pure_; - bool cleanup; -}; +int setrlimit_closest(int resource, const struct rlimit *rlim); -extern const UnitVTable snapshot_vtable; - -int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s); -void snapshot_remove(Snapshot *s); +#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index dbbe817684..8ec7dd75ee 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -19,10 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "path-util.h" #include "btrfs-util.h" +#include "fd-util.h" +#include "mount-util.h" +#include "path-util.h" #include "rm-rf.h" +#include "stat-util.h" +#include "string-util.h" +#include "util.h" int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { _cleanup_closedir_ DIR *d = NULL; @@ -120,7 +124,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { /* This could be a subvolume, try to remove it */ - r = btrfs_subvol_remove_fd(fd, de->d_name, true); + r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (r < 0) { if (r != -ENOTTY && r != -EINVAL) { if (ret == 0) @@ -178,7 +182,7 @@ int rm_rf(const char *path, RemoveFlags flags) { if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) { /* Try to remove as subvolume first */ - r = btrfs_subvol_remove(path, true); + r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (r >= 0) return r; diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 747e6f4dbb..a821a3d5bb 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -29,6 +29,7 @@ #include <selinux/context.h> #endif +#include "alloc-util.h" #include "strv.h" #include "path-util.h" #include "selinux-util.h" @@ -171,15 +172,15 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { int mac_selinux_apply(const char *path, const char *label) { #ifdef HAVE_SELINUX - assert(path); - assert(label); - if (!mac_selinux_use()) return 0; + assert(path); + assert(label); + if (setfilecon(path, (security_context_t) label) < 0) { log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path); - if (security_getenforce() == 1) + if (security_getenforce() > 0) return -errno; } #endif @@ -312,10 +313,10 @@ char* mac_selinux_free(char *label) { } int mac_selinux_create_file_prepare(const char *path, mode_t mode) { - int r = 0; #ifdef HAVE_SELINUX _cleanup_security_context_free_ security_context_t filecon = NULL; + int r; assert(path); @@ -325,34 +326,33 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) { if (path_is_absolute(path)) r = selabel_lookup_raw(label_hnd, &filecon, path, mode); else { - _cleanup_free_ char *newpath; + _cleanup_free_ char *newpath = NULL; - newpath = path_make_absolute_cwd(path); - if (!newpath) - return -ENOMEM; + r = path_make_absolute_cwd(path, &newpath); + if (r < 0) + return r; r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode); } - /* No context specified by the policy? Proceed without setting it. */ - if (r < 0 && errno == ENOENT) - return 0; + if (r < 0) { + /* No context specified by the policy? Proceed without setting it. */ + if (errno == ENOENT) + return 0; - if (r < 0) - r = -errno; - else { - r = setfscreatecon(filecon); - if (r < 0) { - log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); - r = -errno; - } + log_enforcing("Failed to determine SELinux security context for %s: %m", path); + } else { + if (setfscreatecon(filecon) >= 0) + return 0; /* Success! */ + + log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); } - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif + if (security_getenforce() > 0) + return -errno; - return r; +#endif + return 0; } void mac_selinux_create_file_clear(void) { @@ -405,6 +405,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { #ifdef HAVE_SELINUX _cleanup_security_context_free_ security_context_t fcon = NULL; const struct sockaddr_un *un; + bool context_changed = false; char *path; int r; @@ -420,7 +421,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { goto skipped; /* Filter out anonymous sockets */ - if (addrlen < sizeof(sa_family_t) + 1) + if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1) goto skipped; /* Filter out abstract namespace sockets */ @@ -433,36 +434,44 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { if (path_is_absolute(path)) r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); else { - _cleanup_free_ char *newpath; + _cleanup_free_ char *newpath = NULL; - newpath = path_make_absolute_cwd(path); - if (!newpath) - return -ENOMEM; + r = path_make_absolute_cwd(path, &newpath); + if (r < 0) + return r; r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); } - if (r == 0) - r = setfscreatecon(fcon); + if (r < 0) { + /* No context specified by the policy? Proceed without setting it */ + if (errno == ENOENT) + goto skipped; - if (r < 0 && errno != ENOENT) { - log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); + log_enforcing("Failed to determine SELinux security context for %s: %m", path); + if (security_getenforce() > 0) + return -errno; - if (security_getenforce() == 1) { - r = -errno; - goto finish; - } + } else { + if (setfscreatecon(fcon) < 0) { + log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); + if (security_getenforce() > 0) + return -errno; + } else + context_changed = true; } - r = bind(fd, addr, addrlen); - if (r < 0) - r = -errno; + r = bind(fd, addr, addrlen) < 0 ? -errno : 0; + + if (context_changed) + setfscreatecon(NULL); -finish: - setfscreatecon(NULL); return r; skipped: #endif - return bind(fd, addr, addrlen) < 0 ? -errno : 0; + if (bind(fd, addr, addrlen) < 0) + return -errno; + + return 0; } diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 90abe8af81..8038bc891d 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -19,8 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "parse-util.h" #include "signal-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" int reset_all_signal_handlers(void) { static const struct sigaction sa = { @@ -266,3 +269,7 @@ int signal_from_string_try_harder(const char *s) { return signo; } + +void nop_signal_handler(int sig) { + /* nothing here */ +} diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index 5e6eb50b07..e7393e2dac 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -39,3 +39,5 @@ const char *signal_to_string(int i) _const_; int signal_from_string(const char *s) _pure_; int signal_from_string_try_harder(const char *s); + +void nop_signal_handler(int sig); diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index 5f570ff02a..fcc046098d 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -23,11 +23,14 @@ #include <sys/xattr.h> -#include "util.h" -#include "process-util.h" -#include "path-util.h" +#include "alloc-util.h" #include "fileio.h" +#include "path-util.h" +#include "process-util.h" #include "smack-util.h" +#include "string-table.h" +#include "util.h" +#include "xattr-util.h" #ifdef HAVE_SMACK bool mac_smack_use(void) { diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 937124cc02..e5d4efc719 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -19,18 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> #include <errno.h> -#include <sys/stat.h> #include <stddef.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" #include "macro.h" -#include "util.h" -#include "mkdir.h" #include "missing.h" +#include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" +#include "util.h" int socket_address_listen( const SocketAddress *a, diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 8fd3149276..1acab1ef95 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -19,23 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> -#include <errno.h> #include <arpa/inet.h> -#include <stdio.h> +#include <errno.h> #include <net/if.h> -#include <sys/types.h> -#include <stddef.h> #include <netdb.h> +#include <netinet/ip.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" #include "macro.h" +#include "missing.h" +#include "parse-util.h" #include "path-util.h" -#include "util.h" #include "socket-util.h" -#include "missing.h" -#include "fileio.h" -#include "formats-util.h" +#include "string-table.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" int socket_address_parse(SocketAddress *a, const char *s) { char *e, *n; @@ -749,21 +756,182 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b return false; } -char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { - assert(addr); - assert(buffer); +int fd_inc_sndbuf(int fd, size_t n) { + int r, value; + socklen_t l = sizeof(value); - /* Like ether_ntoa() but uses %02x instead of %x to print - * ethernet addresses, which makes them look less funny. Also, - * doesn't use a static buffer. */ + r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + return 0; - sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", - addr->ether_addr_octet[0], - addr->ether_addr_octet[1], - addr->ether_addr_octet[2], - addr->ether_addr_octet[3], - addr->ether_addr_octet[4], - addr->ether_addr_octet[5]); + /* If we have the privileges we will ignore the kernel limit. */ + + value = (int) n; + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) + return -errno; + + return 1; +} + +int fd_inc_rcvbuf(int fd, size_t n) { + int r, value; + socklen_t l = sizeof(value); + + r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + return 0; + + /* If we have the privileges we will ignore the kernel limit. */ + + value = (int) n; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) + return -errno; + return 1; +} + +static const char* const ip_tos_table[] = { + [IPTOS_LOWDELAY] = "low-delay", + [IPTOS_THROUGHPUT] = "throughput", + [IPTOS_RELIABILITY] = "reliability", + [IPTOS_LOWCOST] = "low-cost", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); + +int getpeercred(int fd, struct ucred *ucred) { + socklen_t n = sizeof(struct ucred); + struct ucred u; + int r; + + assert(fd >= 0); + assert(ucred); + + r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); + if (r < 0) + return -errno; + + if (n != sizeof(struct ucred)) + return -EIO; + + /* Check if the data is actually useful and not suppressed due + * to namespacing issues */ + if (u.pid <= 0) + return -ENODATA; + if (u.uid == UID_INVALID) + return -ENODATA; + if (u.gid == GID_INVALID) + return -ENODATA; + + *ucred = u; + return 0; +} + +int getpeersec(int fd, char **ret) { + socklen_t n = 64; + char *s; + int r; + + assert(fd >= 0); + assert(ret); + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + + if (errno != ERANGE) + return -errno; + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + return -errno; + } + } + + if (isempty(s)) { + free(s); + return -EOPNOTSUPP; + } + + *ret = s; + return 0; +} + +int send_one_fd(int transport_fd, int fd, int flags) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + + assert(transport_fd >= 0); + assert(fd >= 0); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = CMSG_SPACE(sizeof(int)); + if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0) + return -errno; + + return 0; +} + +int receive_one_fd(int transport_fd, int flags) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg, *found = NULL; + + assert(transport_fd >= 0); + + /* + * Receive a single FD via @transport_fd. We don't care for + * the transport-type. We retrieve a single FD at most, so for + * packet-based transports, the caller must ensure to send + * only a single FD per packet. This is best used in + * combination with send_one_fd(). + */ + + if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0) + return -errno; + + CMSG_FOREACH(cmsg, &mh) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS && + cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + assert(!found); + found = cmsg; + break; + } + } + + if (!found) { + cmsg_close_all(&mh); + return -EIO; + } - return buffer; + return *(int*) CMSG_DATA(found); } diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 6b0ce7836f..c60f2556af 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -116,6 +116,17 @@ int netlink_family_from_string(const char *s) _pure_; bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b); -#define ETHER_ADDR_TO_STRING_MAX (3*6) +int fd_inc_sndbuf(int fd, size_t n); +int fd_inc_rcvbuf(int fd, size_t n); -char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); +int ip_tos_to_string_alloc(int i, char **s); +int ip_tos_from_string(const char *s); + +int getpeercred(int fd, struct ucred *ucred); +int getpeersec(int fd, char **ret); + +int send_one_fd(int transport_fd, int fd, int flags); +int receive_one_fd(int transport_fd, int flags); + +#define CMSG_FOREACH(cmsg, mh) \ + for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c new file mode 100644 index 0000000000..3bc66b3be7 --- /dev/null +++ b/src/basic/stat-util.c @@ -0,0 +1,216 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <linux/magic.h> +#include <sys/statvfs.h> +#include <unistd.h> + +#include "dirent-util.h" +#include "fd-util.h" +#include "macro.h" +#include "missing.h" +#include "stat-util.h" +#include "string-util.h" + +int is_symlink(const char *path) { + struct stat info; + + assert(path); + + if (lstat(path, &info) < 0) + return -errno; + + return !!S_ISLNK(info.st_mode); +} + +int is_dir(const char* path, bool follow) { + struct stat st; + int r; + + assert(path); + + if (follow) + r = stat(path, &st); + else + r = lstat(path, &st); + if (r < 0) + return -errno; + + return !!S_ISDIR(st.st_mode); +} + +int is_device_node(const char *path) { + struct stat info; + + assert(path); + + if (lstat(path, &info) < 0) + return -errno; + + return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); +} + +int dir_is_empty(const char *path) { + _cleanup_closedir_ DIR *d; + struct dirent *de; + + d = opendir(path); + if (!d) + return -errno; + + FOREACH_DIRENT(de, d, return -errno) + return 0; + + return 1; +} + +bool null_or_empty(struct stat *st) { + assert(st); + + if (S_ISREG(st->st_mode) && st->st_size <= 0) + return true; + + /* We don't want to hardcode the major/minor of /dev/null, + * hence we do a simpler "is this a device node?" check. */ + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) + return true; + + return false; +} + +int null_or_empty_path(const char *fn) { + struct stat st; + + assert(fn); + + if (stat(fn, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +int null_or_empty_fd(int fd) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +int path_is_read_only_fs(const char *path) { + struct statvfs st; + + assert(path); + + if (statvfs(path, &st) < 0) + return -errno; + + if (st.f_flag & ST_RDONLY) + return true; + + /* On NFS, statvfs() might not reflect whether we can actually + * write to the remote share. Let's try again with + * access(W_OK) which is more reliable, at least sometimes. */ + if (access(path, W_OK) < 0 && errno == EROFS) + return true; + + return false; +} + +int path_is_os_tree(const char *path) { + char *p; + int r; + + assert(path); + + /* We use /usr/lib/os-release as flag file if something is an OS */ + p = strjoina(path, "/usr/lib/os-release"); + r = access(p, F_OK); + if (r >= 0) + return 1; + + /* Also check for the old location in /etc, just in case. */ + p = strjoina(path, "/etc/os-release"); + r = access(p, F_OK); + + return r >= 0; +} + +int files_same(const char *filea, const char *fileb) { + struct stat a, b; + + assert(filea); + assert(fileb); + + if (stat(filea, &a) < 0) + return -errno; + + if (stat(fileb, &b) < 0) + return -errno; + + return a.st_dev == b.st_dev && + a.st_ino == b.st_ino; +} + +bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { + assert(s); + assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type)); + + return F_TYPE_EQUAL(s->f_type, magic_value); +} + +int fd_check_fstype(int fd, statfs_f_type_t magic_value) { + struct statfs s; + + if (fstatfs(fd, &s) < 0) + return -errno; + + return is_fs_type(&s, magic_value); +} + +int path_check_fstype(const char *path, statfs_f_type_t magic_value) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + return fd_check_fstype(fd, magic_value); +} + +bool is_temporary_fs(const struct statfs *s) { + return is_fs_type(s, TMPFS_MAGIC) || + is_fs_type(s, RAMFS_MAGIC); +} + +int fd_is_temporary_fs(int fd) { + struct statfs s; + + if (fstatfs(fd, &s) < 0) + return -errno; + + return is_temporary_fs(&s); +} diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h new file mode 100644 index 0000000000..909b220a24 --- /dev/null +++ b/src/basic/stat-util.h @@ -0,0 +1,70 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/vfs.h> + +#include "macro.h" + +int is_symlink(const char *path); +int is_dir(const char *path, bool follow); +int is_device_node(const char *path); + +int dir_is_empty(const char *path); + +static inline int dir_is_populated(const char *path) { + int r; + r = dir_is_empty(path); + if (r < 0) + return r; + return !r; +} + +bool null_or_empty(struct stat *st) _pure_; +int null_or_empty_path(const char *fn); +int null_or_empty_fd(int fd); + +int path_is_read_only_fs(const char *path); +int path_is_os_tree(const char *path); + +int files_same(const char *filea, const char *fileb); + +/* The .f_type field of struct statfs is really weird defined on + * different archs. Let's use our own type we know is sufficiently + * larger to store the possible values. */ +typedef long statfs_f_type_t; + +bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_; +int fd_check_fstype(int fd, statfs_f_type_t magic_value); +int path_check_fstype(const char *path, statfs_f_type_t magic_value); + +bool is_temporary_fs(const struct statfs *s) _pure_; +int fd_is_temporary_fs(int fd); + +/* Because statfs.t_type can be int on some architectures, we have to cast + * the const magic to the type, otherwise the compiler warns about + * signed/unsigned comparison, because the magic can be 32 bit unsigned. + */ +#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h new file mode 100644 index 0000000000..b36e8a947e --- /dev/null +++ b/src/basic/stdio-util.h @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <printf.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> + +#include "macro.h" + +#define xsprintf(buf, fmt, ...) \ + assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough") + + +#define VA_FORMAT_ADVANCE(format, ap) \ +do { \ + int _argtypes[128]; \ + size_t _i, _k; \ + _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ + assert(_k < ELEMENTSOF(_argtypes)); \ + for (_i = 0; _i < _k; _i++) { \ + if (_argtypes[_i] & PA_FLAG_PTR) { \ + (void) va_arg(ap, void*); \ + continue; \ + } \ + \ + switch (_argtypes[_i]) { \ + case PA_INT: \ + case PA_INT|PA_FLAG_SHORT: \ + case PA_CHAR: \ + (void) va_arg(ap, int); \ + break; \ + case PA_INT|PA_FLAG_LONG: \ + (void) va_arg(ap, long int); \ + break; \ + case PA_INT|PA_FLAG_LONG_LONG: \ + (void) va_arg(ap, long long int); \ + break; \ + case PA_WCHAR: \ + (void) va_arg(ap, wchar_t); \ + break; \ + case PA_WSTRING: \ + case PA_STRING: \ + case PA_POINTER: \ + (void) va_arg(ap, void*); \ + break; \ + case PA_FLOAT: \ + case PA_DOUBLE: \ + (void) va_arg(ap, double); \ + break; \ + case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ + (void) va_arg(ap, long double); \ + break; \ + default: \ + assert_not_reached("Unknown format string argument."); \ + } \ + } \ +} while(false) diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index 01a076c2ba..f4f702a05a 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -22,8 +22,9 @@ #include <stdlib.h> #include <string.h> -#include "util.h" +#include "alloc-util.h" #include "strbuf.h" +#include "util.h" /* * Strbuf stores given strings in a single continuous allocated memory diff --git a/src/basic/string-table.c b/src/basic/string-table.c new file mode 100644 index 0000000000..a860324fc9 --- /dev/null +++ b/src/basic/string-table.c @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "string-table.h" + +ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { + size_t i; + + if (!key) + return -1; + + for (i = 0; i < len; ++i) + if (streq_ptr(table[i], key)) + return (ssize_t) i; + + return -1; +} diff --git a/src/basic/string-table.h b/src/basic/string-table.h new file mode 100644 index 0000000000..51b6007214 --- /dev/null +++ b/src/basic/string-table.h @@ -0,0 +1,88 @@ + +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "macro.h" +#include "parse-util.h" +#include "string-util.h" + +ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); + +/* For basic lookup tables with strictly enumerated entries */ +#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + scope const char *name##_to_string(type i) { \ + if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ + return NULL; \ + return name##_table[i]; \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + scope type name##_from_string(const char *s) { \ + return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) + +/* For string conversions where numbers are also acceptable */ +#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ + int name##_to_string_alloc(type i, char **str) { \ + char *s; \ + if (i < 0 || i > max) \ + return -ERANGE; \ + if (i < (type) ELEMENTSOF(name##_table)) { \ + s = strdup(name##_table[i]); \ + if (!s) \ + return -ENOMEM; \ + } else { \ + if (asprintf(&s, "%i", i) < 0) \ + return -ENOMEM; \ + } \ + *str = s; \ + return 0; \ + } \ + type name##_from_string(const char *s) { \ + type i; \ + unsigned u = 0; \ + if (!s) \ + return (type) -1; \ + for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ + if (streq_ptr(name##_table[i], s)) \ + return i; \ + if (safe_atou(s, &u) >= 0 && u <= max) \ + return (type) u; \ + return (type) -1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ diff --git a/src/basic/string-util.c b/src/basic/string-util.c new file mode 100644 index 0000000000..6006767daa --- /dev/null +++ b/src/basic/string-util.c @@ -0,0 +1,800 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "gunicode.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" + +int strcmp_ptr(const char *a, const char *b) { + + /* Like strcmp(), but tries to make sense of NULL pointers */ + if (a && b) + return strcmp(a, b); + + if (!a && b) + return -1; + + if (a && !b) + return 1; + + return 0; +} + +char* endswith(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +char* endswith_no_case(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (strcasecmp(s + sl - pl, postfix) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +char* first_word(const char *s, const char *word) { + size_t sl, wl; + const char *p; + + assert(s); + assert(word); + + /* Checks if the string starts with the specified word, either + * followed by NUL or by whitespace. Returns a pointer to the + * NUL or the first character after the whitespace. */ + + sl = strlen(s); + wl = strlen(word); + + if (sl < wl) + return NULL; + + if (wl == 0) + return (char*) s; + + if (memcmp(s, word, wl) != 0) + return NULL; + + p = s + wl; + if (*p == 0) + return (char*) p; + + if (!strchr(WHITESPACE, *p)) + return NULL; + + p += strspn(p, WHITESPACE); + return (char*) p; +} + +static size_t strcspn_escaped(const char *s, const char *reject) { + bool escaped = false; + int n; + + for (n=0; s[n]; n++) { + if (escaped) + escaped = false; + else if (s[n] == '\\') + escaped = true; + else if (strchr(reject, s[n])) + break; + } + + /* if s ends in \, return index of previous char */ + return n - escaped; +} + +/* Split a string into words. */ +const char* split(const char **state, size_t *l, const char *separator, bool quoted) { + const char *current; + + current = *state; + + if (!*current) { + assert(**state == '\0'); + return NULL; + } + + current += strspn(current, separator); + if (!*current) { + *state = current; + return NULL; + } + + if (quoted && strchr("\'\"", *current)) { + char quotechars[2] = {*current, '\0'}; + + *l = strcspn_escaped(current + 1, quotechars); + if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || + (current[*l + 2] && !strchr(separator, current[*l + 2]))) { + /* right quote missing or garbage at the end */ + *state = current; + return NULL; + } + *state = current++ + *l + 2; + } else if (quoted) { + *l = strcspn_escaped(current, separator); + if (current[*l] && !strchr(separator, current[*l])) { + /* unfinished escape */ + *state = current; + return NULL; + } + *state = current + *l; + } else { + *l = strcspn(current, separator); + *state = current + *l; + } + + return current; +} + +char *strnappend(const char *s, const char *suffix, size_t b) { + size_t a; + char *r; + + if (!s && !suffix) + return strdup(""); + + if (!s) + return strndup(suffix, b); + + if (!suffix) + return strdup(s); + + assert(s); + assert(suffix); + + a = strlen(s); + if (b > ((size_t) -1) - a) + return NULL; + + r = new(char, a+b+1); + if (!r) + return NULL; + + memcpy(r, s, a); + memcpy(r+a, suffix, b); + r[a+b] = 0; + + return r; +} + +char *strappend(const char *s, const char *suffix) { + return strnappend(s, suffix, suffix ? strlen(suffix) : 0); +} + +char *strjoin(const char *x, ...) { + va_list ap; + size_t l; + char *r, *p; + + va_start(ap, x); + + if (x) { + l = strlen(x); + + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + } else + l = 0; + + va_end(ap); + + r = new(char, l+1); + if (!r) + return NULL; + + if (x) { + p = stpcpy(r, x); + + va_start(ap, x); + + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + + va_end(ap); + } else + r[0] = 0; + + return r; +} + +char *strstrip(char *s) { + char *e; + + /* Drops trailing whitespace. Modifies the string in + * place. Returns pointer to first non-space character */ + + s += strspn(s, WHITESPACE); + + for (e = strchr(s, 0); e > s; e --) + if (!strchr(WHITESPACE, e[-1])) + break; + + *e = 0; + + return s; +} + +char *delete_chars(char *s, const char *bad) { + char *f, *t; + + /* Drops all whitespace, regardless where in the string */ + + for (f = s, t = s; *f; f++) { + if (strchr(bad, *f)) + continue; + + *(t++) = *f; + } + + *t = 0; + + return s; +} + +char *truncate_nl(char *s) { + assert(s); + + s[strcspn(s, NEWLINE)] = 0; + return s; +} + +char *ascii_strlower(char *t) { + char *p; + + assert(t); + + for (p = t; *p; p++) + if (*p >= 'A' && *p <= 'Z') + *p = *p - 'A' + 'a'; + + return t; +} + +bool chars_intersect(const char *a, const char *b) { + const char *p; + + /* Returns true if any of the chars in a are in b. */ + for (p = a; *p; p++) + if (strchr(b, *p)) + return true; + + return false; +} + +bool string_has_cc(const char *p, const char *ok) { + const char *t; + + assert(p); + + /* + * Check if a string contains control characters. If 'ok' is + * non-NULL it may be a string containing additional CCs to be + * considered OK. + */ + + for (t = p; *t; t++) { + if (ok && strchr(ok, *t)) + continue; + + if (*t > 0 && *t < ' ') + return true; + + if (*t == 127) + return true; + } + + return false; +} + +static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *r; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + r = new0(char, new_length+1); + if (!r) + return NULL; + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + memcpy(r, s, x); + r[x] = '.'; + r[x+1] = '.'; + r[x+2] = '.'; + memcpy(r + x + 3, + s + old_length - (new_length - x - 3), + new_length - x - 3); + + return r; +} + +char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *e; + const char *i, *j; + unsigned k, len, len2; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + /* if no multibyte characters use ascii_ellipsize_mem for speed */ + if (ascii_is_valid(s)) + return ascii_ellipsize_mem(s, old_length, new_length, percent); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + k = 0; + for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { + int c; + + c = utf8_encoded_to_unichar(i); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + + if (k > x) /* last character was wide and went over quota */ + x ++; + + for (j = s + old_length; k < new_length && j > i; ) { + int c; + + j = utf8_prev_char(j); + c = utf8_encoded_to_unichar(j); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + assert(i <= j); + + /* we don't actually need to ellipsize */ + if (i == j) + return memdup(s, old_length + 1); + + /* make space for ellipsis */ + j = utf8_next_char(j); + + len = i - s; + len2 = s + old_length - j; + e = new(char, len + 3 + len2 + 1); + if (!e) + return NULL; + + /* + printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", + old_length, new_length, x, len, len2, k); + */ + + memcpy(e, s, len); + e[len] = 0xe2; /* tri-dot ellipsis: … */ + e[len + 1] = 0x80; + e[len + 2] = 0xa6; + + memcpy(e + len + 3, j, len2 + 1); + + return e; +} + +char *ellipsize(const char *s, size_t length, unsigned percent) { + return ellipsize_mem(s, strlen(s), length, percent); +} + +bool nulstr_contains(const char*nulstr, const char *needle) { + const char *i; + + if (!nulstr) + return false; + + NULSTR_FOREACH(i, nulstr) + if (streq(i, needle)) + return true; + + return false; +} + +char* strshorten(char *s, size_t l) { + assert(s); + + if (l < strlen(s)) + s[l] = 0; + + return s; +} + +char *strreplace(const char *text, const char *old_string, const char *new_string) { + const char *f; + char *t, *r; + size_t l, old_len, new_len; + + assert(text); + assert(old_string); + assert(new_string); + + old_len = strlen(old_string); + new_len = strlen(new_string); + + l = strlen(text); + r = new(char, l+1); + if (!r) + return NULL; + + f = text; + t = r; + while (*f) { + char *a; + size_t d, nl; + + if (!startswith(f, old_string)) { + *(t++) = *(f++); + continue; + } + + d = t - r; + nl = l - old_len + new_len; + a = realloc(r, nl + 1); + if (!a) + goto oom; + + l = nl; + r = a; + t = r + d; + + t = stpcpy(t, new_string); + f += old_len; + } + + *t = 0; + return r; + +oom: + free(r); + return NULL; +} + +char *strip_tab_ansi(char **ibuf, size_t *_isz) { + const char *i, *begin = NULL; + enum { + STATE_OTHER, + STATE_ESCAPE, + STATE_BRACKET + } state = STATE_OTHER; + char *obuf = NULL; + size_t osz = 0, isz; + FILE *f; + + assert(ibuf); + assert(*ibuf); + + /* Strips ANSI color and replaces TABs by 8 spaces */ + + isz = _isz ? *_isz : strlen(*ibuf); + + f = open_memstream(&obuf, &osz); + if (!f) + return NULL; + + for (i = *ibuf; i < *ibuf + isz + 1; i++) { + + switch (state) { + + case STATE_OTHER: + if (i >= *ibuf + isz) /* EOT */ + break; + else if (*i == '\x1B') + state = STATE_ESCAPE; + else if (*i == '\t') + fputs(" ", f); + else + fputc(*i, f); + break; + + case STATE_ESCAPE: + if (i >= *ibuf + isz) { /* EOT */ + fputc('\x1B', f); + break; + } else if (*i == '[') { + state = STATE_BRACKET; + begin = i + 1; + } else { + fputc('\x1B', f); + fputc(*i, f); + state = STATE_OTHER; + } + + break; + + case STATE_BRACKET: + + if (i >= *ibuf + isz || /* EOT */ + (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { + fputc('\x1B', f); + fputc('[', f); + state = STATE_OTHER; + i = begin-1; + } else if (*i == 'm') + state = STATE_OTHER; + break; + } + } + + if (ferror(f)) { + fclose(f); + free(obuf); + return NULL; + } + + fclose(f); + + free(*ibuf); + *ibuf = obuf; + + if (_isz) + *_isz = osz; + + return obuf; +} + +char *strextend(char **x, ...) { + va_list ap; + size_t f, l; + char *r, *p; + + assert(x); + + l = f = *x ? strlen(*x) : 0; + + va_start(ap, x); + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + va_end(ap); + + r = realloc(*x, l+1); + if (!r) + return NULL; + + p = r + f; + + va_start(ap, x); + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + va_end(ap); + + *p = 0; + *x = r; + + return r + l; +} + +char *strrep(const char *s, unsigned n) { + size_t l; + char *r, *p; + unsigned i; + + assert(s); + + l = strlen(s); + p = r = malloc(l * n + 1); + if (!r) + return NULL; + + for (i = 0; i < n; i++) + p = stpcpy(p, s); + + *p = 0; + return r; +} + +int split_pair(const char *s, const char *sep, char **l, char **r) { + char *x, *a, *b; + + assert(s); + assert(sep); + assert(l); + assert(r); + + if (isempty(sep)) + return -EINVAL; + + x = strstr(s, sep); + if (!x) + return -EINVAL; + + a = strndup(s, x - s); + if (!a) + return -ENOMEM; + + b = strdup(x + strlen(sep)); + if (!b) { + free(a); + return -ENOMEM; + } + + *l = a; + *r = b; + + return 0; +} + +int free_and_strdup(char **p, const char *s) { + char *t; + + assert(p); + + /* Replaces a string pointer with an strdup()ed new string, + * possibly freeing the old one. */ + + if (streq_ptr(*p, s)) + return 0; + + if (s) { + t = strdup(s); + if (!t) + return -ENOMEM; + } else + t = NULL; + + free(*p); + *p = t; + + return 1; +} + +#pragma GCC push_options +#pragma GCC optimize("O0") + +void* memory_erase(void *p, size_t l) { + volatile uint8_t* x = (volatile uint8_t*) p; + + /* This basically does what memset() does, but hopefully isn't + * optimized away by the compiler. One of those days, when + * glibc learns memset_s() we should replace this call by + * memset_s(), but until then this has to do. */ + + for (; l > 0; l--) + *(x++) = 'x'; + + return p; +} + +#pragma GCC pop_options + +char* string_erase(char *x) { + + if (!x) + return NULL; + + /* A delicious drop of snake-oil! To be called on memory where + * we stored passphrases or so, after we used them. */ + + return memory_erase(x, strlen(x)); +} + +char *string_free_erase(char *s) { + return mfree(string_erase(s)); +} + +bool string_is_safe(const char *p) { + const char *t; + + if (!p) + return false; + + for (t = p; *t; t++) { + if (*t > 0 && *t < ' ') /* no control characters */ + return false; + + if (strchr(QUOTES "\\\x7f", *t)) + return false; + } + + return true; +} diff --git a/src/basic/string-util.h b/src/basic/string-util.h new file mode 100644 index 0000000000..54f9d3058c --- /dev/null +++ b/src/basic/string-util.h @@ -0,0 +1,184 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <string.h> + +#include "macro.h" + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n\r" +#define NEWLINE "\n\r" +#define QUOTES "\"\'" +#define COMMENTS "#;" +#define GLOB_CHARS "*?[" +#define DIGITS "0123456789" +#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +#define ALPHANUMERICAL LETTERS DIGITS + +#define streq(a,b) (strcmp((a),(b)) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +int strcmp_ptr(const char *a, const char *b) _pure_; + +static inline bool streq_ptr(const char *a, const char *b) { + return strcmp_ptr(a, b) == 0; +} + +static inline const char* strempty(const char *s) { + return s ? s : ""; +} + +static inline const char* strnull(const char *s) { + return s ? s : "(null)"; +} + +static inline const char *strna(const char *s) { + return s ? s : "n/a"; +} + +static inline bool isempty(const char *p) { + return !p || !p[0]; +} + +static inline char *startswith(const char *s, const char *prefix) { + size_t l; + + l = strlen(prefix); + if (strncmp(s, prefix, l) == 0) + return (char*) s + l; + + return NULL; +} + +static inline char *startswith_no_case(const char *s, const char *prefix) { + size_t l; + + l = strlen(prefix); + if (strncasecmp(s, prefix, l) == 0) + return (char*) s + l; + + return NULL; +} + +char *endswith(const char *s, const char *postfix) _pure_; +char *endswith_no_case(const char *s, const char *postfix) _pure_; + +char *first_word(const char *s, const char *word) _pure_; + +const char* split(const char **state, size_t *l, const char *separator, bool quoted); + +#define FOREACH_WORD(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, false, state) + +#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ + _FOREACH_WORD(word, length, s, separator, false, state) + +#define FOREACH_WORD_QUOTED(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, true, state) + +#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ + for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) + +char *strappend(const char *s, const char *suffix); +char *strnappend(const char *s, const char *suffix, size_t length); + +char *strjoin(const char *x, ...) _sentinel_; + +#define strjoina(a, ...) \ + ({ \ + const char *_appendees_[] = { a, __VA_ARGS__ }; \ + char *_d_, *_p_; \ + int _len_ = 0; \ + unsigned _i_; \ + for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ + _len_ += strlen(_appendees_[_i_]); \ + _p_ = _d_ = alloca(_len_ + 1); \ + for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ + _p_ = stpcpy(_p_, _appendees_[_i_]); \ + *_p_ = 0; \ + _d_; \ + }) + +char *strstrip(char *s); +char *delete_chars(char *s, const char *bad); +char *truncate_nl(char *s); + +char *ascii_strlower(char *path); + +bool chars_intersect(const char *a, const char *b) _pure_; + +static inline bool _pure_ in_charset(const char *s, const char* charset) { + assert(s); + assert(charset); + return s[strspn(s, charset)] == '\0'; +} + +bool string_has_cc(const char *p, const char *ok) _pure_; + +char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent); +char *ellipsize(const char *s, size_t length, unsigned percent); + +bool nulstr_contains(const char*nulstr, const char *needle); + +char* strshorten(char *s, size_t l); + +char *strreplace(const char *text, const char *old_string, const char *new_string); + +char *strip_tab_ansi(char **p, size_t *l); + +char *strextend(char **x, ...) _sentinel_; + +char *strrep(const char *s, unsigned n); + +int split_pair(const char *s, const char *sep, char **l, char **r); + +int free_and_strdup(char **p, const char *s); + +/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ +static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { + + if (needlelen <= 0) + return (void*) haystack; + + if (haystacklen < needlelen) + return NULL; + + assert(haystack); + assert(needle); + + return memmem(haystack, haystacklen, needle, needlelen); +} + +void* memory_erase(void *p, size_t l); +char *string_erase(char *x); + +char *string_free_erase(char *s); +DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase); +#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep) + +bool string_is_safe(const char *p) _pure_; diff --git a/src/basic/strv.c b/src/basic/strv.c index b66c176487..ba6df716a7 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <errno.h> #include <stdarg.h> +#include <stdlib.h> #include <string.h> -#include <errno.h> +#include "alloc-util.h" +#include "escape.h" +#include "string-util.h" #include "util.h" #include "strv.h" @@ -86,6 +89,15 @@ char **strv_free(char **l) { return NULL; } +char **strv_free_erase(char **l) { + char **i; + + STRV_FOREACH(i, l) + string_erase(*i); + + return strv_free(l); +} + char **strv_copy(char * const *l) { char **r, **k; diff --git a/src/basic/strv.h b/src/basic/strv.h index e49f443835..e66794fc34 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -21,10 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fnmatch.h> #include <stdarg.h> #include <stdbool.h> -#include <fnmatch.h> +#include "extract-word.h" #include "util.h" char *strv_find(char **l, const char *name) _pure_; @@ -35,6 +36,10 @@ char **strv_free(char **l); DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); #define _cleanup_strv_free_ _cleanup_(strv_freep) +char **strv_free_erase(char **l); +DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); +#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep) + void strv_clear(char **l); char **strv_copy(char * const *l); diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c new file mode 100644 index 0000000000..01577941a0 --- /dev/null +++ b/src/basic/syslog-util.c @@ -0,0 +1,115 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <syslog.h> + +#include "assert.h" +#include "hexdecoct.h" +#include "string-table.h" +#include "syslog-util.h" + +int syslog_parse_priority(const char **p, int *priority, bool with_facility) { + int a = 0, b = 0, c = 0; + int k; + + assert(p); + assert(*p); + assert(priority); + + if ((*p)[0] != '<') + return 0; + + if (!strchr(*p, '>')) + return 0; + + if ((*p)[2] == '>') { + c = undecchar((*p)[1]); + k = 3; + } else if ((*p)[3] == '>') { + b = undecchar((*p)[1]); + c = undecchar((*p)[2]); + k = 4; + } else if ((*p)[4] == '>') { + a = undecchar((*p)[1]); + b = undecchar((*p)[2]); + c = undecchar((*p)[3]); + k = 5; + } else + return 0; + + if (a < 0 || b < 0 || c < 0 || + (!with_facility && (a || b || c > 7))) + return 0; + + if (with_facility) + *priority = a*100 + b*10 + c; + else + *priority = (*priority & LOG_FACMASK) | c; + + *p += k; + return 1; +} + +static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { + [LOG_FAC(LOG_KERN)] = "kern", + [LOG_FAC(LOG_USER)] = "user", + [LOG_FAC(LOG_MAIL)] = "mail", + [LOG_FAC(LOG_DAEMON)] = "daemon", + [LOG_FAC(LOG_AUTH)] = "auth", + [LOG_FAC(LOG_SYSLOG)] = "syslog", + [LOG_FAC(LOG_LPR)] = "lpr", + [LOG_FAC(LOG_NEWS)] = "news", + [LOG_FAC(LOG_UUCP)] = "uucp", + [LOG_FAC(LOG_CRON)] = "cron", + [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", + [LOG_FAC(LOG_FTP)] = "ftp", + [LOG_FAC(LOG_LOCAL0)] = "local0", + [LOG_FAC(LOG_LOCAL1)] = "local1", + [LOG_FAC(LOG_LOCAL2)] = "local2", + [LOG_FAC(LOG_LOCAL3)] = "local3", + [LOG_FAC(LOG_LOCAL4)] = "local4", + [LOG_FAC(LOG_LOCAL5)] = "local5", + [LOG_FAC(LOG_LOCAL6)] = "local6", + [LOG_FAC(LOG_LOCAL7)] = "local7" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); + +bool log_facility_unshifted_is_valid(int facility) { + return facility >= 0 && facility <= LOG_FAC(~0); +} + +static const char *const log_level_table[] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); + +bool log_level_is_valid(int level) { + return level >= 0 && level <= LOG_DEBUG; +} diff --git a/src/basic/syslog-util.h b/src/basic/syslog-util.h new file mode 100644 index 0000000000..eb79c6dbd8 --- /dev/null +++ b/src/basic/syslog-util.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +int log_facility_unshifted_to_string_alloc(int i, char **s); +int log_facility_unshifted_from_string(const char *s); +bool log_facility_unshifted_is_valid(int faciliy); + +int log_level_to_string_alloc(int i, char **s); +int log_level_from_string(const char *s); +bool log_level_is_valid(int level); + +int syslog_parse_priority(const char **p, int *priority, bool with_facility); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index ca7554a9fa..3931b03bc2 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -17,26 +17,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <assert.h> +#include <fcntl.h> +#include <linux/kd.h> +#include <linux/tiocl.h> +#include <linux/vt.h> +#include <poll.h> +#include <signal.h> #include <sys/ioctl.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include <termios.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> #include <time.h> -#include <assert.h> -#include <poll.h> -#include <linux/vt.h> -#include <linux/tiocl.h> -#include <linux/kd.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "process-util.h" +#include "socket-util.h" +#include "stat-util.h" +#include "string-util.h" #include "terminal-util.h" #include "time-util.h" -#include "process-util.h" #include "util.h" -#include "fileio.h" -#include "path-util.h" static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; @@ -412,7 +420,7 @@ int acquire_terminal( assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); - /* Sometimes it makes sense to ignore TIOCSCTTY + /* Sometimes, it makes sense to ignore TIOCSCTTY * returning EPERM, i.e. when very likely we already * are have this controlling terminal. */ if (r < 0 && r == -EPERM && ignore_tiocstty_eperm) @@ -620,84 +628,6 @@ int make_console_stdio(void) { return 0; } -int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { - static const char status_indent[] = " "; /* "[" STATUS "] " */ - _cleanup_free_ char *s = NULL; - _cleanup_close_ int fd = -1; - struct iovec iovec[6] = {}; - int n = 0; - static bool prev_ephemeral; - - assert(format); - - /* This is independent of logging, as status messages are - * optional and go exclusively to the console. */ - - if (vasprintf(&s, format, ap) < 0) - return log_oom(); - - fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - if (ellipse) { - char *e; - size_t emax, sl; - int c; - - c = fd_columns(fd); - if (c <= 0) - c = 80; - - sl = status ? sizeof(status_indent)-1 : 0; - - emax = c - sl - 1; - if (emax < 3) - emax = 3; - - e = ellipsize(s, emax, 50); - if (e) { - free(s); - s = e; - } - } - - if (prev_ephemeral) - IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); - prev_ephemeral = ephemeral; - - if (status) { - if (!isempty(status)) { - IOVEC_SET_STRING(iovec[n++], "["); - IOVEC_SET_STRING(iovec[n++], status); - IOVEC_SET_STRING(iovec[n++], "] "); - } else - IOVEC_SET_STRING(iovec[n++], status_indent); - } - - IOVEC_SET_STRING(iovec[n++], s); - if (!ephemeral) - IOVEC_SET_STRING(iovec[n++], "\n"); - - if (writev(fd, iovec, n) < 0) - return -errno; - - return 0; -} - -int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) { - va_list ap; - int r; - - assert(format); - - va_start(ap, format); - r = status_vprintf(status, ellipse, ephemeral, format, ap); - va_end(ap); - - return r; -} - bool tty_is_vc(const char *tty) { assert(tty); diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index ee0b68b433..f2185c1c11 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -71,9 +71,6 @@ int make_stdio(int fd); int make_null_stdio(void); int make_console_stdio(void); -int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); -int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); - int fd_columns(int fd); unsigned columns(void); int fd_lines(int fd); diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 531931f6e1..b36fbe4f09 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -19,15 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <time.h> #include <string.h> -#include <sys/timex.h> #include <sys/timerfd.h> +#include <sys/timex.h> -#include "util.h" -#include "time-util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" +#include "time-util.h" +#include "util.h" usec_t now(clockid_t clock_id) { struct timespec ts; @@ -205,11 +209,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) return NULL; sec = (time_t) (t / USEC_PER_SEC); + localtime_or_gmtime_r(&sec, &tm, utc); - if (utc) - gmtime_r(&sec, &tm); - else - localtime_r(&sec, &tm); if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) return NULL; @@ -235,10 +236,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut return NULL; sec = (time_t) (t / USEC_PER_SEC); - if (utc) - gmtime_r(&sec, &tm); - else - localtime_r(&sec, &tm); + localtime_or_gmtime_r(&sec, &tm, utc); if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) return NULL; @@ -484,9 +482,10 @@ int parse_timestamp(const char *t, usec_t *usec) { }; const char *k; + const char *utc; struct tm tm, copy; time_t x; - usec_t plus = 0, minus = 0, ret; + usec_t x_usec, plus = 0, minus = 0, ret; int r, weekday = -1; unsigned i; @@ -511,28 +510,15 @@ int parse_timestamp(const char *t, usec_t *usec) { assert(t); assert(usec); - x = time(NULL); - assert_se(localtime_r(&x, &tm)); - tm.tm_isdst = -1; - - if (streq(t, "now")) - goto finish; - - else if (streq(t, "today")) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + if (t[0] == '@') + return parse_sec(t + 1, usec); - } else if (streq(t, "yesterday")) { - tm.tm_mday --; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + ret = now(CLOCK_REALTIME); - } else if (streq(t, "tomorrow")) { - tm.tm_mday ++; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + if (streq(t, "now")) goto finish; - } else if (t[0] == '+') { + else if (t[0] == '+') { r = parse_sec(t+1, &plus); if (r < 0) return r; @@ -546,35 +532,51 @@ int parse_timestamp(const char *t, usec_t *usec) { goto finish; - } else if (t[0] == '@') - return parse_sec(t + 1, usec); - - else if (endswith(t, " ago")) { - _cleanup_free_ char *z; + } else if ((k = endswith(t, " ago"))) { + t = strndupa(t, k - t); - z = strndup(t, strlen(t) - 4); - if (!z) - return -ENOMEM; - - r = parse_sec(z, &minus); + r = parse_sec(t, &minus); if (r < 0) return r; goto finish; - } else if (endswith(t, " left")) { - _cleanup_free_ char *z; - z = strndup(t, strlen(t) - 4); - if (!z) - return -ENOMEM; + } else if ((k = endswith(t, " left"))) { + t = strndupa(t, k - t); - r = parse_sec(z, &plus); + r = parse_sec(t, &plus); if (r < 0) return r; goto finish; } + utc = endswith_no_case(t, " UTC"); + if (utc) + t = strndupa(t, utc - t); + + x = ret / USEC_PER_SEC; + x_usec = 0; + + assert_se(localtime_or_gmtime_r(&x, &tm, utc)); + tm.tm_isdst = -1; + + if (streq(t, "today")) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + + } else if (streq(t, "yesterday")) { + tm.tm_mday --; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + + } else if (streq(t, "tomorrow")) { + tm.tm_mday ++; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + } + + for (i = 0; i < ELEMENTSOF(day_nr); i++) { size_t skip; @@ -592,66 +594,106 @@ int parse_timestamp(const char *t, usec_t *usec) { copy = tm; k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } tm = copy; k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } tm = copy; k = strptime(t, "%y-%m-%d %H:%M", &tm); if (k && *k == 0) { tm.tm_sec = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%Y-%m-%d %H:%M", &tm); if (k && *k == 0) { tm.tm_sec = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%y-%m-%d", &tm); if (k && *k == 0) { tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%Y-%m-%d", &tm); if (k && *k == 0) { tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } tm = copy; k = strptime(t, "%H:%M", &tm); if (k && *k == 0) { tm.tm_sec = 0; - goto finish; + goto from_tm; } return -EINVAL; -finish: - x = mktime(&tm); +parse_usec: + { + char *end; + unsigned long long val; + size_t l; + + k++; + if (*k < '0' || *k > '9') + return -EINVAL; + + /* base 10 instead of base 0, .09 is not base 8 */ + errno = 0; + val = strtoull(k, &end, 10); + if (*end || errno) + return -EINVAL; + + l = end-k; + + /* val has l digits, make them 6 */ + for (; l < 6; l++) + val *= 10; + for (; l > 6; l--) + val /= 10; + + x_usec = val; + } + +from_tm: + x = mktime_or_timegm(&tm, utc); if (x == (time_t) -1) return -EINVAL; if (weekday >= 0 && tm.tm_wday != weekday) return -EINVAL; - ret = (usec_t) x * USEC_PER_SEC; + ret = (usec_t) x * USEC_PER_SEC + x_usec; +finish: ret += plus; if (ret > minus) ret -= minus; @@ -663,7 +705,8 @@ finish: return 0; } -int parse_sec(const char *t, usec_t *usec) { +int parse_time(const char *t, usec_t *usec, usec_t default_unit) { + static const struct { const char *suffix; usec_t usec; @@ -695,7 +738,6 @@ int parse_sec(const char *t, usec_t *usec) { { "y", USEC_PER_YEAR }, { "usec", 1ULL }, { "us", 1ULL }, - { "", USEC_PER_SEC }, /* default is sec */ }; const char *p, *s; @@ -704,6 +746,7 @@ int parse_sec(const char *t, usec_t *usec) { assert(t); assert(usec); + assert(default_unit > 0); p = t; @@ -722,6 +765,7 @@ int parse_sec(const char *t, usec_t *usec) { long long l, z = 0; char *e; unsigned i, n = 0; + usec_t multiplier, k; p += strspn(p, WHITESPACE); @@ -764,21 +808,24 @@ int parse_sec(const char *t, usec_t *usec) { for (i = 0; i < ELEMENTSOF(table); i++) if (startswith(e, table[i].suffix)) { - usec_t k = (usec_t) z * table[i].usec; - - for (; n > 0; n--) - k /= 10; - - r += (usec_t) l * table[i].usec + k; + multiplier = table[i].usec; p = e + strlen(table[i].suffix); - - something = true; break; } - if (i >= ELEMENTSOF(table)) - return -EINVAL; + if (i >= ELEMENTSOF(table)) { + multiplier = default_unit; + p = e; + } + + something = true; + k = (usec_t) z * multiplier; + + for (; n > 0; n--) + k /= 10; + + r += (usec_t) l * multiplier + k; } *usec = r; @@ -786,6 +833,10 @@ int parse_sec(const char *t, usec_t *usec) { return 0; } +int parse_sec(const char *t, usec_t *usec) { + return parse_time(t, usec, USEC_PER_SEC); +} + int parse_nsec(const char *t, nsec_t *nsec) { static const struct { const char *suffix; @@ -1072,3 +1123,25 @@ int get_timezone(char **tz) { *tz = z; return 0; } + +time_t mktime_or_timegm(struct tm *tm, bool utc) { + return utc ? timegm(tm) : mktime(tm); +} + +struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) { + return utc ? gmtime_r(t, tm) : localtime_r(t, tm); +} + +unsigned long usec_to_jiffies(usec_t u) { + static thread_local unsigned long hz = 0; + long r; + + if (hz == 0) { + r = sysconf(_SC_CLK_TCK); + + assert(r > 0); + hz = (unsigned long) r; + } + + return DIV_ROUND_UP(u , USEC_PER_SEC / hz); +} diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 1af01541fc..0417c29cdd 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -21,8 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <inttypes.h> +#include <stdio.h> +#include <time.h> typedef uint64_t usec_t; typedef uint64_t nsec_t; @@ -103,6 +104,7 @@ int dual_timestamp_deserialize(const char *value, dual_timestamp *t); int parse_timestamp(const char *t, usec_t *usec); int parse_sec(const char *t, usec_t *usec); +int parse_time(const char *t, usec_t *usec, usec_t default_unit); int parse_nsec(const char *t, nsec_t *nsec); bool ntp_synced(void); @@ -117,3 +119,8 @@ clockid_t clock_boottime_or_monotonic(void); "xstrftime: " #buf "[] must be big enough") int get_timezone(char **timezone); + +time_t mktime_or_timegm(struct tm *tm, bool utc); +struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); + +unsigned long usec_to_jiffies(usec_t usec); diff --git a/src/basic/umask-util.h b/src/basic/umask-util.h new file mode 100644 index 0000000000..8ed34658b4 --- /dev/null +++ b/src/basic/umask-util.h @@ -0,0 +1,48 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "macro.h" + +static inline void umaskp(mode_t *u) { + umask(*u); +} + +#define _cleanup_umask_ _cleanup_(umaskp) + +struct _umask_struct_ { + mode_t mask; + bool quit; +}; + +static inline void _reset_umask_(struct _umask_struct_ *s) { + umask(s->mask); +}; + +#define RUN_WITH_UMASK(mask) \ + for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ + !_saved_umask_.quit ; \ + _saved_umask_.quit = true) diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index a8b6b6dace..9a55eacbfb 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -22,12 +22,16 @@ #include <errno.h> #include <string.h> -#include "path-util.h" +#include "alloc-util.h" #include "bus-label.h" -#include "util.h" -#include "unit-name.h" #include "def.h" +#include "hexdecoct.h" +#include "path-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" +#include "unit-name.h" +#include "util.h" #define VALID_CHARS \ DIGITS LETTERS \ @@ -593,7 +597,6 @@ const char* unit_dbus_interface_from_type(UnitType t) { [UNIT_SOCKET] = "org.freedesktop.systemd1.Socket", [UNIT_BUSNAME] = "org.freedesktop.systemd1.BusName", [UNIT_TARGET] = "org.freedesktop.systemd1.Target", - [UNIT_SNAPSHOT] = "org.freedesktop.systemd1.Snapshot", [UNIT_DEVICE] = "org.freedesktop.systemd1.Device", [UNIT_MOUNT] = "org.freedesktop.systemd1.Mount", [UNIT_AUTOMOUNT] = "org.freedesktop.systemd1.Automount", @@ -651,7 +654,7 @@ static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t * /blah/blah is converted to blah-blah.mount, anything else is left alone, * except that @suffix is appended if a valid unit suffix is not present. * - * If @allow_globs, globs characters are preserved. Otherwise they are escaped. + * If @allow_globs, globs characters are preserved. Otherwise, they are escaped. */ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) { char *s, *t; @@ -815,7 +818,6 @@ static const char* const unit_type_table[_UNIT_TYPE_MAX] = { [UNIT_SOCKET] = "socket", [UNIT_BUSNAME] = "busname", [UNIT_TARGET] = "target", - [UNIT_SNAPSHOT] = "snapshot", [UNIT_DEVICE] = "device", [UNIT_MOUNT] = "mount", [UNIT_AUTOMOUNT] = "automount", @@ -946,13 +948,6 @@ static const char* const slice_state_table[_SLICE_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); -static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { - [SNAPSHOT_DEAD] = "dead", - [SNAPSHOT_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); - static const char* const socket_state_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = "dead", [SOCKET_START_PRE] = "start-pre", @@ -1005,16 +1000,12 @@ DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUIRES] = "Requires", - [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable", [UNIT_REQUISITE] = "Requisite", - [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable", [UNIT_WANTS] = "Wants", [UNIT_BINDS_TO] = "BindsTo", [UNIT_PART_OF] = "PartOf", [UNIT_REQUIRED_BY] = "RequiredBy", - [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable", [UNIT_REQUISITE_OF] = "RequisiteOf", - [UNIT_REQUISITE_OF_OVERRIDABLE] = "RequisiteOfOverridable", [UNIT_WANTED_BY] = "WantedBy", [UNIT_BOUND_BY] = "BoundBy", [UNIT_CONSISTS_OF] = "ConsistsOf", diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index 65b55d9554..03c1a6e4ac 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -32,7 +32,6 @@ typedef enum UnitType { UNIT_SOCKET, UNIT_BUSNAME, UNIT_TARGET, - UNIT_SNAPSHOT, UNIT_DEVICE, UNIT_MOUNT, UNIT_AUTOMOUNT, @@ -165,13 +164,6 @@ typedef enum SliceState { _SLICE_STATE_INVALID = -1 } SliceState; -typedef enum SnapshotState { - SNAPSHOT_DEAD, - SNAPSHOT_ACTIVE, - _SNAPSHOT_STATE_MAX, - _SNAPSHOT_STATE_INVALID = -1 -} SnapshotState; - typedef enum SocketState { SOCKET_DEAD, SOCKET_START_PRE, @@ -226,18 +218,14 @@ typedef enum TimerState { typedef enum UnitDependency { /* Positive dependencies */ UNIT_REQUIRES, - UNIT_REQUIRES_OVERRIDABLE, UNIT_REQUISITE, - UNIT_REQUISITE_OVERRIDABLE, UNIT_WANTS, UNIT_BINDS_TO, UNIT_PART_OF, /* Inverse of the above */ UNIT_REQUIRED_BY, /* inverse of 'requires' is 'required_by' */ - UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' is 'required_by_overridable' */ UNIT_REQUISITE_OF, /* inverse of 'requisite' is 'requisite_of' */ - UNIT_REQUISITE_OF_OVERRIDABLE,/* inverse of 'requisite_overridable' is 'requisite_of_overridable' */ UNIT_WANTED_BY, /* inverse of 'wants' */ UNIT_BOUND_BY, /* inverse of 'binds_to' */ UNIT_CONSISTS_OF, /* inverse of 'part_of' */ @@ -366,9 +354,6 @@ ServiceState service_state_from_string(const char *s) _pure_; const char* slice_state_to_string(SliceState i) _const_; SliceState slice_state_from_string(const char *s) _pure_; -const char* snapshot_state_to_string(SnapshotState i) _const_; -SnapshotState snapshot_state_from_string(const char *s) _pure_; - const char* socket_state_to_string(SocketState i) _const_; SocketState socket_state_from_string(const char *s) _pure_; diff --git a/src/basic/user-util.c b/src/basic/user-util.c new file mode 100644 index 0000000000..d6c936db37 --- /dev/null +++ b/src/basic/user-util.c @@ -0,0 +1,472 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <pwd.h> +#include <grp.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" + +bool uid_is_valid(uid_t uid) { + + /* Some libc APIs use UID_INVALID as special placeholder */ + if (uid == (uid_t) UINT32_C(0xFFFFFFFF)) + return false; + + /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ + if (uid == (uid_t) UINT32_C(0xFFFF)) + return false; + + return true; +} + +int parse_uid(const char *s, uid_t *ret) { + uint32_t uid = 0; + int r; + + assert(s); + + assert_cc(sizeof(uid_t) == sizeof(uint32_t)); + r = safe_atou32(s, &uid); + if (r < 0) + return r; + + if (!uid_is_valid(uid)) + return -ENXIO; /* we return ENXIO instead of EINVAL + * here, to make it easy to distuingish + * invalid numeric uids invalid + * strings. */ + + if (ret) + *ret = uid; + + return 0; +} + +char* getlogname_malloc(void) { + uid_t uid; + struct stat st; + + if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) + uid = st.st_uid; + else + uid = getuid(); + + return uid_to_name(uid); +} + +char *getusername_malloc(void) { + const char *e; + + e = getenv("USER"); + if (e) + return strdup(e); + + return uid_to_name(getuid()); +} + +int get_user_creds( + const char **username, + uid_t *uid, gid_t *gid, + const char **home, + const char **shell) { + + struct passwd *p; + uid_t u; + + assert(username); + assert(*username); + + /* We enforce some special rules for uid=0: in order to avoid + * NSS lookups for root we hardcode its data. */ + + if (streq(*username, "root") || streq(*username, "0")) { + *username = "root"; + + if (uid) + *uid = 0; + + if (gid) + *gid = 0; + + if (home) + *home = "/root"; + + if (shell) + *shell = "/bin/sh"; + + return 0; + } + + if (parse_uid(*username, &u) >= 0) { + errno = 0; + p = getpwuid(u); + + /* If there are multiple users with the same id, make + * sure to leave $USER to the configured value instead + * of the first occurrence in the database. However if + * the uid was configured by a numeric uid, then let's + * pick the real username from /etc/passwd. */ + if (p) + *username = p->pw_name; + } else { + errno = 0; + p = getpwnam(*username); + } + + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (uid) { + if (!uid_is_valid(p->pw_uid)) + return -EBADMSG; + + *uid = p->pw_uid; + } + + if (gid) { + if (!gid_is_valid(p->pw_gid)) + return -EBADMSG; + + *gid = p->pw_gid; + } + + if (home) + *home = p->pw_dir; + + if (shell) + *shell = p->pw_shell; + + return 0; +} + +int get_group_creds(const char **groupname, gid_t *gid) { + struct group *g; + gid_t id; + + assert(groupname); + + /* We enforce some special rules for gid=0: in order to avoid + * NSS lookups for root we hardcode its data. */ + + if (streq(*groupname, "root") || streq(*groupname, "0")) { + *groupname = "root"; + + if (gid) + *gid = 0; + + return 0; + } + + if (parse_gid(*groupname, &id) >= 0) { + errno = 0; + g = getgrgid(id); + + if (g) + *groupname = g->gr_name; + } else { + errno = 0; + g = getgrnam(*groupname); + } + + if (!g) + return errno > 0 ? -errno : -ESRCH; + + if (gid) { + if (!gid_is_valid(g->gr_gid)) + return -EBADMSG; + + *gid = g->gr_gid; + } + + return 0; +} + +char* uid_to_name(uid_t uid) { + char *ret; + int r; + + /* Shortcut things to avoid NSS lookups */ + if (uid == 0) + return strdup("root"); + + if (uid_is_valid(uid)) { + long bufsize; + + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + if (bufsize <= 0) + bufsize = 4096; + + for (;;) { + struct passwd pwbuf, *pw = NULL; + _cleanup_free_ char *buf = NULL; + + buf = malloc(bufsize); + if (!buf) + return NULL; + + r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw); + if (r == 0 && pw) + return strdup(pw->pw_name); + if (r != ERANGE) + break; + + bufsize *= 2; + } + } + + if (asprintf(&ret, UID_FMT, uid) < 0) + return NULL; + + return ret; +} + +char* gid_to_name(gid_t gid) { + char *ret; + int r; + + if (gid == 0) + return strdup("root"); + + if (gid_is_valid(gid)) { + long bufsize; + + bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); + if (bufsize <= 0) + bufsize = 4096; + + for (;;) { + struct group grbuf, *gr = NULL; + _cleanup_free_ char *buf = NULL; + + buf = malloc(bufsize); + if (!buf) + return NULL; + + r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr); + if (r == 0 && gr) + return strdup(gr->gr_name); + if (r != ERANGE) + break; + + bufsize *= 2; + } + } + + if (asprintf(&ret, GID_FMT, gid) < 0) + return NULL; + + return ret; +} + +int in_gid(gid_t gid) { + gid_t *gids; + int ngroups_max, r, i; + + if (getgid() == gid) + return 1; + + if (getegid() == gid) + return 1; + + if (!gid_is_valid(gid)) + return -EINVAL; + + ngroups_max = sysconf(_SC_NGROUPS_MAX); + assert(ngroups_max > 0); + + gids = alloca(sizeof(gid_t) * ngroups_max); + + r = getgroups(ngroups_max, gids); + if (r < 0) + return -errno; + + for (i = 0; i < r; i++) + if (gids[i] == gid) + return 1; + + return 0; +} + +int in_group(const char *name) { + int r; + gid_t gid; + + r = get_group_creds(&name, &gid); + if (r < 0) + return r; + + return in_gid(gid); +} + +int get_home_dir(char **_h) { + struct passwd *p; + const char *e; + char *h; + uid_t u; + + assert(_h); + + /* Take the user specified one */ + e = secure_getenv("HOME"); + if (e && path_is_absolute(e)) { + h = strdup(e); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + h = strdup("/root"); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_dir)) + return -EINVAL; + + h = strdup(p->pw_dir); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; +} + +int get_shell(char **_s) { + struct passwd *p; + const char *e; + char *s; + uid_t u; + + assert(_s); + + /* Take the user specified one */ + e = getenv("SHELL"); + if (e) { + s = strdup(e); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + s = strdup("/bin/sh"); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_shell)) + return -EINVAL; + + s = strdup(p->pw_shell); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; +} + +int reset_uid_gid(void) { + + if (setgroups(0, NULL) < 0) + return -errno; + + if (setresgid(0, 0, 0) < 0) + return -errno; + + if (setresuid(0, 0, 0) < 0) + return -errno; + + return 0; +} + +int take_etc_passwd_lock(const char *root) { + + struct flock flock = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + + const char *path; + int fd, r; + + /* This is roughly the same as lckpwdf(), but not as awful. We + * don't want to use alarm() and signals, hence we implement + * our own trivial version of this. + * + * Note that shadow-utils also takes per-database locks in + * addition to lckpwdf(). However, we don't given that they + * are redundant as they they invoke lckpwdf() first and keep + * it during everything they do. The per-database locks are + * awfully racy, and thus we just won't do them. */ + + if (root) + path = prefix_roota(root, "/etc/.pwd.lock"); + else + path = "/etc/.pwd.lock"; + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); + if (fd < 0) + return -errno; + + r = fcntl(fd, F_SETLKW, &flock); + if (r < 0) { + safe_close(fd); + return -errno; + } + + return fd; +} diff --git a/src/basic/user-util.h b/src/basic/user-util.h new file mode 100644 index 0000000000..11ff6674cf --- /dev/null +++ b/src/basic/user-util.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/types.h> +#include <stdbool.h> + +bool uid_is_valid(uid_t uid); + +static inline bool gid_is_valid(gid_t gid) { + return uid_is_valid((uid_t) gid); +} + +int parse_uid(const char *s, uid_t* ret_uid); + +static inline int parse_gid(const char *s, gid_t *ret_gid) { + return parse_uid(s, (uid_t*) ret_gid); +} + +char* getlogname_malloc(void); +char* getusername_malloc(void); + +int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); +int get_group_creds(const char **groupname, gid_t *gid); + +char* uid_to_name(uid_t uid); +char* gid_to_name(gid_t gid); + +int in_gid(gid_t gid); +int in_group(const char *name); + +int get_home_dir(char **ret); +int get_shell(char **_ret); + +int reset_uid_gid(void); + +int take_etc_passwd_lock(const char *root); + +#define UID_INVALID ((uid_t) -1) +#define GID_INVALID ((gid_t) -1) + +/* The following macros add 1 when converting things, since UID 0 is a + * valid UID, while the pointer NULL is special */ +#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1)) +#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) + +#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) +#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 800884ffee..7600d99903 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -49,6 +49,8 @@ #include <string.h> #include <stdbool.h> +#include "alloc-util.h" +#include "hexdecoct.h" #include "utf8.h" #include "util.h" diff --git a/src/basic/util.c b/src/basic/util.c index ca5e4befa0..08bdcd28f2 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -23,15 +23,14 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> -#include <glob.h> #include <grp.h> #include <langinfo.h> #include <libintl.h> #include <limits.h> #include <linux/magic.h> +#include <linux/oom.h> #include <linux/sched.h> #include <locale.h> -#include <netinet/ip.h> #include <poll.h> #include <pwd.h> #include <sched.h> @@ -46,7 +45,6 @@ #include <sys/mount.h> #include <sys/personality.h> #include <sys/prctl.h> -#include <sys/resource.h> #include <sys/stat.h> #include <sys/statvfs.h> #include <sys/time.h> @@ -54,7 +52,6 @@ #include <sys/utsname.h> #include <sys/vfs.h> #include <sys/wait.h> -#include <sys/xattr.h> #include <syslog.h> #include <unistd.h> @@ -72,11 +69,14 @@ * otherwise conflicts with sys/mount.h. Yay, Linux is great! */ #include <linux/fs.h> +#include "alloc-util.h" #include "build.h" #include "def.h" #include "device-nodes.h" #include "env-util.h" +#include "escape.h" #include "exit-status.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "gunicode.h" @@ -87,16 +87,23 @@ #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "hexdecoct.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "random-util.h" #include "signal-util.h" #include "sparse-endian.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" +#include "user-util.h" #include "utf8.h" #include "util.h" #include "virt.h" +#include "dirent-util.h" +#include "stat-util.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -118,2763 +125,6 @@ size_t page_size(void) { return pgsz; } -int strcmp_ptr(const char *a, const char *b) { - - /* Like strcmp(), but tries to make sense of NULL pointers */ - if (a && b) - return strcmp(a, b); - - if (!a && b) - return -1; - - if (a && !b) - return 1; - - return 0; -} - -bool streq_ptr(const char *a, const char *b) { - return strcmp_ptr(a, b) == 0; -} - -char* endswith(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (memcmp(s + sl - pl, postfix, pl) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -char* endswith_no_case(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (strcasecmp(s + sl - pl, postfix) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -char* first_word(const char *s, const char *word) { - size_t sl, wl; - const char *p; - - assert(s); - assert(word); - - /* Checks if the string starts with the specified word, either - * followed by NUL or by whitespace. Returns a pointer to the - * NUL or the first character after the whitespace. */ - - sl = strlen(s); - wl = strlen(word); - - if (sl < wl) - return NULL; - - if (wl == 0) - return (char*) s; - - if (memcmp(s, word, wl) != 0) - return NULL; - - p = s + wl; - if (*p == 0) - return (char*) p; - - if (!strchr(WHITESPACE, *p)) - return NULL; - - p += strspn(p, WHITESPACE); - return (char*) p; -} - -size_t cescape_char(char c, char *buf) { - char * buf_old = buf; - - switch (c) { - - case '\a': - *(buf++) = '\\'; - *(buf++) = 'a'; - break; - case '\b': - *(buf++) = '\\'; - *(buf++) = 'b'; - break; - case '\f': - *(buf++) = '\\'; - *(buf++) = 'f'; - break; - case '\n': - *(buf++) = '\\'; - *(buf++) = 'n'; - break; - case '\r': - *(buf++) = '\\'; - *(buf++) = 'r'; - break; - case '\t': - *(buf++) = '\\'; - *(buf++) = 't'; - break; - case '\v': - *(buf++) = '\\'; - *(buf++) = 'v'; - break; - case '\\': - *(buf++) = '\\'; - *(buf++) = '\\'; - break; - case '"': - *(buf++) = '\\'; - *(buf++) = '"'; - break; - case '\'': - *(buf++) = '\\'; - *(buf++) = '\''; - break; - - default: - /* For special chars we prefer octal over - * hexadecimal encoding, simply because glib's - * g_strescape() does the same */ - if ((c < ' ') || (c >= 127)) { - *(buf++) = '\\'; - *(buf++) = octchar((unsigned char) c >> 6); - *(buf++) = octchar((unsigned char) c >> 3); - *(buf++) = octchar((unsigned char) c); - } else - *(buf++) = c; - break; - } - - return buf - buf_old; -} - -int close_nointr(int fd) { - assert(fd >= 0); - - if (close(fd) >= 0) - return 0; - - /* - * Just ignore EINTR; a retry loop is the wrong thing to do on - * Linux. - * - * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html - * https://bugzilla.gnome.org/show_bug.cgi?id=682819 - * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR - * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain - */ - if (errno == EINTR) - return 0; - - return -errno; -} - -int safe_close(int fd) { - - /* - * Like close_nointr() but cannot fail. Guarantees errno is - * unchanged. Is a NOP with negative fds passed, and returns - * -1, so that it can be used in this syntax: - * - * fd = safe_close(fd); - */ - - if (fd >= 0) { - PROTECT_ERRNO; - - /* The kernel might return pretty much any error code - * via close(), but the fd will be closed anyway. The - * only condition we want to check for here is whether - * the fd was invalid at all... */ - - assert_se(close_nointr(fd) != -EBADF); - } - - return -1; -} - -void close_many(const int fds[], unsigned n_fd) { - unsigned i; - - assert(fds || n_fd <= 0); - - for (i = 0; i < n_fd; i++) - safe_close(fds[i]); -} - -int fclose_nointr(FILE *f) { - assert(f); - - /* Same as close_nointr(), but for fclose() */ - - if (fclose(f) == 0) - return 0; - - if (errno == EINTR) - return 0; - - return -errno; -} - -FILE* safe_fclose(FILE *f) { - - /* Same as safe_close(), but for fclose() */ - - if (f) { - PROTECT_ERRNO; - - assert_se(fclose_nointr(f) != EBADF); - } - - return NULL; -} - -DIR* safe_closedir(DIR *d) { - - if (d) { - PROTECT_ERRNO; - - assert_se(closedir(d) >= 0 || errno != EBADF); - } - - return NULL; -} - -int unlink_noerrno(const char *path) { - PROTECT_ERRNO; - int r; - - r = unlink(path); - if (r < 0) - return -errno; - - return 0; -} - -int parse_boolean(const char *v) { - assert(v); - - if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on")) - return 1; - else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off")) - return 0; - - return -EINVAL; -} - -int parse_pid(const char *s, pid_t* ret_pid) { - unsigned long ul = 0; - pid_t pid; - int r; - - assert(s); - assert(ret_pid); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - pid = (pid_t) ul; - - if ((unsigned long) pid != ul) - return -ERANGE; - - if (pid <= 0) - return -ERANGE; - - *ret_pid = pid; - return 0; -} - -bool uid_is_valid(uid_t uid) { - - /* Some libc APIs use UID_INVALID as special placeholder */ - if (uid == (uid_t) 0xFFFFFFFF) - return false; - - /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ - if (uid == (uid_t) 0xFFFF) - return false; - - return true; -} - -int parse_uid(const char *s, uid_t* ret_uid) { - unsigned long ul = 0; - uid_t uid; - int r; - - assert(s); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - uid = (uid_t) ul; - - if ((unsigned long) uid != ul) - return -ERANGE; - - if (!uid_is_valid(uid)) - return -ENXIO; /* we return ENXIO instead of EINVAL - * here, to make it easy to distuingish - * invalid numeric uids invalid - * strings. */ - - if (ret_uid) - *ret_uid = uid; - - return 0; -} - -int safe_atou(const char *s, unsigned *ret_u) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret_u); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (unsigned) l != l) - return -ERANGE; - - *ret_u = (unsigned) l; - return 0; -} - -int safe_atoi(const char *s, int *ret_i) { - char *x = NULL; - long l; - - assert(s); - assert(ret_i); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((long) (int) l != l) - return -ERANGE; - - *ret_i = (int) l; - return 0; -} - -int safe_atou8(const char *s, uint8_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (uint8_t) l != l) - return -ERANGE; - - *ret = (uint8_t) l; - return 0; -} - -int safe_atou16(const char *s, uint16_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (uint16_t) l != l) - return -ERANGE; - - *ret = (uint16_t) l; - return 0; -} - -int safe_atoi16(const char *s, int16_t *ret) { - char *x = NULL; - long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((long) (int16_t) l != l) - return -ERANGE; - - *ret = (int16_t) l; - return 0; -} - -int safe_atollu(const char *s, long long unsigned *ret_llu) { - char *x = NULL; - unsigned long long l; - - assert(s); - assert(ret_llu); - - errno = 0; - l = strtoull(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_llu = l; - return 0; -} - -int safe_atolli(const char *s, long long int *ret_lli) { - char *x = NULL; - long long l; - - assert(s); - assert(ret_lli); - - errno = 0; - l = strtoll(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_lli = l; - return 0; -} - -int safe_atod(const char *s, double *ret_d) { - char *x = NULL; - double d = 0; - locale_t loc; - - assert(s); - assert(ret_d); - - loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); - if (loc == (locale_t) 0) - return -errno; - - errno = 0; - d = strtod_l(s, &x, loc); - - if (!x || x == s || *x || errno) { - freelocale(loc); - return errno ? -errno : -EINVAL; - } - - freelocale(loc); - *ret_d = (double) d; - return 0; -} - -static size_t strcspn_escaped(const char *s, const char *reject) { - bool escaped = false; - int n; - - for (n=0; s[n]; n++) { - if (escaped) - escaped = false; - else if (s[n] == '\\') - escaped = true; - else if (strchr(reject, s[n])) - break; - } - - /* if s ends in \, return index of previous char */ - return n - escaped; -} - -/* Split a string into words. */ -const char* split(const char **state, size_t *l, const char *separator, bool quoted) { - const char *current; - - current = *state; - - if (!*current) { - assert(**state == '\0'); - return NULL; - } - - current += strspn(current, separator); - if (!*current) { - *state = current; - return NULL; - } - - if (quoted && strchr("\'\"", *current)) { - char quotechars[2] = {*current, '\0'}; - - *l = strcspn_escaped(current + 1, quotechars); - if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || - (current[*l + 2] && !strchr(separator, current[*l + 2]))) { - /* right quote missing or garbage at the end */ - *state = current; - return NULL; - } - *state = current++ + *l + 2; - } else if (quoted) { - *l = strcspn_escaped(current, separator); - if (current[*l] && !strchr(separator, current[*l])) { - /* unfinished escape */ - *state = current; - return NULL; - } - *state = current + *l; - } else { - *l = strcspn(current, separator); - *state = current + *l; - } - - return current; -} - -int fchmod_umask(int fd, mode_t m) { - mode_t u; - int r; - - u = umask(0777); - r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; - umask(u); - - return r; -} - -char *truncate_nl(char *s) { - assert(s); - - s[strcspn(s, NEWLINE)] = 0; - return s; -} - -char *strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - - if (!s) - return strndup(suffix, b); - - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - if (b > ((size_t) -1) - a) - return NULL; - - r = new(char, a+b+1); - if (!r) - return NULL; - - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; - - return r; -} - -char *strappend(const char *s, const char *suffix) { - return strnappend(s, suffix, suffix ? strlen(suffix) : 0); -} - -int readlinkat_malloc(int fd, const char *p, char **ret) { - size_t l = 100; - int r; - - assert(p); - assert(ret); - - for (;;) { - char *c; - ssize_t n; - - c = new(char, l); - if (!c) - return -ENOMEM; - - n = readlinkat(fd, p, c, l-1); - if (n < 0) { - r = -errno; - free(c); - return r; - } - - if ((size_t) n < l-1) { - c[n] = 0; - *ret = c; - return 0; - } - - free(c); - l *= 2; - } -} - -int readlink_malloc(const char *p, char **ret) { - return readlinkat_malloc(AT_FDCWD, p, ret); -} - -int readlink_value(const char *p, char **ret) { - _cleanup_free_ char *link = NULL; - char *value; - int r; - - r = readlink_malloc(p, &link); - if (r < 0) - return r; - - value = basename(link); - if (!value) - return -ENOENT; - - value = strdup(value); - if (!value) - return -ENOMEM; - - *ret = value; - - return 0; -} - -int readlink_and_make_absolute(const char *p, char **r) { - _cleanup_free_ char *target = NULL; - char *k; - int j; - - assert(p); - assert(r); - - j = readlink_malloc(p, &target); - if (j < 0) - return j; - - k = file_in_same_dir(p, target); - if (!k) - return -ENOMEM; - - *r = k; - return 0; -} - -int readlink_and_canonicalize(const char *p, char **r) { - char *t, *s; - int j; - - assert(p); - assert(r); - - j = readlink_and_make_absolute(p, &t); - if (j < 0) - return j; - - s = canonicalize_file_name(t); - if (s) { - free(t); - *r = s; - } else - *r = t; - - path_kill_slashes(*r); - - return 0; -} - -char *strstrip(char *s) { - char *e; - - /* Drops trailing whitespace. Modifies the string in - * place. Returns pointer to first non-space character */ - - s += strspn(s, WHITESPACE); - - for (e = strchr(s, 0); e > s; e --) - if (!strchr(WHITESPACE, e[-1])) - break; - - *e = 0; - - return s; -} - -char *delete_chars(char *s, const char *bad) { - char *f, *t; - - /* Drops all whitespace, regardless where in the string */ - - for (f = s, t = s; *f; f++) { - if (strchr(bad, *f)) - continue; - - *(t++) = *f; - } - - *t = 0; - - return s; -} - -char *file_in_same_dir(const char *path, const char *filename) { - char *e, *ret; - size_t k; - - assert(path); - assert(filename); - - /* This removes the last component of path and appends - * filename, unless the latter is absolute anyway or the - * former isn't */ - - if (path_is_absolute(filename)) - return strdup(filename); - - e = strrchr(path, '/'); - if (!e) - return strdup(filename); - - k = strlen(filename); - ret = new(char, (e + 1 - path) + k + 1); - if (!ret) - return NULL; - - memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1); - return ret; -} - -int rmdir_parents(const char *path, const char *stop) { - size_t l; - int r = 0; - - assert(path); - assert(stop); - - l = strlen(path); - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - while (l > 0) { - char *t; - - /* Skip last component */ - while (l > 0 && path[l-1] != '/') - l--; - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - if (l <= 0) - break; - - if (!(t = strndup(path, l))) - return -ENOMEM; - - if (path_startswith(stop, t)) { - free(t); - return 0; - } - - r = rmdir(t); - free(t); - - if (r < 0) - if (errno != ENOENT) - return -errno; - } - - return 0; -} - -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; - - return table[x & 15]; -} - -int unhexchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - return -EINVAL; -} - -char *hexmem(const void *p, size_t l) { - char *r, *z; - const uint8_t *x; - - z = r = malloc(l * 2 + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + l; x++) { - *(z++) = hexchar(*x >> 4); - *(z++) = hexchar(*x & 15); - } - - *z = 0; - return r; -} - -int unhexmem(const char *p, size_t l, void **mem, size_t *len) { - _cleanup_free_ uint8_t *r = NULL; - uint8_t *z; - const char *x; - - assert(mem); - assert(len); - assert(p); - - z = r = malloc((l + 1) / 2 + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + l; x += 2) { - int a, b; - - a = unhexchar(x[0]); - if (a < 0) - return a; - else if (x+1 < p + l) { - b = unhexchar(x[1]); - if (b < 0) - return b; - } else - b = 0; - - *(z++) = (uint8_t) a << 4 | (uint8_t) b; - } - - *z = 0; - - *mem = r; - r = NULL; - *len = (l + 1) / 2; - - return 0; -} - -/* https://tools.ietf.org/html/rfc4648#section-6 - * Notice that base32hex differs from base32 in the alphabet it uses. - * The distinction is that the base32hex representation preserves the - * order of the underlying data when compared as bytestrings, this is - * useful when representing NSEC3 hashes, as one can then verify the - * order of hashes directly from their representation. */ -char base32hexchar(int x) { - static const char table[32] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUV"; - - return table[x & 31]; -} - -int unbase32hexchar(char c) { - unsigned offset; - - if (c >= '0' && c <= '9') - return c - '0'; - - offset = '9' - '0' + 1; - - if (c >= 'A' && c <= 'V') - return c - 'A' + offset; - - return -EINVAL; -} - -char *base32hexmem(const void *p, size_t l, bool padding) { - char *r, *z; - const uint8_t *x; - size_t len; - - if (padding) - /* five input bytes makes eight output bytes, padding is added so we must round up */ - len = 8 * (l + 4) / 5; - else { - /* same, but round down as there is no padding */ - len = 8 * l / 5; - - switch (l % 5) { - case 4: - len += 7; - break; - case 3: - len += 5; - break; - case 2: - len += 4; - break; - case 1: - len += 2; - break; - } - } - - z = r = malloc(len + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { - /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ - x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ - *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ - *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */ - *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */ - } - - switch (l % 5) { - case 4: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ - *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ - *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */ - if (padding) - *(z++) = '='; - - break; - - case 3: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - - case 2: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - - case 1: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - } - - *z = 0; - return r; -} - -int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) { - _cleanup_free_ uint8_t *r = NULL; - int a, b, c, d, e, f, g, h; - uint8_t *z; - const char *x; - size_t len; - unsigned pad = 0; - - assert(p); - - /* padding ensures any base32hex input has input divisible by 8 */ - if (padding && l % 8 != 0) - return -EINVAL; - - if (padding) { - /* strip the padding */ - while (l > 0 && p[l - 1] == '=' && pad < 7) { - pad ++; - l --; - } - } - - /* a group of eight input bytes needs five output bytes, in case of - padding we need to add some extra bytes */ - len = (l / 8) * 5; - - switch (l % 8) { - case 7: - len += 4; - break; - case 5: - len += 3; - break; - case 4: - len += 2; - break; - case 2: - len += 1; - break; - case 0: - break; - default: - return -EINVAL; - } - - z = r = malloc(len + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + (l / 8) * 8; x += 8) { - /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW - e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - f = unbase32hexchar(x[5]); - if (f < 0) - return -EINVAL; - - g = unbase32hexchar(x[6]); - if (g < 0) - return -EINVAL; - - h = unbase32hexchar(x[7]); - if (h < 0) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ - *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */ - } - - switch (l % 8) { - case 7: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - f = unbase32hexchar(x[5]); - if (f < 0) - return -EINVAL; - - g = unbase32hexchar(x[6]); - if (g < 0) - return -EINVAL; - - /* g == 000VV000 */ - if (g & 7) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ - - break; - case 5: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - /* e == 000SSSS0 */ - if (e & 1) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - - break; - case 4: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - /* d == 000W0000 */ - if (d & 15) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - - break; - case 2: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - /* b == 000YYY00 */ - if (b & 3) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - - break; - case 0: - break; - default: - return -EINVAL; - } - - *z = 0; - - *mem = r; - r = NULL; - *_len = len; - - return 0; -} - -/* https://tools.ietf.org/html/rfc4648#section-4 */ -char base64char(int x) { - static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - return table[x & 63]; -} - -int unbase64char(char c) { - unsigned offset; - - if (c >= 'A' && c <= 'Z') - return c - 'A'; - - offset = 'Z' - 'A' + 1; - - if (c >= 'a' && c <= 'z') - return c - 'a' + offset; - - offset += 'z' - 'a' + 1; - - if (c >= '0' && c <= '9') - return c - '0' + offset; - - offset += '9' - '0' + 1; - - if (c == '+') - return offset; - - offset ++; - - if (c == '/') - return offset; - - return -EINVAL; -} - -char *base64mem(const void *p, size_t l) { - char *r, *z; - const uint8_t *x; - - /* three input bytes makes four output bytes, padding is added so we must round up */ - z = r = malloc(4 * (l + 2) / 3 + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { - /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ - *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ - *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ - } - - switch (l % 3) { - case 2: - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ - *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ - *(z++) = '='; - - break; - case 1: - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ - *(z++) = '='; - *(z++) = '='; - - break; - } - - *z = 0; - return r; -} - -int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { - _cleanup_free_ uint8_t *r = NULL; - int a, b, c, d; - uint8_t *z; - const char *x; - size_t len; - - assert(p); - - /* padding ensures any base63 input has input divisible by 4 */ - if (l % 4 != 0) - return -EINVAL; - - /* strip the padding */ - if (l > 0 && p[l - 1] == '=') - l --; - if (l > 0 && p[l - 1] == '=') - l --; - - /* a group of four input bytes needs three output bytes, in case of - padding we need to add two or three extra bytes */ - len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); - - z = r = malloc(len + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + (l / 4) * 4; x += 4) { - /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase64char(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase64char(x[3]); - if (d < 0) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ - } - - switch (l % 4) { - case 3: - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase64char(x[2]); - if (c < 0) - return -EINVAL; - - /* c == 00ZZZZ00 */ - if (c & 3) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - - break; - case 2: - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - /* b == 00YY0000 */ - if (b & 15) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ - - break; - case 0: - - break; - default: - return -EINVAL; - } - - *z = 0; - - *mem = r; - r = NULL; - *_len = len; - - return 0; -} - -char octchar(int x) { - return '0' + (x & 7); -} - -int unoctchar(char c) { - - if (c >= '0' && c <= '7') - return c - '0'; - - return -EINVAL; -} - -char decchar(int x) { - return '0' + (x % 10); -} - -int undecchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - return -EINVAL; -} - -char *cescape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Does C style string escaping. May be reversed with - * cunescape(). */ - - r = new(char, strlen(s)*4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) - t += cescape_char(*f, t); - - *t = 0; - - return r; -} - -static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { - int r = 1; - - assert(p); - assert(*p); - assert(ret); - - /* Unescapes C style. Returns the unescaped character in ret, - * unless we encountered a \u sequence in which case the full - * unicode character is returned in ret_unicode, instead. */ - - if (length != (size_t) -1 && length < 1) - return -EINVAL; - - switch (p[0]) { - - case 'a': - *ret = '\a'; - break; - case 'b': - *ret = '\b'; - break; - case 'f': - *ret = '\f'; - break; - case 'n': - *ret = '\n'; - break; - case 'r': - *ret = '\r'; - break; - case 't': - *ret = '\t'; - break; - case 'v': - *ret = '\v'; - break; - case '\\': - *ret = '\\'; - break; - case '"': - *ret = '"'; - break; - case '\'': - *ret = '\''; - break; - - case 's': - /* This is an extension of the XDG syntax files */ - *ret = ' '; - break; - - case 'x': { - /* hexadecimal encoding */ - int a, b; - - if (length != (size_t) -1 && length < 3) - return -EINVAL; - - a = unhexchar(p[1]); - if (a < 0) - return -EINVAL; - - b = unhexchar(p[2]); - if (b < 0) - return -EINVAL; - - /* Don't allow NUL bytes */ - if (a == 0 && b == 0) - return -EINVAL; - - *ret = (char) ((a << 4U) | b); - r = 3; - break; - } - - case 'u': { - /* C++11 style 16bit unicode */ - - int a[4]; - unsigned i; - uint32_t c; - - if (length != (size_t) -1 && length < 5) - return -EINVAL; - - for (i = 0; i < 4; i++) { - a[i] = unhexchar(p[1 + i]); - if (a[i] < 0) - return a[i]; - } - - c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; - - /* Don't allow 0 chars */ - if (c == 0) - return -EINVAL; - - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - - r = 5; - break; - } - - case 'U': { - /* C++11 style 32bit unicode */ - - int a[8]; - unsigned i; - uint32_t c; - - if (length != (size_t) -1 && length < 9) - return -EINVAL; - - for (i = 0; i < 8; i++) { - a[i] = unhexchar(p[1 + i]); - if (a[i] < 0) - return a[i]; - } - - c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | - ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; - - /* Don't allow 0 chars */ - if (c == 0) - return -EINVAL; - - /* Don't allow invalid code points */ - if (!unichar_is_valid(c)) - return -EINVAL; - - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - - r = 9; - break; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - /* octal encoding */ - int a, b, c; - uint32_t m; - - if (length != (size_t) -1 && length < 3) - return -EINVAL; - - a = unoctchar(p[0]); - if (a < 0) - return -EINVAL; - - b = unoctchar(p[1]); - if (b < 0) - return -EINVAL; - - c = unoctchar(p[2]); - if (c < 0) - return -EINVAL; - - /* don't allow NUL bytes */ - if (a == 0 && b == 0 && c == 0) - return -EINVAL; - - /* Don't allow bytes above 255 */ - m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; - if (m > 255) - return -EINVAL; - - *ret = m; - r = 3; - break; - } - - default: - return -EINVAL; - } - - return r; -} - -int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) { - char *r, *t; - const char *f; - size_t pl; - - assert(s); - assert(ret); - - /* Undoes C style string escaping, and optionally prefixes it. */ - - pl = prefix ? strlen(prefix) : 0; - - r = new(char, pl+length+1); - if (!r) - return -ENOMEM; - - if (prefix) - memcpy(r, prefix, pl); - - for (f = s, t = r + pl; f < s + length; f++) { - size_t remaining; - uint32_t u; - char c; - int k; - - remaining = s + length - f; - assert(remaining > 0); - - if (*f != '\\') { - /* A literal literal, copy verbatim */ - *(t++) = *f; - continue; - } - - if (remaining == 1) { - if (flags & UNESCAPE_RELAX) { - /* A trailing backslash, copy verbatim */ - *(t++) = *f; - continue; - } - - free(r); - return -EINVAL; - } - - k = cunescape_one(f + 1, remaining - 1, &c, &u); - if (k < 0) { - if (flags & UNESCAPE_RELAX) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - continue; - } - - free(r); - return k; - } - - if (c != 0) - /* Non-Unicode? Let's encode this directly */ - *(t++) = c; - else - /* Unicode? Then let's encode this in UTF-8 */ - t += utf8_encode_unichar(t, u); - - f += k; - } - - *t = 0; - - *ret = r; - return t - r; -} - -int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { - return cunescape_length_with_prefix(s, length, NULL, flags, ret); -} - -int cunescape(const char *s, UnescapeFlags flags, char **ret) { - return cunescape_length(s, strlen(s), flags, ret); -} - -char *xescape(const char *s, const char *bad) { - char *r, *t; - const char *f; - - /* Escapes all chars in bad, in addition to \ and all special - * chars, in \xFF style escaping. May be reversed with - * cunescape(). */ - - r = new(char, strlen(s) * 4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) { - - if ((*f < ' ') || (*f >= 127) || - (*f == '\\') || strchr(bad, *f)) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *ascii_strlower(char *t) { - char *p; - - assert(t); - - for (p = t; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; - - return t; -} - -_pure_ static bool hidden_file_allow_backup(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".dpkg-tmp") || - endswith(filename, ".dpkg-dist") || - endswith(filename, ".dpkg-bak") || - endswith(filename, ".dpkg-backup") || - endswith(filename, ".dpkg-remove") || - endswith(filename, ".swp"); -} - -bool hidden_file(const char *filename) { - assert(filename); - - if (endswith(filename, "~")) - return true; - - return hidden_file_allow_backup(filename); -} - -int fd_nonblock(int fd, bool nonblock) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) - return -errno; - - if (nonblock) - nflags = flags | O_NONBLOCK; - else - nflags = flags & ~O_NONBLOCK; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFL, nflags) < 0) - return -errno; - - return 0; -} - -int fd_cloexec(int fd, bool cloexec) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFD, 0); - if (flags < 0) - return -errno; - - if (cloexec) - nflags = flags | FD_CLOEXEC; - else - nflags = flags & ~FD_CLOEXEC; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFD, nflags) < 0) - return -errno; - - return 0; -} - -_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { - unsigned i; - - assert(n_fdset == 0 || fdset); - - for (i = 0; i < n_fdset; i++) - if (fdset[i] == fd) - return true; - - return false; -} - -int close_all_fds(const int except[], unsigned n_except) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r = 0; - - assert(n_except == 0 || except); - - d = opendir("/proc/self/fd"); - if (!d) { - int fd; - struct rlimit rl; - - /* When /proc isn't available (for example in chroots) - * the fallback is brute forcing through the fd - * table */ - - assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - for (fd = 3; fd < (int) rl.rlim_max; fd ++) { - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) - if (errno != EBADF && r == 0) - r = -errno; - } - - return r; - } - - while ((de = readdir(d))) { - int fd = -1; - - if (hidden_file(de->d_name)) - continue; - - if (safe_atoi(de->d_name, &fd) < 0) - /* Let's better ignore this, just in case */ - continue; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) { - /* Valgrind has its own FD and doesn't want to have it closed */ - if (errno != EBADF && r == 0) - r = -errno; - } - } - - return r; -} - -bool chars_intersect(const char *a, const char *b) { - const char *p; - - /* Returns true if any of the chars in a are in b. */ - for (p = a; *p; p++) - if (strchr(b, *p)) - return true; - - return false; -} - -bool fstype_is_network(const char *fstype) { - static const char table[] = - "afs\0" - "cifs\0" - "smbfs\0" - "sshfs\0" - "ncpfs\0" - "ncp\0" - "nfs\0" - "nfs4\0" - "gfs\0" - "gfs2\0" - "glusterfs\0"; - - const char *x; - - x = startswith(fstype, "fuse."); - if (x) - fstype = x; - - return nulstr_contains(table, fstype); -} - -int flush_fd(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN, - }; - - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; - - r = poll(&pollfd, 1, 0); - if (r < 0) { - if (errno == EINTR) - continue; - - return -errno; - - } else if (r == 0) - return 0; - - l = read(fd, buf, sizeof(buf)); - if (l < 0) { - - if (errno == EINTR) - continue; - - if (errno == EAGAIN) - return 0; - - return -errno; - } else if (l == 0) - return 0; - } -} - -void safe_close_pair(int p[]) { - assert(p); - - if (p[0] == p[1]) { - /* Special case pairs which use the same fd in both - * directions... */ - p[0] = p[1] = safe_close(p[0]); - return; - } - - p[0] = safe_close(p[0]); - p[1] = safe_close(p[1]); -} - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p = buf; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - /* If called with nbytes == 0, let's call read() at least - * once, to validate the operation */ - - if (nbytes > (size_t) SSIZE_MAX) - return -EINVAL; - - do { - ssize_t k; - - k = read(fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; - - if (errno == EAGAIN && do_poll) { - - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via read() */ - - (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); - continue; - } - - return n > 0 ? n : -errno; - } - - if (k == 0) - return n; - - assert((size_t) k <= nbytes); - - p += k; - nbytes -= k; - n += k; - } while (nbytes > 0); - - return n; -} - -int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { - ssize_t n; - - n = loop_read(fd, buf, nbytes, do_poll); - if (n < 0) - return (int) n; - if ((size_t) n != nbytes) - return -EIO; - - return 0; -} - -int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { - const uint8_t *p = buf; - - assert(fd >= 0); - assert(buf); - - if (nbytes > (size_t) SSIZE_MAX) - return -EINVAL; - - do { - ssize_t k; - - k = write(fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; - - if (errno == EAGAIN && do_poll) { - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via write() */ - - (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); - continue; - } - - return -errno; - } - - if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */ - return -EIO; - - assert((size_t) k <= nbytes); - - p += k; - nbytes -= k; - } while (nbytes > 0); - - return 0; -} - -int parse_size(const char *t, uint64_t base, uint64_t *size) { - - /* Soo, sometimes we want to parse IEC binary suffixes, and - * sometimes SI decimal suffixes. This function can parse - * both. Which one is the right way depends on the - * context. Wikipedia suggests that SI is customary for - * hardware metrics and network speeds, while IEC is - * customary for most data sizes used by software and volatile - * (RAM) memory. Hence be careful which one you pick! - * - * In either case we use just K, M, G as suffix, and not Ki, - * Mi, Gi or so (as IEC would suggest). That's because that's - * frickin' ugly. But this means you really need to make sure - * to document which base you are parsing when you use this - * call. */ - - struct table { - const char *suffix; - unsigned long long factor; - }; - - static const struct table iec[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, - { "B", 1ULL }, - { "", 1ULL }, - }; - - static const struct table si[] = { - { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, - { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, - { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, - { "G", 1000ULL*1000ULL*1000ULL }, - { "M", 1000ULL*1000ULL }, - { "K", 1000ULL }, - { "B", 1ULL }, - { "", 1ULL }, - }; - - const struct table *table; - const char *p; - unsigned long long r = 0; - unsigned n_entries, start_pos = 0; - - assert(t); - assert(base == 1000 || base == 1024); - assert(size); - - if (base == 1000) { - table = si; - n_entries = ELEMENTSOF(si); - } else { - table = iec; - n_entries = ELEMENTSOF(iec); - } - - p = t; - do { - unsigned long long l, tmp; - double frac = 0; - char *e; - unsigned i; - - p += strspn(p, WHITESPACE); - if (*p == '-') - return -ERANGE; - - errno = 0; - l = strtoull(p, &e, 10); - if (errno > 0) - return -errno; - if (e == p) - return -EINVAL; - - if (*e == '.') { - e++; - - /* strtoull() itself would accept space/+/- */ - if (*e >= '0' && *e <= '9') { - unsigned long long l2; - char *e2; - - l2 = strtoull(e, &e2, 10); - if (errno > 0) - return -errno; - - /* Ignore failure. E.g. 10.M is valid */ - frac = l2; - for (; e < e2; e++) - frac /= 10; - } - } - - e += strspn(e, WHITESPACE); - - for (i = start_pos; i < n_entries; i++) - if (startswith(e, table[i].suffix)) - break; - - if (i >= n_entries) - return -EINVAL; - - if (l + (frac > 0) > ULLONG_MAX / table[i].factor) - return -ERANGE; - - tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); - if (tmp > ULLONG_MAX - r) - return -ERANGE; - - r += tmp; - if ((unsigned long long) (uint64_t) r != r) - return -ERANGE; - - p = e + strlen(table[i].suffix); - - start_pos = i + 1; - - } while (*p); - - *size = r; - - return 0; -} - -bool is_device_path(const char *path) { - - /* Returns true on paths that refer to a device, either in - * sysfs or in /dev */ - - return - path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); -} - -int dir_is_empty(const char *path) { - _cleanup_closedir_ DIR *d; - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - - if (!de) - return 1; - - if (!hidden_file(de->d_name)) - return 0; - } -} - -char* dirname_malloc(const char *path) { - char *d, *dir, *dir2; - - d = strdup(path); - if (!d) - return NULL; - dir = dirname(d); - assert(dir); - - if (dir != d) { - dir2 = strdup(dir); - free(d); - return dir2; - } - - return dir; -} - -void rename_process(const char name[8]) { - assert(name); - - /* This is a like a poor man's setproctitle(). It changes the - * comm field, argv[0], and also the glibc's internally used - * name of the process. For the first one a limit of 16 chars - * applies, to the second one usually one of 10 (i.e. length - * of "/sbin/init"), to the third one one of 7 (i.e. length of - * "systemd"). If you pass a longer string it will be - * truncated */ - - prctl(PR_SET_NAME, name); - - if (program_invocation_name) - strncpy(program_invocation_name, name, strlen(program_invocation_name)); - - if (saved_argc > 0) { - int i; - - if (saved_argv[0]) - strncpy(saved_argv[0], name, strlen(saved_argv[0])); - - for (i = 1; i < saved_argc; i++) { - if (!saved_argv[i]) - break; - - memzero(saved_argv[i], strlen(saved_argv[i])); - } - } -} - -char *lookup_uid(uid_t uid) { - long bufsize; - char *name; - _cleanup_free_ char *buf = NULL; - struct passwd pwbuf, *pw = NULL; - - /* Shortcut things to avoid NSS lookups */ - if (uid == 0) - return strdup("root"); - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize <= 0) - bufsize = 4096; - - buf = malloc(bufsize); - if (!buf) - return NULL; - - if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) - return strdup(pw->pw_name); - - if (asprintf(&name, UID_FMT, uid) < 0) - return NULL; - - return name; -} - -char* getlogname_malloc(void) { - uid_t uid; - struct stat st; - - if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) - uid = st.st_uid; - else - uid = getuid(); - - return lookup_uid(uid); -} - -char *getusername_malloc(void) { - const char *e; - - e = getenv("USER"); - if (e) - return strdup(e); - - return lookup_uid(getuid()); -} - -bool is_temporary_fs(const struct statfs *s) { - assert(s); - - return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) || - F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC); -} - -int fd_is_temporary_fs(int fd) { - struct statfs s; - - if (fstatfs(fd, &s) < 0) - return -errno; - - return is_temporary_fs(&s); -} - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { - assert(path); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != MODE_INVALID) - if (chmod(path, mode) < 0) - return -errno; - - if (uid != UID_INVALID || gid != GID_INVALID) - if (chown(path, uid, gid) < 0) - return -errno; - - return 0; -} - -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { - assert(fd >= 0); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != MODE_INVALID) - if (fchmod(fd, mode) < 0) - return -errno; - - if (uid != UID_INVALID || gid != GID_INVALID) - if (fchown(fd, uid, gid) < 0) - return -errno; - - return 0; -} - -int files_same(const char *filea, const char *fileb) { - struct stat a, b; - - if (stat(filea, &a) < 0) - return -errno; - - if (stat(fileb, &b) < 0) - return -errno; - - return a.st_dev == b.st_dev && - a.st_ino == b.st_ino; -} - -int running_in_chroot(void) { - int ret; - - ret = files_same("/proc/1/root", "/"); - if (ret < 0) - return ret; - - return ret == 0; -} - -static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *r; - - assert(s); - assert(percent <= 100); - assert(new_length >= 3); - - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - r = new0(char, new_length+1); - if (!r) - return NULL; - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; - - memcpy(r, s, x); - r[x] = '.'; - r[x+1] = '.'; - r[x+2] = '.'; - memcpy(r + x + 3, - s + old_length - (new_length - x - 3), - new_length - x - 3); - - return r; -} - -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *e; - const char *i, *j; - unsigned k, len, len2; - - assert(s); - assert(percent <= 100); - assert(new_length >= 3); - - /* if no multibyte characters use ascii_ellipsize_mem for speed */ - if (ascii_is_valid(s)) - return ascii_ellipsize_mem(s, old_length, new_length, percent); - - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; - - k = 0; - for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { - int c; - - c = utf8_encoded_to_unichar(i); - if (c < 0) - return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - - if (k > x) /* last character was wide and went over quota */ - x ++; - - for (j = s + old_length; k < new_length && j > i; ) { - int c; - - j = utf8_prev_char(j); - c = utf8_encoded_to_unichar(j); - if (c < 0) - return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - assert(i <= j); - - /* we don't actually need to ellipsize */ - if (i == j) - return memdup(s, old_length + 1); - - /* make space for ellipsis */ - j = utf8_next_char(j); - - len = i - s; - len2 = s + old_length - j; - e = new(char, len + 3 + len2 + 1); - if (!e) - return NULL; - - /* - printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", - old_length, new_length, x, len, len2, k); - */ - - memcpy(e, s, len); - e[len] = 0xe2; /* tri-dot ellipsis: … */ - e[len + 1] = 0x80; - e[len + 2] = 0xa6; - - memcpy(e + len + 3, j, len2 + 1); - - return e; -} - -char *ellipsize(const char *s, size_t length, unsigned percent) { - return ellipsize_mem(s, strlen(s), length, percent); -} - -int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { - _cleanup_close_ int fd; - int r; - - assert(path); - - if (parents) - mkdir_parents(path, 0755); - - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); - if (fd < 0) - return -errno; - - if (mode > 0) { - r = fchmod(fd, mode); - if (r < 0) - return -errno; - } - - if (uid != UID_INVALID || gid != GID_INVALID) { - r = fchown(fd, uid, gid); - if (r < 0) - return -errno; - } - - if (stamp != USEC_INFINITY) { - struct timespec ts[2]; - - timespec_store(&ts[0], stamp); - ts[1] = ts[0]; - r = futimens(fd, ts); - } else - r = futimens(fd, NULL); - if (r < 0) - return -errno; - - return 0; -} - -int touch(const char *path) { - return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0); -} - -static char *unquote(const char *s, const char* quotes) { - size_t l; - assert(s); - - /* This is rather stupid, simply removes the heading and - * trailing quotes if there is one. Doesn't care about - * escaping or anything. - * - * DON'T USE THIS FOR NEW CODE ANYMORE!*/ - - l = strlen(s); - if (l < 2) - return strdup(s); - - if (strchr(quotes, s[0]) && s[l-1] == s[0]) - return strndup(s+1, l-2); - - return strdup(s); -} - -noreturn void freeze(void) { - - /* Make sure nobody waits for us on a socket anymore */ - close_all_fds(NULL, 0); - - sync(); - - for (;;) - pause(); -} - -bool null_or_empty(struct stat *st) { - assert(st); - - if (S_ISREG(st->st_mode) && st->st_size <= 0) - return true; - - if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - return true; - - return false; -} - -int null_or_empty_path(const char *fn) { - struct stat st; - - assert(fn); - - if (stat(fn, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -int null_or_empty_fd(int fd) { - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -DIR *xopendirat(int fd, const char *name, int flags) { - int nfd; - DIR *d; - - assert(!(flags & O_CREAT)); - - nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); - if (nfd < 0) - return NULL; - - d = fdopendir(nfd); - if (!d) { - safe_close(nfd); - return NULL; - } - - return d; -} - -static char *tag_to_udev_node(const char *tagvalue, const char *by) { - _cleanup_free_ char *t = NULL, *u = NULL; - size_t enc_len; - - u = unquote(tagvalue, QUOTES); - if (!u) - return NULL; - - enc_len = strlen(u) * 4 + 1; - t = new(char, enc_len); - if (!t) - return NULL; - - if (encode_devnode_name(u, t, enc_len) < 0) - return NULL; - - return strjoin("/dev/disk/by-", by, "/", t, NULL); -} - -char *fstab_node_to_udev_node(const char *p) { - assert(p); - - if (startswith(p, "LABEL=")) - return tag_to_udev_node(p+6, "label"); - - if (startswith(p, "UUID=")) - return tag_to_udev_node(p+5, "uuid"); - - if (startswith(p, "PARTUUID=")) - return tag_to_udev_node(p+9, "partuuid"); - - if (startswith(p, "PARTLABEL=")) - return tag_to_udev_node(p+10, "partlabel"); - - return strdup(p); -} - -bool dirent_is_file(const struct dirent *de) { - assert(de); - - if (hidden_file(de->d_name)) - return false; - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - return true; -} - -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { - assert(de); - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - if (hidden_file_allow_backup(de->d_name)) - return false; - - return endswith(de->d_name, suffix); -} - static int do_execute(char **directories, usec_t timeout, char *argv[]) { _cleanup_hashmap_free_free_ Hashmap *pids = NULL; _cleanup_set_free_free_ Set *seen = NULL; @@ -3015,189 +265,10 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a wait_for_terminate_and_warn(name, executor_pid, true); } -bool nulstr_contains(const char*nulstr, const char *needle) { - const char *i; - - if (!nulstr) - return false; - - NULSTR_FOREACH(i, nulstr) - if (streq(i, needle)) - return true; - - return false; -} - bool plymouth_running(void) { return access("/run/plymouth/pid", F_OK) >= 0; } -char* strshorten(char *s, size_t l) { - assert(s); - - if (l < strlen(s)) - s[l] = 0; - - return s; -} - -int pipe_eof(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN|POLLHUP, - }; - - int r; - - r = poll(&pollfd, 1, 0); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents & POLLHUP; -} - -int fd_wait_for_event(int fd, int event, usec_t t) { - - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; - - struct timespec ts; - int r; - - r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents; -} - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { - FILE *f; - char *t; - int r, fd; - - assert(path); - assert(_f); - assert(_temp_path); - - r = tempfn_xxxxxx(path, NULL, &t); - if (r < 0) - return r; - - fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - free(t); - return -errno; - } - - f = fdopen(fd, "we"); - if (!f) { - unlink_noerrno(t); - free(t); - safe_close(fd); - return -errno; - } - - *_f = f; - *_temp_path = t; - - return 0; -} - -int symlink_atomic(const char *from, const char *to) { - _cleanup_free_ char *t = NULL; - int r; - - assert(from); - assert(to); - - r = tempfn_random(to, NULL, &t); - if (r < 0) - return r; - - if (symlink(from, t) < 0) - return -errno; - - if (rename(t, to) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -int symlink_idempotent(const char *from, const char *to) { - _cleanup_free_ char *p = NULL; - int r; - - assert(from); - assert(to); - - if (symlink(from, to) < 0) { - if (errno != EEXIST) - return -errno; - - r = readlink_malloc(to, &p); - if (r < 0) - return r; - - if (!streq(p, from)) - return -EINVAL; - } - - return 0; -} - -int mknod_atomic(const char *path, mode_t mode, dev_t dev) { - _cleanup_free_ char *t = NULL; - int r; - - assert(path); - - r = tempfn_random(path, NULL, &t); - if (r < 0) - return r; - - if (mknod(t, mode, dev) < 0) - return -errno; - - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -int mkfifo_atomic(const char *path, mode_t mode) { - _cleanup_free_ char *t = NULL; - int r; - - assert(path); - - r = tempfn_random(path, NULL, &t); - if (r < 0) - return r; - - if (mkfifo(t, mode) < 0) - return -errno; - - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - bool display_is_local(const char *display) { assert(display); @@ -3232,368 +303,6 @@ int socket_from_display(const char *display, char **path) { return 0; } -int get_user_creds( - const char **username, - uid_t *uid, gid_t *gid, - const char **home, - const char **shell) { - - struct passwd *p; - uid_t u; - - assert(username); - assert(*username); - - /* We enforce some special rules for uid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*username, "root") || streq(*username, "0")) { - *username = "root"; - - if (uid) - *uid = 0; - - if (gid) - *gid = 0; - - if (home) - *home = "/root"; - - if (shell) - *shell = "/bin/sh"; - - return 0; - } - - if (parse_uid(*username, &u) >= 0) { - errno = 0; - p = getpwuid(u); - - /* If there are multiple users with the same id, make - * sure to leave $USER to the configured value instead - * of the first occurrence in the database. However if - * the uid was configured by a numeric uid, then let's - * pick the real username from /etc/passwd. */ - if (p) - *username = p->pw_name; - } else { - errno = 0; - p = getpwnam(*username); - } - - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (uid) - *uid = p->pw_uid; - - if (gid) - *gid = p->pw_gid; - - if (home) - *home = p->pw_dir; - - if (shell) - *shell = p->pw_shell; - - return 0; -} - -char* uid_to_name(uid_t uid) { - struct passwd *p; - char *r; - - if (uid == 0) - return strdup("root"); - - p = getpwuid(uid); - if (p) - return strdup(p->pw_name); - - if (asprintf(&r, UID_FMT, uid) < 0) - return NULL; - - return r; -} - -char* gid_to_name(gid_t gid) { - struct group *p; - char *r; - - if (gid == 0) - return strdup("root"); - - p = getgrgid(gid); - if (p) - return strdup(p->gr_name); - - if (asprintf(&r, GID_FMT, gid) < 0) - return NULL; - - return r; -} - -int get_group_creds(const char **groupname, gid_t *gid) { - struct group *g; - gid_t id; - - assert(groupname); - - /* We enforce some special rules for gid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*groupname, "root") || streq(*groupname, "0")) { - *groupname = "root"; - - if (gid) - *gid = 0; - - return 0; - } - - if (parse_gid(*groupname, &id) >= 0) { - errno = 0; - g = getgrgid(id); - - if (g) - *groupname = g->gr_name; - } else { - errno = 0; - g = getgrnam(*groupname); - } - - if (!g) - return errno > 0 ? -errno : -ESRCH; - - if (gid) - *gid = g->gr_gid; - - return 0; -} - -int in_gid(gid_t gid) { - gid_t *gids; - int ngroups_max, r, i; - - if (getgid() == gid) - return 1; - - if (getegid() == gid) - return 1; - - ngroups_max = sysconf(_SC_NGROUPS_MAX); - assert(ngroups_max > 0); - - gids = alloca(sizeof(gid_t) * ngroups_max); - - r = getgroups(ngroups_max, gids); - if (r < 0) - return -errno; - - for (i = 0; i < r; i++) - if (gids[i] == gid) - return 1; - - return 0; -} - -int in_group(const char *name) { - int r; - gid_t gid; - - r = get_group_creds(&name, &gid); - if (r < 0) - return r; - - return in_gid(gid); -} - -int glob_exists(const char *path) { - _cleanup_globfree_ glob_t g = {}; - int k; - - assert(path); - - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - return 0; - else if (k == GLOB_NOSPACE) - return -ENOMEM; - else if (k == 0) - return !strv_isempty(g.gl_pathv); - else - return errno ? -errno : -EIO; -} - -int glob_extend(char ***strv, const char *path) { - _cleanup_globfree_ glob_t g = {}; - int k; - char **p; - - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - return -ENOENT; - else if (k == GLOB_NOSPACE) - return -ENOMEM; - else if (k != 0 || strv_isempty(g.gl_pathv)) - return errno ? -errno : -EIO; - - STRV_FOREACH(p, g.gl_pathv) { - k = strv_extend(strv, *p); - if (k < 0) - break; - } - - return k; -} - -int dirent_ensure_type(DIR *d, struct dirent *de) { - struct stat st; - - assert(d); - assert(de); - - if (de->d_type != DT_UNKNOWN) - return 0; - - if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) - return -errno; - - de->d_type = - S_ISREG(st.st_mode) ? DT_REG : - S_ISDIR(st.st_mode) ? DT_DIR : - S_ISLNK(st.st_mode) ? DT_LNK : - S_ISFIFO(st.st_mode) ? DT_FIFO : - S_ISSOCK(st.st_mode) ? DT_SOCK : - S_ISCHR(st.st_mode) ? DT_CHR : - S_ISBLK(st.st_mode) ? DT_BLK : - DT_UNKNOWN; - - return 0; -} - -int get_files_in_directory(const char *path, char ***list) { - _cleanup_closedir_ DIR *d = NULL; - size_t bufsize = 0, n = 0; - _cleanup_strv_free_ char **l = NULL; - - assert(path); - - /* Returns all files in a directory in *list, and the number - * of files as return value. If list is NULL returns only the - * number. */ - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - if (!de) - break; - - dirent_ensure_type(d, de); - - if (!dirent_is_file(de)) - continue; - - if (list) { - /* one extra slot is needed for the terminating NULL */ - if (!GREEDY_REALLOC(l, bufsize, n + 2)) - return -ENOMEM; - - l[n] = strdup(de->d_name); - if (!l[n]) - return -ENOMEM; - - l[++n] = NULL; - } else - n++; - } - - if (list) { - *list = l; - l = NULL; /* avoid freeing */ - } - - return n; -} - -char *strjoin(const char *x, ...) { - va_list ap; - size_t l; - char *r, *p; - - va_start(ap, x); - - if (x) { - l = strlen(x); - - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - } else - l = 0; - - va_end(ap); - - r = new(char, l+1); - if (!r) - return NULL; - - if (x) { - p = stpcpy(r, x); - - va_start(ap, x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - - va_end(ap); - } else - r[0] = 0; - - return r; -} - -bool is_main_thread(void) { - static thread_local int cached = 0; - - if (_unlikely_(cached == 0)) - cached = getpid() == gettid() ? 1 : -1; - - return cached > 0; -} - int block_get_whole_disk(dev_t d, dev_t *ret) { char *p, *s; int r; @@ -3654,104 +363,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret) { return -ENOENT; } -static const char *const ioprio_class_table[] = { - [IOPRIO_CLASS_NONE] = "none", - [IOPRIO_CLASS_RT] = "realtime", - [IOPRIO_CLASS_BE] = "best-effort", - [IOPRIO_CLASS_IDLE] = "idle" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); - -static const char *const sigchld_code_table[] = { - [CLD_EXITED] = "exited", - [CLD_KILLED] = "killed", - [CLD_DUMPED] = "dumped", - [CLD_TRAPPED] = "trapped", - [CLD_STOPPED] = "stopped", - [CLD_CONTINUED] = "continued", -}; - -DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); - -static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { - [LOG_FAC(LOG_KERN)] = "kern", - [LOG_FAC(LOG_USER)] = "user", - [LOG_FAC(LOG_MAIL)] = "mail", - [LOG_FAC(LOG_DAEMON)] = "daemon", - [LOG_FAC(LOG_AUTH)] = "auth", - [LOG_FAC(LOG_SYSLOG)] = "syslog", - [LOG_FAC(LOG_LPR)] = "lpr", - [LOG_FAC(LOG_NEWS)] = "news", - [LOG_FAC(LOG_UUCP)] = "uucp", - [LOG_FAC(LOG_CRON)] = "cron", - [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", - [LOG_FAC(LOG_FTP)] = "ftp", - [LOG_FAC(LOG_LOCAL0)] = "local0", - [LOG_FAC(LOG_LOCAL1)] = "local1", - [LOG_FAC(LOG_LOCAL2)] = "local2", - [LOG_FAC(LOG_LOCAL3)] = "local3", - [LOG_FAC(LOG_LOCAL4)] = "local4", - [LOG_FAC(LOG_LOCAL5)] = "local5", - [LOG_FAC(LOG_LOCAL6)] = "local6", - [LOG_FAC(LOG_LOCAL7)] = "local7" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); - -static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", - [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); - -static const char* const sched_policy_table[] = { - [SCHED_OTHER] = "other", - [SCHED_BATCH] = "batch", - [SCHED_IDLE] = "idle", - [SCHED_FIFO] = "fifo", - [SCHED_RR] = "rr" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); - -static const char* const rlimit_table[_RLIMIT_MAX] = { - [RLIMIT_CPU] = "LimitCPU", - [RLIMIT_FSIZE] = "LimitFSIZE", - [RLIMIT_DATA] = "LimitDATA", - [RLIMIT_STACK] = "LimitSTACK", - [RLIMIT_CORE] = "LimitCORE", - [RLIMIT_RSS] = "LimitRSS", - [RLIMIT_NOFILE] = "LimitNOFILE", - [RLIMIT_AS] = "LimitAS", - [RLIMIT_NPROC] = "LimitNPROC", - [RLIMIT_MEMLOCK] = "LimitMEMLOCK", - [RLIMIT_LOCKS] = "LimitLOCKS", - [RLIMIT_SIGPENDING] = "LimitSIGPENDING", - [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", - [RLIMIT_NICE] = "LimitNICE", - [RLIMIT_RTPRIO] = "LimitRTPRIO", - [RLIMIT_RTTIME] = "LimitRTTIME" -}; - -DEFINE_STRING_TABLE_LOOKUP(rlimit, int); - -static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", - [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); - bool kexec_loaded(void) { bool loaded = false; char *s; @@ -3782,93 +393,6 @@ int prot_from_flags(int flags) { } } -char *format_bytes(char *buf, size_t l, uint64_t t) { - unsigned i; - - static const struct { - const char *suffix; - uint64_t factor; - } table[] = { - { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "M", UINT64_C(1024)*UINT64_C(1024) }, - { "K", UINT64_C(1024) }, - }; - - if (t == (uint64_t) -1) - return NULL; - - for (i = 0; i < ELEMENTSOF(table); i++) { - - if (t >= table[i].factor) { - snprintf(buf, l, - "%" PRIu64 ".%" PRIu64 "%s", - t / table[i].factor, - ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), - table[i].suffix); - - goto finish; - } - } - - snprintf(buf, l, "%" PRIu64 "B", t); - -finish: - buf[l-1] = 0; - return buf; - -} - -void* memdup(const void *p, size_t l) { - void *r; - - assert(p); - - r = malloc(l); - if (!r) - return NULL; - - memcpy(r, p, l); - return r; -} - -int fd_inc_sndbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) - return 0; - - /* If we have the privileges we will ignore the kernel limit. */ - - value = (int) n; - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) - return -errno; - - return 1; -} - -int fd_inc_rcvbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) - return 0; - - /* If we have the privileges we will ignore the kernel limit. */ - - value = (int) n; - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) - return -errno; - return 1; -} - int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { bool stdout_is_tty, stderr_is_tty; pid_t parent_pid, agent_pid; @@ -3971,82 +495,6 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa _exit(EXIT_FAILURE); } -int setrlimit_closest(int resource, const struct rlimit *rlim) { - struct rlimit highest, fixed; - - assert(rlim); - - if (setrlimit(resource, rlim) >= 0) - return 0; - - if (errno != EPERM) - return -errno; - - /* So we failed to set the desired setrlimit, then let's try - * to get as close as we can */ - assert_se(getrlimit(resource, &highest) == 0); - - fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); - fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); - - if (setrlimit(resource, &fixed) < 0) - return -errno; - - return 0; -} - -bool http_etag_is_valid(const char *etag) { - if (isempty(etag)) - return false; - - if (!endswith(etag, "\"")) - return false; - - if (!startswith(etag, "\"") && !startswith(etag, "W/\"")) - return false; - - return true; -} - -bool http_url_is_valid(const char *url) { - const char *p; - - if (isempty(url)) - return false; - - p = startswith(url, "http://"); - if (!p) - p = startswith(url, "https://"); - if (!p) - return false; - - if (isempty(p)) - return false; - - return ascii_is_valid(p); -} - -bool documentation_url_is_valid(const char *url) { - const char *p; - - if (isempty(url)) - return false; - - if (http_url_is_valid(url)) - return true; - - p = startswith(url, "file:/"); - if (!p) - p = startswith(url, "info:"); - if (!p) - p = startswith(url, "man:"); - - if (isempty(p)) - return false; - - return ascii_is_valid(p); -} - bool in_initrd(void) { static int saved = -1; struct statfs s; @@ -4071,181 +519,6 @@ bool in_initrd(void) { return saved; } -int get_home_dir(char **_h) { - struct passwd *p; - const char *e; - char *h; - uid_t u; - - assert(_h); - - /* Take the user specified one */ - e = secure_getenv("HOME"); - if (e && path_is_absolute(e)) { - h = strdup(e); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - h = strdup("/root"); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_dir)) - return -EINVAL; - - h = strdup(p->pw_dir); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; -} - -int get_shell(char **_s) { - struct passwd *p; - const char *e; - char *s; - uid_t u; - - assert(_s); - - /* Take the user specified one */ - e = getenv("SHELL"); - if (e) { - s = strdup(e); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - s = strdup("/bin/sh"); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_shell)) - return -EINVAL; - - s = strdup(p->pw_shell); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; -} - -bool filename_is_valid(const char *p) { - - if (isempty(p)) - return false; - - if (strchr(p, '/')) - return false; - - if (streq(p, ".")) - return false; - - if (streq(p, "..")) - return false; - - if (strlen(p) > FILENAME_MAX) - return false; - - return true; -} - -bool string_is_safe(const char *p) { - const char *t; - - if (!p) - return false; - - for (t = p; *t; t++) { - if (*t > 0 && *t < ' ') - return false; - - if (strchr("\\\"\'\x7f", *t)) - return false; - } - - return true; -} - -/** - * Check if a string contains control characters. If 'ok' is non-NULL - * it may be a string containing additional CCs to be considered OK. - */ -bool string_has_cc(const char *p, const char *ok) { - const char *t; - - assert(p); - - for (t = p; *t; t++) { - if (ok && strchr(ok, *t)) - continue; - - if (*t > 0 && *t < ' ') - return true; - - if (*t == 127) - return true; - } - - return false; -} - -bool path_is_safe(const char *p) { - - if (isempty(p)) - return false; - - if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) - return false; - - if (strlen(p)+1 > PATH_MAX) - return false; - - /* The following two checks are not really dangerous, but hey, they still are confusing */ - if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) - return false; - - if (strstr(p, "//")) - return false; - - return true; -} - /* hey glibc, APIs with callbacks without a user pointer are so useless */ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), void *arg) { @@ -4269,216 +542,6 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, return NULL; } -void init_gettext(void) { - setlocale(LC_ALL, ""); - textdomain(GETTEXT_PACKAGE); -} - -bool is_locale_utf8(void) { - const char *set; - static int cached_answer = -1; - - if (cached_answer >= 0) - goto out; - - if (!setlocale(LC_ALL, "")) { - cached_answer = true; - goto out; - } - - set = nl_langinfo(CODESET); - if (!set) { - cached_answer = true; - goto out; - } - - if (streq(set, "UTF-8")) { - cached_answer = true; - goto out; - } - - /* For LC_CTYPE=="C" return true, because CTYPE is effectly - * unset and everything can do to UTF-8 nowadays. */ - set = setlocale(LC_CTYPE, NULL); - if (!set) { - cached_answer = true; - goto out; - } - - /* Check result, but ignore the result if C was set - * explicitly. */ - cached_answer = - STR_IN_SET(set, "C", "POSIX") && - !getenv("LC_ALL") && - !getenv("LC_CTYPE") && - !getenv("LANG"); - -out: - return (bool) cached_answer; -} - -const char *draw_special_char(DrawSpecialChar ch) { - static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { - - /* UTF-8 */ { - [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */ - [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ - [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ - [DRAW_TREE_SPACE] = " ", /* */ - [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ - [DRAW_BLACK_CIRCLE] = "\342\227\217", /* â— */ - [DRAW_ARROW] = "\342\206\222", /* → */ - [DRAW_DASH] = "\342\200\223", /* – */ - }, - - /* ASCII fallback */ { - [DRAW_TREE_VERTICAL] = "| ", - [DRAW_TREE_BRANCH] = "|-", - [DRAW_TREE_RIGHT] = "`-", - [DRAW_TREE_SPACE] = " ", - [DRAW_TRIANGULAR_BULLET] = ">", - [DRAW_BLACK_CIRCLE] = "*", - [DRAW_ARROW] = "->", - [DRAW_DASH] = "-", - } - }; - - return draw_table[!is_locale_utf8()][ch]; -} - -char *strreplace(const char *text, const char *old_string, const char *new_string) { - const char *f; - char *t, *r; - size_t l, old_len, new_len; - - assert(text); - assert(old_string); - assert(new_string); - - old_len = strlen(old_string); - new_len = strlen(new_string); - - l = strlen(text); - r = new(char, l+1); - if (!r) - return NULL; - - f = text; - t = r; - while (*f) { - char *a; - size_t d, nl; - - if (!startswith(f, old_string)) { - *(t++) = *(f++); - continue; - } - - d = t - r; - nl = l - old_len + new_len; - a = realloc(r, nl + 1); - if (!a) - goto oom; - - l = nl; - r = a; - t = r + d; - - t = stpcpy(t, new_string); - f += old_len; - } - - *t = 0; - return r; - -oom: - free(r); - return NULL; -} - -char *strip_tab_ansi(char **ibuf, size_t *_isz) { - const char *i, *begin = NULL; - enum { - STATE_OTHER, - STATE_ESCAPE, - STATE_BRACKET - } state = STATE_OTHER; - char *obuf = NULL; - size_t osz = 0, isz; - FILE *f; - - assert(ibuf); - assert(*ibuf); - - /* Strips ANSI color and replaces TABs by 8 spaces */ - - isz = _isz ? *_isz : strlen(*ibuf); - - f = open_memstream(&obuf, &osz); - if (!f) - return NULL; - - for (i = *ibuf; i < *ibuf + isz + 1; i++) { - - switch (state) { - - case STATE_OTHER: - if (i >= *ibuf + isz) /* EOT */ - break; - else if (*i == '\x1B') - state = STATE_ESCAPE; - else if (*i == '\t') - fputs(" ", f); - else - fputc(*i, f); - break; - - case STATE_ESCAPE: - if (i >= *ibuf + isz) { /* EOT */ - fputc('\x1B', f); - break; - } else if (*i == '[') { - state = STATE_BRACKET; - begin = i + 1; - } else { - fputc('\x1B', f); - fputc(*i, f); - state = STATE_OTHER; - } - - break; - - case STATE_BRACKET: - - if (i >= *ibuf + isz || /* EOT */ - (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { - fputc('\x1B', f); - fputc('[', f); - state = STATE_OTHER; - i = begin-1; - } else if (*i == 'm') - state = STATE_OTHER; - break; - } - } - - if (ferror(f)) { - fclose(f); - free(obuf); - return NULL; - } - - fclose(f); - - free(*ibuf); - *ibuf = obuf; - - if (_isz) - *_isz = osz; - - return obuf; -} - int on_ac_power(void) { bool found_offline = false, found_online = false; _cleanup_closedir_ DIR *d = NULL; @@ -4555,204 +618,6 @@ int on_ac_power(void) { return found_online || !found_offline; } -static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) { - char **i; - - assert(path); - assert(mode); - assert(_f); - - if (!path_strv_resolve_uniq(search, root)) - return -ENOMEM; - - STRV_FOREACH(i, search) { - _cleanup_free_ char *p = NULL; - FILE *f; - - if (root) - p = strjoin(root, *i, "/", path, NULL); - else - p = strjoin(*i, "/", path, NULL); - if (!p) - return -ENOMEM; - - f = fopen(p, mode); - if (f) { - *_f = f; - return 0; - } - - if (errno != ENOENT) - return -errno; - } - - return -ENOENT; -} - -int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) { - _cleanup_strv_free_ char **copy = NULL; - - assert(path); - assert(mode); - assert(_f); - - if (path_is_absolute(path)) { - FILE *f; - - f = fopen(path, mode); - if (f) { - *_f = f; - return 0; - } - - return -errno; - } - - copy = strv_copy((char**) search); - if (!copy) - return -ENOMEM; - - return search_and_fopen_internal(path, mode, root, copy, _f); -} - -int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) { - _cleanup_strv_free_ char **s = NULL; - - if (path_is_absolute(path)) { - FILE *f; - - f = fopen(path, mode); - if (f) { - *_f = f; - return 0; - } - - return -errno; - } - - s = strv_split_nulstr(search); - if (!s) - return -ENOMEM; - - return search_and_fopen_internal(path, mode, root, s, _f); -} - -char *strextend(char **x, ...) { - va_list ap; - size_t f, l; - char *r, *p; - - assert(x); - - l = f = *x ? strlen(*x) : 0; - - va_start(ap, x); - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - va_end(ap); - - r = realloc(*x, l+1); - if (!r) - return NULL; - - p = r + f; - - va_start(ap, x); - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - va_end(ap); - - *p = 0; - *x = r; - - return r + l; -} - -char *strrep(const char *s, unsigned n) { - size_t l; - char *r, *p; - unsigned i; - - assert(s); - - l = strlen(s); - p = r = malloc(l * n + 1); - if (!r) - return NULL; - - for (i = 0; i < n; i++) - p = stpcpy(p, s); - - *p = 0; - return r; -} - -void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { - size_t a, newalloc; - void *q; - - assert(p); - assert(allocated); - - if (*allocated >= need) - return *p; - - newalloc = MAX(need * 2, 64u / size); - a = newalloc * size; - - /* check for overflows */ - if (a < size * need) - return NULL; - - q = realloc(*p, a); - if (!q) - return NULL; - - *p = q; - *allocated = newalloc; - return q; -} - -void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { - size_t prev; - uint8_t *q; - - assert(p); - assert(allocated); - - prev = *allocated; - - q = greedy_realloc(p, allocated, need, size); - if (!q) - return NULL; - - if (*allocated > prev) - memzero(q + prev * size, (*allocated - prev) * size); - - return q; -} - bool id128_is_valid(const char *s) { size_t i, l; @@ -4794,151 +659,6 @@ bool id128_is_valid(const char *s) { return true; } -int split_pair(const char *s, const char *sep, char **l, char **r) { - char *x, *a, *b; - - assert(s); - assert(sep); - assert(l); - assert(r); - - if (isempty(sep)) - return -EINVAL; - - x = strstr(s, sep); - if (!x) - return -EINVAL; - - a = strndup(s, x - s); - if (!a) - return -ENOMEM; - - b = strdup(x + strlen(sep)); - if (!b) { - free(a); - return -ENOMEM; - } - - *l = a; - *r = b; - - return 0; -} - -int shall_restore_state(void) { - _cleanup_free_ char *value = NULL; - int r; - - r = get_proc_cmdline_key("systemd.restore_state=", &value); - if (r < 0) - return r; - if (r == 0) - return true; - - return parse_boolean(value) != 0; -} - -int proc_cmdline(char **ret) { - assert(ret); - - if (detect_container() > 0) - return get_process_cmdline(1, 0, false, ret); - else - return read_one_line_file("/proc/cmdline", ret); -} - -int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { - _cleanup_free_ char *line = NULL; - const char *p; - int r; - - assert(parse_item); - - r = proc_cmdline(&line); - if (r < 0) - return r; - - p = line; - for (;;) { - _cleanup_free_ char *word = NULL; - char *value = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); - if (r < 0) - return r; - if (r == 0) - break; - - /* Filter out arguments that are intended only for the - * initrd */ - if (!in_initrd() && startswith(word, "rd.")) - continue; - - value = strchr(word, '='); - if (value) - *(value++) = 0; - - r = parse_item(word, value); - if (r < 0) - return r; - } - - return 0; -} - -int get_proc_cmdline_key(const char *key, char **value) { - _cleanup_free_ char *line = NULL, *ret = NULL; - bool found = false; - const char *p; - int r; - - assert(key); - - r = proc_cmdline(&line); - if (r < 0) - return r; - - p = line; - for (;;) { - _cleanup_free_ char *word = NULL; - const char *e; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); - if (r < 0) - return r; - if (r == 0) - break; - - /* Filter out arguments that are intended only for the - * initrd */ - if (!in_initrd() && startswith(word, "rd.")) - continue; - - if (value) { - e = startswith(word, key); - if (!e) - continue; - - r = free_and_strdup(&ret, e); - if (r < 0) - return r; - - found = true; - } else { - if (streq(word, key)) - found = true; - } - } - - if (value) { - *value = ret; - ret = NULL; - } - - return found; - -} - int container_get_leader(const char *machine, pid_t *pid) { _cleanup_free_ char *s = NULL, *class = NULL; const char *p; @@ -5088,203 +808,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int return reset_uid_gid(); } -int getpeercred(int fd, struct ucred *ucred) { - socklen_t n = sizeof(struct ucred); - struct ucred u; - int r; - - assert(fd >= 0); - assert(ucred); - - r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); - if (r < 0) - return -errno; - - if (n != sizeof(struct ucred)) - return -EIO; - - /* Check if the data is actually useful and not suppressed due - * to namespacing issues */ - if (u.pid <= 0) - return -ENODATA; - if (u.uid == UID_INVALID) - return -ENODATA; - if (u.gid == GID_INVALID) - return -ENODATA; - - *ucred = u; - return 0; -} - -int getpeersec(int fd, char **ret) { - socklen_t n = 64; - char *s; - int r; - - assert(fd >= 0); - assert(ret); - - s = new0(char, n); - if (!s) - return -ENOMEM; - - r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); - if (r < 0) { - free(s); - - if (errno != ERANGE) - return -errno; - - s = new0(char, n); - if (!s) - return -ENOMEM; - - r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); - if (r < 0) { - free(s); - return -errno; - } - } - - if (isempty(s)) { - free(s); - return -EOPNOTSUPP; - } - - *ret = s; - return 0; -} - -/* This is much like like mkostemp() but is subject to umask(). */ -int mkostemp_safe(char *pattern, int flags) { - _cleanup_umask_ mode_t u; - int fd; - - assert(pattern); - - u = umask(077); - - fd = mkostemp(pattern, flags); - if (fd < 0) - return -errno; - - return fd; -} - -int open_tmpfile(const char *path, int flags) { - char *p; - int fd; - - assert(path); - -#ifdef O_TMPFILE - /* Try O_TMPFILE first, if it is supported */ - fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); - if (fd >= 0) - return fd; -#endif - - /* Fall back to unguessable name + unlinking */ - p = strjoina(path, "/systemd-tmp-XXXXXX"); - - fd = mkostemp_safe(p, flags); - if (fd < 0) - return fd; - - unlink(p); - return fd; -} - -int fd_warn_permissions(const char *path, int fd) { - struct stat st; - - if (fstat(fd, &st) < 0) - return -errno; - - if (st.st_mode & 0111) - log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); - - if (st.st_mode & 0002) - log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); - - if (getpid() == 1 && (st.st_mode & 0044) != 0044) - log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); - - return 0; -} - -unsigned long personality_from_string(const char *p) { - - /* Parse a personality specifier. We introduce our own - * identifiers that indicate specific ABIs, rather than just - * hints regarding the register size, since we want to keep - * things open for multiple locally supported ABIs for the - * same register size. We try to reuse the ABI identifiers - * used by libseccomp. */ - -#if defined(__x86_64__) - - if (streq(p, "x86")) - return PER_LINUX32; - - if (streq(p, "x86-64")) - return PER_LINUX; - -#elif defined(__i386__) - - if (streq(p, "x86")) - return PER_LINUX; - -#elif defined(__s390x__) - - if (streq(p, "s390")) - return PER_LINUX32; - - if (streq(p, "s390x")) - return PER_LINUX; - -#elif defined(__s390__) - - if (streq(p, "s390")) - return PER_LINUX; -#endif - - return PERSONALITY_INVALID; -} - -const char* personality_to_string(unsigned long p) { - -#if defined(__x86_64__) - - if (p == PER_LINUX32) - return "x86"; - - if (p == PER_LINUX) - return "x86-64"; - -#elif defined(__i386__) - - if (p == PER_LINUX) - return "x86"; - -#elif defined(__s390x__) - - if (p == PER_LINUX) - return "s390x"; - - if (p == PER_LINUX32) - return "s390"; - -#elif defined(__s390__) - - if (p == PER_LINUX) - return "s390"; - -#endif - - return NULL; -} - uint64_t physical_memory(void) { long mem; @@ -5297,49 +820,6 @@ uint64_t physical_memory(void) { return (uint64_t) mem * (uint64_t) page_size(); } -void hexdump(FILE *f, const void *p, size_t s) { - const uint8_t *b = p; - unsigned n = 0; - - assert(s == 0 || b); - - while (s > 0) { - size_t i; - - fprintf(f, "%04x ", n); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputs(" ", f); - else - fprintf(f, "%02x ", b[i]); - - if (i == 7) - fputc(' ', f); - } - - fputc(' ', f); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputc(' ', f); - else - fputc(isprint(b[i]) ? (char) b[i] : '.', f); - } - - fputc('\n', f); - - if (s < 16) - break; - - n += 16; - b += 16; - s -= 16; - } -} - int update_reboot_param_file(const char *param) { int r = 0; @@ -5353,1442 +833,8 @@ int update_reboot_param_file(const char *param) { return 0; } -int umount_recursive(const char *prefix, int flags) { - bool again; - int n = 0, r; - - /* Try to umount everything recursively below a - * directory. Also, take care of stacked mounts, and keep - * unmounting them until they are gone. */ - - do { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - - again = false; - r = 0; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%*s " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options 2 */ - "%*[^\n]", /* some rubbish at the end */ - &path); - if (k != 1) { - if (k == EOF) - break; - - continue; - } - - r = cunescape(path, UNESCAPE_RELAX, &p); - if (r < 0) - return r; - - if (!path_startswith(p, prefix)) - continue; - - if (umount2(p, flags) < 0) { - r = -errno; - continue; - } - - again = true; - n++; - - break; - } - - } while (again); - - return r ? r : n; -} - -static int get_mount_flags(const char *path, unsigned long *flags) { - struct statvfs buf; - - if (statvfs(path, &buf) < 0) - return -errno; - *flags = buf.f_flag; - return 0; -} - -int bind_remount_recursive(const char *prefix, bool ro) { - _cleanup_set_free_free_ Set *done = NULL; - _cleanup_free_ char *cleaned = NULL; - int r; - - /* Recursively remount a directory (and all its submounts) - * read-only or read-write. If the directory is already - * mounted, we reuse the mount and simply mark it - * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write - * operation). If it isn't we first make it one. Afterwards we - * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all - * submounts we can access, too. When mounts are stacked on - * the same mount point we only care for each individual - * "top-level" mount on each point, as we cannot - * influence/access the underlying mounts anyway. We do not - * have any effect on future submounts that might get - * propagated, they migt be writable. This includes future - * submounts that have been triggered via autofs. */ - - cleaned = strdup(prefix); - if (!cleaned) - return -ENOMEM; - - path_kill_slashes(cleaned); - - done = set_new(&string_hash_ops); - if (!done) - return -ENOMEM; - - for (;;) { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - _cleanup_set_free_free_ Set *todo = NULL; - bool top_autofs = false; - char *x; - unsigned long orig_flags; - - todo = set_new(&string_hash_ops); - if (!todo) - return -ENOMEM; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options (superblock) */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%ms " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options (bind mount) */ - "%*[^\n]", /* some rubbish at the end */ - &path, - &type); - if (k != 2) { - if (k == EOF) - break; - - continue; - } - - r = cunescape(path, UNESCAPE_RELAX, &p); - if (r < 0) - return r; - - /* Let's ignore autofs mounts. If they aren't - * triggered yet, we want to avoid triggering - * them, as we don't make any guarantees for - * future submounts anyway. If they are - * already triggered, then we will find - * another entry for this. */ - if (streq(type, "autofs")) { - top_autofs = top_autofs || path_equal(cleaned, p); - continue; - } - - if (path_startswith(p, cleaned) && - !set_contains(done, p)) { - - r = set_consume(todo, p); - p = NULL; - - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - } - - /* If we have no submounts to process anymore and if - * the root is either already done, or an autofs, we - * are done */ - if (set_isempty(todo) && - (top_autofs || set_contains(done, cleaned))) - return 0; - - if (!set_contains(done, cleaned) && - !set_contains(todo, cleaned)) { - /* The prefix directory itself is not yet a - * mount, make it one. */ - if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0) - return -errno; - - orig_flags = 0; - (void) get_mount_flags(cleaned, &orig_flags); - orig_flags &= ~MS_RDONLY; - - if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) - return -errno; - - x = strdup(cleaned); - if (!x) - return -ENOMEM; - - r = set_consume(done, x); - if (r < 0) - return r; - } - - while ((x = set_steal_first(todo))) { - - r = set_consume(done, x); - if (r == -EEXIST || r == 0) - continue; - if (r < 0) - return r; - - /* Try to reuse the original flag set, but - * don't care for errors, in case of - * obstructed mounts */ - orig_flags = 0; - (void) get_mount_flags(x, &orig_flags); - orig_flags &= ~MS_RDONLY; - - if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { - - /* Deal with mount points that are - * obstructed by a later mount */ - - if (errno != ENOENT) - return -errno; - } - - } - } -} - -int fflush_and_check(FILE *f) { - assert(f); - - errno = 0; - fflush(f); - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; -} - -int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { - const char *fn; - char *t; - - assert(p); - assert(ret); - - /* - * Turns this: - * /foo/bar/waldo - * - * Into this: - * /foo/bar/.#<extra>waldoXXXXXX - */ - - fn = basename(p); - if (!filename_is_valid(fn)) - return -EINVAL; - - if (extra == NULL) - extra = ""; - - t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); - if (!t) - return -ENOMEM; - - strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); - - *ret = path_kill_slashes(t); - return 0; -} - -int tempfn_random(const char *p, const char *extra, char **ret) { - const char *fn; - char *t, *x; - uint64_t u; - unsigned i; - - assert(p); - assert(ret); - - /* - * Turns this: - * /foo/bar/waldo - * - * Into this: - * /foo/bar/.#<extra>waldobaa2a261115984a9 - */ - - fn = basename(p); - if (!filename_is_valid(fn)) - return -EINVAL; - - if (!extra) - extra = ""; - - t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); - if (!t) - return -ENOMEM; - - x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn); - - u = random_u64(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(u & 0xF); - u >>= 4; - } - - *x = 0; - - *ret = path_kill_slashes(t); - return 0; -} - -int tempfn_random_child(const char *p, const char *extra, char **ret) { - char *t, *x; - uint64_t u; - unsigned i; - - assert(p); - assert(ret); - - /* Turns this: - * /foo/bar/waldo - * Into this: - * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0 - */ - - if (!extra) - extra = ""; - - t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1); - if (!t) - return -ENOMEM; - - x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); - - u = random_u64(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(u & 0xF); - u >>= 4; - } - - *x = 0; - - *ret = path_kill_slashes(t); - return 0; -} - -int take_password_lock(const char *root) { - - struct flock flock = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; - - const char *path; - int fd, r; - - /* This is roughly the same as lckpwdf(), but not as awful. We - * don't want to use alarm() and signals, hence we implement - * our own trivial version of this. - * - * Note that shadow-utils also takes per-database locks in - * addition to lckpwdf(). However, we don't given that they - * are redundant as they they invoke lckpwdf() first and keep - * it during everything they do. The per-database locks are - * awfully racy, and thus we just won't do them. */ - - if (root) - path = strjoina(root, "/etc/.pwd.lock"); - else - path = "/etc/.pwd.lock"; - - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); - if (fd < 0) - return -errno; - - r = fcntl(fd, F_SETLKW, &flock); - if (r < 0) { - safe_close(fd); - return -errno; - } - - return fd; -} - -int is_symlink(const char *path) { - struct stat info; - - if (lstat(path, &info) < 0) - return -errno; - - return !!S_ISLNK(info.st_mode); -} - -int is_dir(const char* path, bool follow) { - struct stat st; - int r; - - if (follow) - r = stat(path, &st); - else - r = lstat(path, &st); - if (r < 0) - return -errno; - - return !!S_ISDIR(st.st_mode); -} - -int is_device_node(const char *path) { - struct stat info; - - if (lstat(path, &info) < 0) - return -errno; - - return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); -} - -int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { - _cleanup_free_ char *s = NULL; - size_t allocated = 0, sz = 0; - int r; - - enum { - START, - VALUE, - VALUE_ESCAPE, - SINGLE_QUOTE, - SINGLE_QUOTE_ESCAPE, - DOUBLE_QUOTE, - DOUBLE_QUOTE_ESCAPE, - SEPARATOR, - } state = START; - - assert(p); - assert(ret); - - if (!separators) - separators = WHITESPACE; - - /* Bail early if called after last value or with no input */ - if (!*p) - goto finish_force_terminate; - - /* Parses the first word of a string, and returns it in - * *ret. Removes all quotes in the process. When parsing fails - * (because of an uneven number of quotes or similar), leaves - * the pointer *p at the first invalid character. */ - - for (;;) { - char c = **p; - - switch (state) { - - case START: - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - - if (c == 0) - goto finish_force_terminate; - else if (strchr(separators, c)) { - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; - goto finish_force_next; - } - break; - } - - /* We found a non-blank character, so we will always - * want to return a string (even if it is empty), - * allocate it here. */ - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - - state = VALUE; - /* fallthrough */ - - case VALUE: - if (c == 0) - goto finish_force_terminate; - else if (c == '\'' && (flags & EXTRACT_QUOTES)) - state = SINGLE_QUOTE; - else if (c == '\\') - state = VALUE_ESCAPE; - else if (c == '\"' && (flags & EXTRACT_QUOTES)) - state = DOUBLE_QUOTE; - else if (strchr(separators, c)) { - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; - goto finish_force_next; - } - state = SEPARATOR; - } else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case SINGLE_QUOTE: - if (c == 0) { - if (flags & EXTRACT_RELAX) - goto finish_force_terminate; - return -EINVAL; - } else if (c == '\'') - state = VALUE; - else if (c == '\\') - state = SINGLE_QUOTE_ESCAPE; - else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case DOUBLE_QUOTE: - if (c == 0) - return -EINVAL; - else if (c == '\"') - state = VALUE; - else if (c == '\\') - state = DOUBLE_QUOTE_ESCAPE; - else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case SINGLE_QUOTE_ESCAPE: - case DOUBLE_QUOTE_ESCAPE: - case VALUE_ESCAPE: - if (!GREEDY_REALLOC(s, allocated, sz+7)) - return -ENOMEM; - - if (c == 0) { - if ((flags & EXTRACT_CUNESCAPE_RELAX) && - (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) { - /* If we find an unquoted trailing backslash and we're in - * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the - * output. - * - * Unbalanced quotes will only be allowed in EXTRACT_RELAX - * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. - */ - s[sz++] = '\\'; - goto finish_force_terminate; - } - if (flags & EXTRACT_RELAX) - goto finish_force_terminate; - return -EINVAL; - } - - if (flags & EXTRACT_CUNESCAPE) { - uint32_t u; - - r = cunescape_one(*p, (size_t) -1, &c, &u); - if (r < 0) { - if (flags & EXTRACT_CUNESCAPE_RELAX) { - s[sz++] = '\\'; - s[sz++] = c; - goto end_escape; - } - return -EINVAL; - } - - (*p) += r - 1; - - if (c != 0) - s[sz++] = c; /* normal explicit char */ - else - sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ - } else - s[sz++] = c; - -end_escape: - state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE : - (state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE : - VALUE; - break; - - case SEPARATOR: - if (c == 0) - goto finish_force_terminate; - if (!strchr(separators, c)) - goto finish; - break; - } - - (*p) ++; - } - -finish_force_terminate: - *p = NULL; -finish: - if (!s) { - *p = NULL; - *ret = NULL; - return 0; - } - -finish_force_next: - s[sz] = 0; - *ret = s; - s = NULL; - - return 1; -} - -int extract_first_word_and_warn( - const char **p, - char **ret, - const char *separators, - ExtractFlags flags, - const char *unit, - const char *filename, - unsigned line, - const char *rvalue) { - - /* Try to unquote it, if it fails, warn about it and try again but this - * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim - * in invalid escape sequences. */ - const char *save; - int r; - - save = *p; - r = extract_first_word(p, ret, separators, flags); - if (r < 0 && !(flags & EXTRACT_CUNESCAPE_RELAX)) { - - /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ - *p = save; - r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); - else - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid escape sequences in command line: \"%s\"", rvalue); - } - - return r; -} - -int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { - va_list ap; - char **l; - int n = 0, i, c, r; - - /* Parses a number of words from a string, stripping any - * quotes if necessary. */ - - assert(p); - - /* Count how many words are expected */ - va_start(ap, flags); - for (;;) { - if (!va_arg(ap, char **)) - break; - n++; - } - va_end(ap); - - if (n <= 0) - return 0; - - /* Read all words into a temporary array */ - l = newa0(char*, n); - for (c = 0; c < n; c++) { - - r = extract_first_word(p, &l[c], separators, flags); - if (r < 0) { - int j; - - for (j = 0; j < c; j++) - free(l[j]); - - return r; - } - - if (r == 0) - break; - } - - /* If we managed to parse all words, return them in the passed - * in parameters */ - va_start(ap, flags); - for (i = 0; i < n; i++) { - char **v; - - v = va_arg(ap, char **); - assert(v); - - *v = l[i]; - } - va_end(ap); - - return c; -} - -int free_and_strdup(char **p, const char *s) { - char *t; - - assert(p); - - /* Replaces a string pointer with an strdup()ed new string, - * possibly freeing the old one. */ - - if (streq_ptr(*p, s)) - return 0; - - if (s) { - t = strdup(s); - if (!t) - return -ENOMEM; - } else - t = NULL; - - free(*p); - *p = t; - - return 1; -} - -ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) { - char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; - _cleanup_close_ int fd = -1; - ssize_t l; - - /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ - - fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); - if (fd < 0) - return -errno; - - xsprintf(fn, "/proc/self/fd/%i", fd); - - l = getxattr(fn, attribute, value, size); - if (l < 0) - return -errno; - - return l; -} - -static int parse_crtime(le64_t le, usec_t *usec) { - uint64_t u; - - assert(usec); - - u = le64toh(le); - if (u == 0 || u == (uint64_t) -1) - return -EIO; - - *usec = (usec_t) u; - return 0; -} - -int fd_getcrtime(int fd, usec_t *usec) { - le64_t le; - ssize_t n; - - assert(fd >= 0); - assert(usec); - - /* Until Linux gets a real concept of birthtime/creation time, - * let's fake one with xattrs */ - - n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le)); - if (n < 0) - return -errno; - if (n != sizeof(le)) - return -EIO; - - return parse_crtime(le, usec); -} - -int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) { - le64_t le; - ssize_t n; - - n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags); - if (n < 0) - return -errno; - if (n != sizeof(le)) - return -EIO; - - return parse_crtime(le, usec); -} - -int path_getcrtime(const char *p, usec_t *usec) { - le64_t le; - ssize_t n; - - assert(p); - assert(usec); - - n = getxattr(p, "user.crtime_usec", &le, sizeof(le)); - if (n < 0) - return -errno; - if (n != sizeof(le)) - return -EIO; - - return parse_crtime(le, usec); -} - -int fd_setcrtime(int fd, usec_t usec) { - le64_t le; - - assert(fd >= 0); - - if (usec <= 0) - usec = now(CLOCK_REALTIME); - - le = htole64((uint64_t) usec); - if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0) - return -errno; - - return 0; -} - -int same_fd(int a, int b) { - struct stat sta, stb; - pid_t pid; - int r, fa, fb; - - assert(a >= 0); - assert(b >= 0); - - /* Compares two file descriptors. Note that semantics are - * quite different depending on whether we have kcmp() or we - * don't. If we have kcmp() this will only return true for - * dup()ed file descriptors, but not otherwise. If we don't - * have kcmp() this will also return true for two fds of the same - * file, created by separate open() calls. Since we use this - * call mostly for filtering out duplicates in the fd store - * this difference hopefully doesn't matter too much. */ - - if (a == b) - return true; - - /* Try to use kcmp() if we have it. */ - pid = getpid(); - r = kcmp(pid, pid, KCMP_FILE, a, b); - if (r == 0) - return true; - if (r > 0) - return false; - if (errno != ENOSYS) - return -errno; - - /* We don't have kcmp(), use fstat() instead. */ - if (fstat(a, &sta) < 0) - return -errno; - - if (fstat(b, &stb) < 0) - return -errno; - - if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) - return false; - - /* We consider all device fds different, since two device fds - * might refer to quite different device contexts even though - * they share the same inode and backing dev_t. */ - - if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) - return false; - - if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) - return false; - - /* The fds refer to the same inode on disk, let's also check - * if they have the same fd flags. This is useful to - * distinguish the read and write side of a pipe created with - * pipe(). */ - fa = fcntl(a, F_GETFL); - if (fa < 0) - return -errno; - - fb = fcntl(b, F_GETFL); - if (fb < 0) - return -errno; - - return fa == fb; -} - -int chattr_fd(int fd, unsigned value, unsigned mask) { - unsigned old_attr, new_attr; - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - /* Explicitly check whether this is a regular file or - * directory. If it is anything else (such as a device node or - * fifo), then the ioctl will not hit the file systems but - * possibly drivers, where the ioctl might have different - * effects. Notably, DRM is using the same ioctl() number. */ - - if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) - return -ENOTTY; - - if (mask == 0) - return 0; - - if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) - return -errno; - - new_attr = (old_attr & ~mask) | (value & mask); - if (new_attr == old_attr) - return 0; - - if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) - return -errno; - - return 1; -} - -int chattr_path(const char *p, unsigned value, unsigned mask) { - _cleanup_close_ int fd = -1; - - assert(p); - - if (mask == 0) - return 0; - - fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd < 0) - return -errno; - - return chattr_fd(fd, value, mask); -} - -int read_attr_fd(int fd, unsigned *ret) { - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) - return -ENOTTY; - - if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) - return -errno; - - return 0; -} - -int read_attr_path(const char *p, unsigned *ret) { - _cleanup_close_ int fd = -1; - - assert(p); - assert(ret); - - fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd < 0) - return -errno; - - return read_attr_fd(fd, ret); -} - -static size_t nul_length(const uint8_t *p, size_t sz) { - size_t n = 0; - - while (sz > 0) { - if (*p != 0) - break; - - n++; - p++; - sz--; - } - - return n; -} - -ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { - const uint8_t *q, *w, *e; - ssize_t l; - - q = w = p; - e = q + sz; - while (q < e) { - size_t n; - - n = nul_length(q, e - q); - - /* If there are more than the specified run length of - * NUL bytes, or if this is the beginning or the end - * of the buffer, then seek instead of write */ - if ((n > run_length) || - (n > 0 && q == p) || - (n > 0 && q + n >= e)) { - if (q > w) { - l = write(fd, w, q - w); - if (l < 0) - return -errno; - if (l != q -w) - return -EIO; - } - - if (lseek(fd, n, SEEK_CUR) == (off_t) -1) - return -errno; - - q += n; - w = q; - } else if (n > 0) - q += n; - else - q ++; - } - - if (q > w) { - l = write(fd, w, q - w); - if (l < 0) - return -errno; - if (l != q - w) - return -EIO; - } - - return q - (const uint8_t*) p; -} - -void sigkill_wait(pid_t *pid) { - if (!pid) - return; - if (*pid <= 1) - return; - - if (kill(*pid, SIGKILL) > 0) - (void) wait_for_terminate(*pid, NULL); -} - -int syslog_parse_priority(const char **p, int *priority, bool with_facility) { - int a = 0, b = 0, c = 0; - int k; - - assert(p); - assert(*p); - assert(priority); - - if ((*p)[0] != '<') - return 0; - - if (!strchr(*p, '>')) - return 0; - - if ((*p)[2] == '>') { - c = undecchar((*p)[1]); - k = 3; - } else if ((*p)[3] == '>') { - b = undecchar((*p)[1]); - c = undecchar((*p)[2]); - k = 4; - } else if ((*p)[4] == '>') { - a = undecchar((*p)[1]); - b = undecchar((*p)[2]); - c = undecchar((*p)[3]); - k = 5; - } else - return 0; - - if (a < 0 || b < 0 || c < 0 || - (!with_facility && (a || b || c > 7))) - return 0; - - if (with_facility) - *priority = a*100 + b*10 + c; - else - *priority = (*priority & LOG_FACMASK) | c; - - *p += k; - return 1; -} - -ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { - size_t i; - - if (!key) - return -1; - - for (i = 0; i < len; ++i) - if (streq_ptr(table[i], key)) - return (ssize_t) i; - - return -1; -} - -void cmsg_close_all(struct msghdr *mh) { - struct cmsghdr *cmsg; - - assert(mh); - - CMSG_FOREACH(cmsg, mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) - close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); -} - -int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { - struct stat buf; - int ret; - - ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE); - if (ret >= 0) - return 0; - - /* renameat2() exists since Linux 3.15, btrfs added support for it later. - * If it is not implemented, fallback to another method. */ - if (!IN_SET(errno, EINVAL, ENOSYS)) - return -errno; - - /* The link()/unlink() fallback does not work on directories. But - * renameat() without RENAME_NOREPLACE gives the same semantics on - * directories, except when newpath is an *empty* directory. This is - * good enough. */ - ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW); - if (ret >= 0 && S_ISDIR(buf.st_mode)) { - ret = renameat(olddirfd, oldpath, newdirfd, newpath); - return ret >= 0 ? 0 : -errno; - } - - /* If it is not a directory, use the link()/unlink() fallback. */ - ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0); - if (ret < 0) - return -errno; - - ret = unlinkat(olddirfd, oldpath, 0); - if (ret < 0) { - /* backup errno before the following unlinkat() alters it */ - ret = errno; - (void) unlinkat(newdirfd, newpath, 0); - errno = ret; - return -errno; - } - - return 0; -} - -static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { - assert(bad); - - for (; *s; s++) { - if (*s == '\\' || strchr(bad, *s)) - *(t++) = '\\'; - - *(t++) = *s; - } - - return t; -} - -char *shell_escape(const char *s, const char *bad) { - char *r, *t; - - r = new(char, strlen(s)*2+1); - if (!r) - return NULL; - - t = strcpy_backslash_escaped(r, s, bad); - *t = 0; - - return r; -} - -char *shell_maybe_quote(const char *s) { - const char *p; - char *r, *t; - - assert(s); - - /* Encloses a string in double quotes if necessary to make it - * OK as shell string. */ - - for (p = s; *p; p++) - if (*p <= ' ' || - *p >= 127 || - strchr(SHELL_NEED_QUOTES, *p)) - break; - - if (!*p) - return strdup(s); - - r = new(char, 1+strlen(s)*2+1+1); - if (!r) - return NULL; - - t = r; - *(t++) = '"'; - t = mempcpy(t, s, p - s); - - t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); - - *(t++)= '"'; - *t = 0; - - return r; -} - -int parse_mode(const char *s, mode_t *ret) { - char *x; - long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtol(s, &x, 8); - if (errno != 0) - return -errno; - - if (!x || x == s || *x) - return -EINVAL; - if (l < 0 || l > 07777) - return -ERANGE; - - *ret = (mode_t) l; - return 0; -} - -int mount_move_root(const char *path) { - assert(path); - - if (chdir(path) < 0) - return -errno; - - if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) - return -errno; - - if (chroot(".") < 0) - return -errno; - - if (chdir("/") < 0) - return -errno; - - return 0; -} - -int reset_uid_gid(void) { - - if (setgroups(0, NULL) < 0) - return -errno; - - if (setresgid(0, 0, 0) < 0) - return -errno; - - if (setresuid(0, 0, 0) < 0) - return -errno; - - return 0; -} - -int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { - char *v; - size_t l; - ssize_t n; - - assert(path); - assert(name); - assert(value); - - for (l = 100; ; l = (size_t) n + 1) { - v = new0(char, l); - if (!v) - return -ENOMEM; - - if (allow_symlink) - n = lgetxattr(path, name, v, l); - else - n = getxattr(path, name, v, l); - - if (n >= 0 && (size_t) n < l) { - *value = v; - return n; - } - - free(v); - - if (n < 0 && errno != ERANGE) - return -errno; - - if (allow_symlink) - n = lgetxattr(path, name, NULL, 0); - else - n = getxattr(path, name, NULL, 0); - if (n < 0) - return -errno; - } -} - -int fgetxattr_malloc(int fd, const char *name, char **value) { - char *v; - size_t l; - ssize_t n; - - assert(fd >= 0); - assert(name); - assert(value); - - for (l = 100; ; l = (size_t) n + 1) { - v = new0(char, l); - if (!v) - return -ENOMEM; - - n = fgetxattr(fd, name, v, l); - - if (n >= 0 && (size_t) n < l) { - *value = v; - return n; - } - - free(v); - - if (n < 0 && errno != ERANGE) - return -errno; - - n = fgetxattr(fd, name, NULL, 0); - if (n < 0) - return -errno; - } -} - -int send_one_fd(int transport_fd, int fd, int flags) { - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - - assert(transport_fd >= 0); - assert(fd >= 0); - - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = CMSG_SPACE(sizeof(int)); - if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0) - return -errno; - - return 0; -} - -int receive_one_fd(int transport_fd, int flags) { - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg, *found = NULL; - - assert(transport_fd >= 0); - - /* - * Receive a single FD via @transport_fd. We don't care for - * the transport-type. We retrieve a single FD at most, so for - * packet-based transports, the caller must ensure to send - * only a single FD per packet. This is best used in - * combination with send_one_fd(). - */ - - if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0) - return -errno; - - CMSG_FOREACH(cmsg, &mh) { - if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_RIGHTS && - cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { - assert(!found); - found = cmsg; - break; - } - } - - if (!found) { - cmsg_close_all(&mh); - return -EIO; - } - - return *(int*) CMSG_DATA(found); -} - -void nop_signal_handler(int sig) { - /* nothing here */ -} - int version(void) { puts(PACKAGE_STRING "\n" SYSTEMD_FEATURES); return 0; } - -bool fdname_is_valid(const char *s) { - const char *p; - - /* Validates a name for $LISTEN_FDNAMES. We basically allow - * everything ASCII that's not a control character. Also, as - * special exception the ":" character is not allowed, as we - * use that as field separator in $LISTEN_FDNAMES. - * - * Note that the empty string is explicitly allowed - * here. However, we limit the length of the names to 255 - * characters. */ - - if (!s) - return false; - - for (p = s; *p; p++) { - if (*p < ' ') - return false; - if (*p >= 127) - return false; - if (*p == ':') - return false; - } - - return p - s < 256; -} diff --git a/src/basic/util.h b/src/basic/util.h index 79c7ad1b39..d9d2f72b75 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -22,12 +22,10 @@ ***/ #include <alloca.h> -#include <dirent.h> #include <fcntl.h> #include <inttypes.h> #include <limits.h> #include <locale.h> -#include <mntent.h> #include <stdarg.h> #include <stdbool.h> #include <stddef.h> @@ -46,49 +44,9 @@ #include "missing.h" #include "time-util.h" -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;" -#define GLOB_CHARS "*?[" - -/* What characters are special in the shell? */ -/* must be escaped outside and inside double-quotes */ -#define SHELL_NEED_ESCAPE "\"\\`$" -/* can be escaped or double-quoted */ -#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;" - -#define FORMAT_BYTES_MAX 8 - size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) -#define streq(a,b) (strcmp((a),(b)) == 0) -#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) -#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) -#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) - -bool streq_ptr(const char *a, const char *b) _pure_; -int strcmp_ptr(const char *a, const char *b) _pure_; - -#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) - -#define new0(t, n) ((t*) calloc((n), sizeof(t))) - -#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) - -#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) - -#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) - -#define malloc0(n) (calloc(1, (n))) - -static inline void *mfree(void *memory) { - free(memory); - return NULL; -} - static inline const char* yes_no(bool b) { return b ? "yes" : "no"; } @@ -101,345 +59,13 @@ static inline const char* one_zero(bool b) { return b ? "1" : "0"; } -static inline const char* strempty(const char *s) { - return s ? s : ""; -} - -static inline const char* strnull(const char *s) { - return s ? s : "(null)"; -} - -static inline const char *strna(const char *s) { - return s ? s : "n/a"; -} - -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - -static inline char *startswith(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -static inline char *startswith_no_case(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncasecmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -char *endswith(const char *s, const char *postfix) _pure_; -char *endswith_no_case(const char *s, const char *postfix) _pure_; - -char *first_word(const char *s, const char *word) _pure_; - -int close_nointr(int fd); -int safe_close(int fd); -void safe_close_pair(int p[]); - -void close_many(const int fds[], unsigned n_fd); - -int fclose_nointr(FILE *f); -FILE* safe_fclose(FILE *f); -DIR* safe_closedir(DIR *f); - -int parse_size(const char *t, uint64_t base, uint64_t *size); - -int parse_boolean(const char *v) _pure_; -int parse_pid(const char *s, pid_t* ret_pid); -int parse_uid(const char *s, uid_t* ret_uid); -#define parse_gid(s, ret_gid) parse_uid(s, ret_gid) - -bool uid_is_valid(uid_t uid); - -static inline bool gid_is_valid(gid_t gid) { - return uid_is_valid((uid_t) gid); -} - -int safe_atou(const char *s, unsigned *ret_u); -int safe_atoi(const char *s, int *ret_i); - -int safe_atollu(const char *s, unsigned long long *ret_u); -int safe_atolli(const char *s, long long int *ret_i); - -int safe_atod(const char *s, double *ret_d); - -int safe_atou8(const char *s, uint8_t *ret); - -#if LONG_MAX == INT_MAX -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(int)); - return safe_atoi(s, (int*) ret_u); -} -#else -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_u); -} -#endif - -static inline int safe_atou32(const char *s, uint32_t *ret_u) { - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} - -static inline int safe_atoi32(const char *s, int32_t *ret_i) { - assert_cc(sizeof(int32_t) == sizeof(int)); - return safe_atoi(s, (int*) ret_i); -} - -static inline int safe_atou64(const char *s, uint64_t *ret_u) { - assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} - -static inline int safe_atoi64(const char *s, int64_t *ret_i) { - assert_cc(sizeof(int64_t) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_i); -} - -int safe_atou16(const char *s, uint16_t *ret); -int safe_atoi16(const char *s, int16_t *ret); - -const char* split(const char **state, size_t *l, const char *separator, bool quoted); - -#define FOREACH_WORD(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, false, state) - -#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - _FOREACH_WORD(word, length, s, separator, false, state) - -#define FOREACH_WORD_QUOTED(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, true, state) - -#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ - for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) - -char *strappend(const char *s, const char *suffix); -char *strnappend(const char *s, const char *suffix, size_t length); - -int readlinkat_malloc(int fd, const char *p, char **ret); -int readlink_malloc(const char *p, char **r); -int readlink_value(const char *p, char **ret); -int readlink_and_make_absolute(const char *p, char **r); -int readlink_and_canonicalize(const char *p, char **r); - -char *strstrip(char *s); -char *delete_chars(char *s, const char *bad); -char *truncate_nl(char *s); - -char *file_in_same_dir(const char *path, const char *filename); - -int rmdir_parents(const char *path, const char *stop); - -char hexchar(int x) _const_; -int unhexchar(char c) _const_; -char octchar(int x) _const_; -int unoctchar(char c) _const_; -char decchar(int x) _const_; -int undecchar(char c) _const_; -char base32hexchar(int x) _const_; -int unbase32hexchar(char c) _const_; -char base64char(int x) _const_; -int unbase64char(char c) _const_; - -char *cescape(const char *s); -size_t cescape_char(char c, char *buf); - -typedef enum UnescapeFlags { - UNESCAPE_RELAX = 1, -} UnescapeFlags; - -int cunescape(const char *s, UnescapeFlags flags, char **ret); -int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); -int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); - -char *xescape(const char *s, const char *bad); - -char *ascii_strlower(char *path); - -bool dirent_is_file(const struct dirent *de) _pure_; -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; - -bool hidden_file(const char *filename) _pure_; - -bool chars_intersect(const char *a, const char *b) _pure_; - -/* For basic lookup tables with strictly enumerated entries */ -#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - scope const char *name##_to_string(type i) { \ - if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ - return NULL; \ - return name##_table[i]; \ - } - -ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); - -#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - scope type name##_from_string(const char *s) { \ - return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ - } - -#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) - -/* For string conversions where numbers are also acceptable */ -#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ - int name##_to_string_alloc(type i, char **str) { \ - char *s; \ - if (i < 0 || i > max) \ - return -ERANGE; \ - if (i < (type) ELEMENTSOF(name##_table)) { \ - s = strdup(name##_table[i]); \ - if (!s) \ - return -ENOMEM; \ - } else { \ - if (asprintf(&s, "%i", i) < 0) \ - return -ENOMEM; \ - } \ - *str = s; \ - return 0; \ - } \ - type name##_from_string(const char *s) { \ - type i; \ - unsigned u = 0; \ - if (!s) \ - return (type) -1; \ - for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ - if (streq_ptr(name##_table[i], s)) \ - return i; \ - if (safe_atou(s, &u) >= 0 && u <= max) \ - return (type) u; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -int fd_nonblock(int fd, bool nonblock); -int fd_cloexec(int fd, bool cloexec); - -int close_all_fds(const int except[], unsigned n_except); - -bool fstype_is_network(const char *fstype); - -int flush_fd(int fd); - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path); - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); -int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); -int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); - -bool is_device_path(const char *path); - -int dir_is_empty(const char *path); -char* dirname_malloc(const char *path); - -char* lookup_uid(uid_t uid); -char* getlogname_malloc(void); -char* getusername_malloc(void); - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid); - -bool is_temporary_fs(const struct statfs *s) _pure_; -int fd_is_temporary_fs(int fd); - -int pipe_eof(int fd); - -#define xsprintf(buf, fmt, ...) \ - assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \ - "xsprintf: " #buf "[] must be big enough") - -int files_same(const char *filea, const char *fileb); - -int running_in_chroot(void); - -char *ellipsize(const char *s, size_t length, unsigned percent); - /* bytes columns */ -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent); - -int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); -int touch(const char *path); - -noreturn void freeze(void); - -bool null_or_empty(struct stat *st) _pure_; -int null_or_empty_path(const char *fn); -int null_or_empty_fd(int fd); - -DIR *xopendirat(int dirfd, const char *name, int flags); - -char *fstab_node_to_udev_node(const char *p); - void execute_directories(const char* const* directories, usec_t timeout, char *argv[]); -bool nulstr_contains(const char*nulstr, const char *needle); - bool plymouth_running(void); -char* strshorten(char *s, size_t l); - -int symlink_idempotent(const char *from, const char *to); - -int symlink_atomic(const char *from, const char *to); -int mknod_atomic(const char *path, mode_t mode, dev_t dev); -int mkfifo_atomic(const char *path, mode_t mode); - -int fchmod_umask(int fd, mode_t mode); - bool display_is_local(const char *display) _pure_; int socket_from_display(const char *display, char **path); -int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); -int get_group_creds(const char **groupname, gid_t *gid); - -int in_gid(gid_t gid); -int in_group(const char *name); - -char* uid_to_name(uid_t uid); -char* gid_to_name(gid_t gid); - -int glob_exists(const char *path); -int glob_extend(char ***strv, const char *path); - -int dirent_ensure_type(DIR *d, struct dirent *de); - -int get_files_in_directory(const char *path, char ***list); - -char *strjoin(const char *x, ...) _sentinel_; - -bool is_main_thread(void); - -static inline bool _pure_ in_charset(const char *s, const char* charset) { - assert(s); - assert(charset); - return s[strspn(s, charset)] == '\0'; -} - int block_get_whole_disk(dev_t d, dev_t *ret); #define NULSTR_FOREACH(i, l) \ @@ -448,27 +74,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret); #define NULSTR_FOREACH_PAIR(i, j, l) \ for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) -int ioprio_class_to_string_alloc(int i, char **s); -int ioprio_class_from_string(const char *s); - -const char *sigchld_code_to_string(int i) _const_; -int sigchld_code_from_string(const char *s) _pure_; - -int log_facility_unshifted_to_string_alloc(int i, char **s); -int log_facility_unshifted_from_string(const char *s); - -int log_level_to_string_alloc(int i, char **s); -int log_level_from_string(const char *s); - -int sched_policy_to_string_alloc(int i, char **s); -int sched_policy_from_string(const char *s); - -const char *rlimit_to_string(int i) _const_; -int rlimit_from_string(const char *s) _pure_; - -int ip_tos_to_string_alloc(int i, char **s); -int ip_tos_from_string(const char *s); - extern int saved_argc; extern char **saved_argv; @@ -476,182 +81,36 @@ bool kexec_loaded(void); int prot_from_flags(int flags) _const_; -char *format_bytes(char *buf, size_t l, uint64_t t); - -int fd_wait_for_event(int fd, int event, usec_t timeout); - -void* memdup(const void *p, size_t l) _alloc_(2); - -int fd_inc_sndbuf(int fd, size_t n); -int fd_inc_rcvbuf(int fd, size_t n); - int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); -int setrlimit_closest(int resource, const struct rlimit *rlim); - -bool http_url_is_valid(const char *url) _pure_; -bool documentation_url_is_valid(const char *url) _pure_; - -bool http_etag_is_valid(const char *etag); - bool in_initrd(void); -int get_home_dir(char **ret); -int get_shell(char **_ret); - -static inline void freep(void *p) { - free(*(void**) p); -} - -static inline void closep(int *fd) { - safe_close(*fd); -} - -static inline void umaskp(mode_t *u) { - umask(*u); -} - -static inline void close_pairp(int (*p)[2]) { - safe_close_pair(*p); -} - -static inline void fclosep(FILE **f) { - safe_fclose(*f); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); - -#define _cleanup_free_ _cleanup_(freep) -#define _cleanup_close_ _cleanup_(closep) -#define _cleanup_umask_ _cleanup_(umaskp) -#define _cleanup_globfree_ _cleanup_(globfree) -#define _cleanup_fclose_ _cleanup_(fclosep) -#define _cleanup_pclose_ _cleanup_(pclosep) -#define _cleanup_closedir_ _cleanup_(closedirp) -#define _cleanup_endmntent_ _cleanup_(endmntentp) -#define _cleanup_close_pair_ _cleanup_(close_pairp) - -_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return malloc(a * b); -} - -_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return realloc(p, a * b); -} - -_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return memdup(p, a * b); -} - -bool filename_is_valid(const char *p) _pure_; -bool path_is_safe(const char *p) _pure_; -bool string_is_safe(const char *p) _pure_; -bool string_has_cc(const char *p, const char *ok) _pure_; - -/** - * Check if a string contains any glob patterns. - */ -_pure_ static inline bool string_is_glob(const char *p) { - return !!strpbrk(p, GLOB_CHARS); -} - void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), void *arg); -#define _(String) gettext (String) -#define N_(String) String -void init_gettext(void); -bool is_locale_utf8(void); - -typedef enum DrawSpecialChar { - DRAW_TREE_VERTICAL, - DRAW_TREE_BRANCH, - DRAW_TREE_RIGHT, - DRAW_TREE_SPACE, - DRAW_TRIANGULAR_BULLET, - DRAW_BLACK_CIRCLE, - DRAW_ARROW, - DRAW_DASH, - _DRAW_SPECIAL_CHAR_MAX -} DrawSpecialChar; - -const char *draw_special_char(DrawSpecialChar ch); - -char *strreplace(const char *text, const char *old_string, const char *new_string); +/** + * Normal qsort requires base to be nonnull. Here were require + * that only if nmemb > 0. + */ +static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { + if (nmemb <= 1) + return; -char *strip_tab_ansi(char **p, size_t *l); + assert(base); + qsort(base, nmemb, size, compar); +} int on_ac_power(void); -int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); -int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); - -#define FOREACH_LINE(line, f, on_error) \ - for (;;) \ - if (!fgets(line, sizeof(line), f)) { \ - if (ferror(f)) { \ - on_error; \ - } \ - break; \ - } else - -#define FOREACH_DIRENT(de, d, on_error) \ - for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ - if (!de) { \ - if (errno > 0) { \ - on_error; \ - } \ - break; \ - } else if (hidden_file((de)->d_name)) \ - continue; \ - else - -#define FOREACH_DIRENT_ALL(de, d, on_error) \ - for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ - if (!de) { \ - if (errno > 0) { \ - on_error; \ - } \ - break; \ - } else +#define memzero(x,l) (memset((x), 0, (l))) +#define zero(x) (memzero(&(x), sizeof(x))) static inline void *mempset(void *s, int c, size_t n) { memset(s, c, n); return (uint8_t*)s + n; } -char *hexmem(const void *p, size_t l); -int unhexmem(const char *p, size_t l, void **mem, size_t *len); - -char *base32hexmem(const void *p, size_t l, bool padding); -int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); - -char *base64mem(const void *p, size_t l); -int unbase64mem(const char *p, size_t l, void **mem, size_t *len); - -char *strextend(char **x, ...) _sentinel_; -char *strrep(const char *s, unsigned n); - -void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); -void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); -#define GREEDY_REALLOC(array, allocated, need) \ - greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) - -#define GREEDY_REALLOC0(array, allocated, need) \ - greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) - static inline void _reset_errno_(int *saved_errno) { errno = *saved_errno; } @@ -667,20 +126,6 @@ static inline int negative_errno(void) { return -errno; } -struct _umask_struct_ { - mode_t mask; - bool quit; -}; - -static inline void _reset_umask_(struct _umask_struct_ *s) { - umask(s->mask); -}; - -#define RUN_WITH_UMASK(mask) \ - for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ - !_saved_umask_.quit ; \ - _saved_umask_.quit = true) - static inline unsigned u64log2(uint64_t n) { #if __SIZEOF_LONG_LONG__ == 8 return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; @@ -718,224 +163,15 @@ static inline unsigned log2u_round_up(unsigned x) { return log2u(x - 1) + 1; } -static inline bool logind_running(void) { - return access("/run/systemd/seats/", F_OK) >= 0; -} - -#define DECIMAL_STR_WIDTH(x) \ - ({ \ - typeof(x) _x_ = (x); \ - unsigned ans = 1; \ - while (_x_ /= 10) \ - ans++; \ - ans; \ - }) - -int unlink_noerrno(const char *path); - -#define alloca0(n) \ - ({ \ - char *_new_; \ - size_t _len_ = n; \ - _new_ = alloca(_len_); \ - (void *) memset(_new_, 0, _len_); \ - }) - -/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ -#define alloca_align(size, align) \ - ({ \ - void *_ptr_; \ - size_t _mask_ = (align) - 1; \ - _ptr_ = alloca((size) + _mask_); \ - (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ - }) - -#define alloca0_align(size, align) \ - ({ \ - void *_new_; \ - size_t _size_ = (size); \ - _new_ = alloca_align(_size_, (align)); \ - (void*)memset(_new_, 0, _size_); \ - }) - -#define strjoina(a, ...) \ - ({ \ - const char *_appendees_[] = { a, __VA_ARGS__ }; \ - char *_d_, *_p_; \ - int _len_ = 0; \ - unsigned _i_; \ - for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ - _len_ += strlen(_appendees_[_i_]); \ - _p_ = _d_ = alloca(_len_ + 1); \ - for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ - _p_ = stpcpy(_p_, _appendees_[_i_]); \ - *_p_ = 0; \ - _d_; \ - }) - bool id128_is_valid(const char *s) _pure_; -int split_pair(const char *s, const char *sep, char **l, char **r); - -int shall_restore_state(void); - -/** - * Normal qsort requires base to be nonnull. Here were require - * that only if nmemb > 0. - */ -static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { - if (nmemb <= 1) - return; - - assert(base); - qsort(base, nmemb, size, compar); -} - -/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ -static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { - - if (needlelen <= 0) - return (void*) haystack; - - if (haystacklen < needlelen) - return NULL; - - assert(haystack); - assert(needle); - - return memmem(haystack, haystacklen, needle, needlelen); -} - -int proc_cmdline(char **ret); -int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value)); -int get_proc_cmdline_key(const char *parameter, char **value); - int container_get_leader(const char *machine, pid_t *pid); int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); -int getpeercred(int fd, struct ucred *ucred); -int getpeersec(int fd, char **ret); - -int writev_safe(int fd, const struct iovec *w, int j); - -int mkostemp_safe(char *pattern, int flags); -int open_tmpfile(const char *path, int flags); - -int fd_warn_permissions(const char *path, int fd); - -#ifndef PERSONALITY_INVALID -/* personality(7) documents that 0xffffffffUL is used for querying the - * current personality, hence let's use that here as error - * indicator. */ -#define PERSONALITY_INVALID 0xffffffffLU -#endif - -unsigned long personality_from_string(const char *p); -const char *personality_to_string(unsigned long); - uint64_t physical_memory(void); -void hexdump(FILE *f, const void *p, size_t s); - -union file_handle_union { - struct file_handle handle; - char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; -}; -#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } - int update_reboot_param_file(const char *param); -int umount_recursive(const char *target, int flags); - -int bind_remount_recursive(const char *prefix, bool ro); - -int fflush_and_check(FILE *f); - -int tempfn_xxxxxx(const char *p, const char *extra, char **ret); -int tempfn_random(const char *p, const char *extra, char **ret); -int tempfn_random_child(const char *p, const char *extra, char **ret); - -int take_password_lock(const char *root); - -int is_symlink(const char *path); -int is_dir(const char *path, bool follow); -int is_device_node(const char *path); - -typedef enum ExtractFlags { - EXTRACT_RELAX = 1, - EXTRACT_CUNESCAPE = 2, - EXTRACT_CUNESCAPE_RELAX = 4, - EXTRACT_QUOTES = 8, - EXTRACT_DONT_COALESCE_SEPARATORS = 16, -} ExtractFlags; - -int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); -int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); -int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; - -int free_and_strdup(char **p, const char *s); - -#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) - -#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ - for ((e) = &buffer.ev; \ - (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \ - (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len)) - -union inotify_event_buffer { - struct inotify_event ev; - uint8_t raw[INOTIFY_EVENT_MAX]; -}; - -#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) - -ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags); - -int fd_setcrtime(int fd, usec_t usec); -int fd_getcrtime(int fd, usec_t *usec); -int path_getcrtime(const char *p, usec_t *usec); -int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags); - -int same_fd(int a, int b); - -int chattr_fd(int fd, unsigned value, unsigned mask); -int chattr_path(const char *p, unsigned value, unsigned mask); - -int read_attr_fd(int fd, unsigned *ret); -int read_attr_path(const char *p, unsigned *ret); - -#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) - -ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); - -void sigkill_wait(pid_t *pid); -#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait) - -int syslog_parse_priority(const char **p, int *priority, bool with_facility); - -void cmsg_close_all(struct msghdr *mh); - -int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); - -char *shell_escape(const char *s, const char *bad); -char *shell_maybe_quote(const char *s); - -int parse_mode(const char *s, mode_t *ret); - -int mount_move_root(const char *path); - -int reset_uid_gid(void); - -int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); -int fgetxattr_malloc(int fd, const char *name, char **value); - -int send_one_fd(int transport_fd, int fd, int flags); -int receive_one_fd(int transport_fd, int flags); - -void nop_signal_handler(int sig); - int version(void); - -bool fdname_is_valid(const char *s); diff --git a/src/basic/verbs.c b/src/basic/verbs.c index c7beccc2dc..d63062d39e 100644 --- a/src/basic/verbs.c +++ b/src/basic/verbs.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "string-util.h" #include "util.h" #include "verbs.h" diff --git a/src/basic/virt.c b/src/basic/virt.c index 70543177b6..d088b7a804 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -19,18 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> +#include <string.h> #include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "fileio.h" #include "process-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" #include "virt.h" -#include "fileio.h" static int detect_vm_cpuid(void) { - /* Both CPUID and DMI are x86 specific interfaces... */ + /* CPUID is an x86 specific interface. */ #if defined(__i386__) || defined(__x86_64__) static const struct { @@ -140,11 +144,10 @@ static int detect_vm_device_tree(void) { } static int detect_vm_dmi(void) { - - /* Both CPUID and DMI are x86 specific interfaces... */ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) static const char *const dmi_vendors[] = { + "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */ "/sys/class/dmi/id/sys_vendor", "/sys/class/dmi/id/board_vendor", "/sys/class/dmi/id/bios_vendor" @@ -154,6 +157,7 @@ static int detect_vm_dmi(void) { const char *vendor; int id; } dmi_vendor_table[] = { + { "KVM", VIRTUALIZATION_KVM }, { "QEMU", VIRTUALIZATION_QEMU }, /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ { "VMware", VIRTUALIZATION_VMWARE }, @@ -263,12 +267,7 @@ int detect_vm(void) { if (cached_found >= 0) return cached_found; - /* Try xen capabilities file first, if not found try - * high-level hypervisor sysfs file: - * - * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ - - r = detect_vm_xen(); + r = detect_vm_cpuid(); if (r < 0) return r; if (r != VIRTUALIZATION_NONE) @@ -280,7 +279,14 @@ int detect_vm(void) { if (r != VIRTUALIZATION_NONE) goto finish; - r = detect_vm_cpuid(); + /* x86 xen will most likely be detected by cpuid. If not (most likely + * because we're not an x86 guest), then we should try the xen capabilities + * file next. If that's not found, then we check for the high-level + * hypervisor sysfs file: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ + + r = detect_vm_xen(); if (r < 0) return r; if (r != VIRTUALIZATION_NONE) @@ -323,6 +329,7 @@ int detect_container(void) { { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT }, { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN }, { "docker", VIRTUALIZATION_DOCKER }, + { "rkt", VIRTUALIZATION_RKT }, }; static thread_local int cached_found = _VIRTUALIZATION_INVALID; @@ -393,7 +400,7 @@ int detect_container(void) { goto finish; } - r = VIRTUALIZATION_NONE; + r = VIRTUALIZATION_CONTAINER_OTHER; finish: cached_found = r; @@ -410,6 +417,16 @@ int detect_virtualization(void) { return detect_vm(); } +int running_in_chroot(void) { + int ret; + + ret = files_same("/proc/1/root", "/"); + if (ret < 0) + return ret; + + return ret == 0; +} + static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { [VIRTUALIZATION_NONE] = "none", [VIRTUALIZATION_KVM] = "kvm", @@ -429,6 +446,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { [VIRTUALIZATION_LXC] = "lxc", [VIRTUALIZATION_OPENVZ] = "openvz", [VIRTUALIZATION_DOCKER] = "docker", + [VIRTUALIZATION_RKT] = "rkt", [VIRTUALIZATION_CONTAINER_OTHER] = "container-other", }; diff --git a/src/basic/virt.h b/src/basic/virt.h index 449e069901..aca961867c 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -48,6 +48,7 @@ enum { VIRTUALIZATION_LXC, VIRTUALIZATION_OPENVZ, VIRTUALIZATION_DOCKER, + VIRTUALIZATION_RKT, VIRTUALIZATION_CONTAINER_OTHER, VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER, @@ -67,5 +68,7 @@ int detect_vm(void); int detect_container(void); int detect_virtualization(void); +int running_in_chroot(void); + const char *virtualization_to_string(int v) _const_; int virtualization_from_string(const char *s) _pure_; diff --git a/src/basic/web-util.c b/src/basic/web-util.c new file mode 100644 index 0000000000..68ec04021b --- /dev/null +++ b/src/basic/web-util.c @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +#include "string-util.h" +#include "utf8.h" +#include "web-util.h" + +bool http_etag_is_valid(const char *etag) { + if (isempty(etag)) + return false; + + if (!endswith(etag, "\"")) + return false; + + if (!startswith(etag, "\"") && !startswith(etag, "W/\"")) + return false; + + return true; +} + +bool http_url_is_valid(const char *url) { + const char *p; + + if (isempty(url)) + return false; + + p = startswith(url, "http://"); + if (!p) + p = startswith(url, "https://"); + if (!p) + return false; + + if (isempty(p)) + return false; + + return ascii_is_valid(p); +} + +bool documentation_url_is_valid(const char *url) { + const char *p; + + if (isempty(url)) + return false; + + if (http_url_is_valid(url)) + return true; + + p = startswith(url, "file:/"); + if (!p) + p = startswith(url, "info:"); + if (!p) + p = startswith(url, "man:"); + + if (isempty(p)) + return false; + + return ascii_is_valid(p); +} diff --git a/src/core/dbus-snapshot.h b/src/basic/web-util.h index 9288f44e15..40c1509eb8 100644 --- a/src/core/dbus-snapshot.h +++ b/src/basic/web-util.h @@ -21,8 +21,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-bus.h" +#include <stdbool.h> -extern const sd_bus_vtable bus_snapshot_vtable[]; +#include "macro.h" -int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error); +bool http_url_is_valid(const char *url) _pure_; + +bool documentation_url_is_valid(const char *url) _pure_; + +bool http_etag_is_valid(const char *etag); diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c new file mode 100644 index 0000000000..6abdaedc3e --- /dev/null +++ b/src/basic/xattr-util.c @@ -0,0 +1,195 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/xattr.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "sparse-endian.h" +#include "stdio-util.h" +#include "util.h" +#include "xattr-util.h" + +int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { + char *v; + size_t l; + ssize_t n; + + assert(path); + assert(name); + assert(value); + + for (l = 100; ; l = (size_t) n + 1) { + v = new0(char, l); + if (!v) + return -ENOMEM; + + if (allow_symlink) + n = lgetxattr(path, name, v, l); + else + n = getxattr(path, name, v, l); + + if (n >= 0 && (size_t) n < l) { + *value = v; + return n; + } + + free(v); + + if (n < 0 && errno != ERANGE) + return -errno; + + if (allow_symlink) + n = lgetxattr(path, name, NULL, 0); + else + n = getxattr(path, name, NULL, 0); + if (n < 0) + return -errno; + } +} + +int fgetxattr_malloc(int fd, const char *name, char **value) { + char *v; + size_t l; + ssize_t n; + + assert(fd >= 0); + assert(name); + assert(value); + + for (l = 100; ; l = (size_t) n + 1) { + v = new0(char, l); + if (!v) + return -ENOMEM; + + n = fgetxattr(fd, name, v, l); + + if (n >= 0 && (size_t) n < l) { + *value = v; + return n; + } + + free(v); + + if (n < 0 && errno != ERANGE) + return -errno; + + n = fgetxattr(fd, name, NULL, 0); + if (n < 0) + return -errno; + } +} + +ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) { + char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + _cleanup_close_ int fd = -1; + ssize_t l; + + /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ + + fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); + if (fd < 0) + return -errno; + + xsprintf(fn, "/proc/self/fd/%i", fd); + + l = getxattr(fn, attribute, value, size); + if (l < 0) + return -errno; + + return l; +} + +static int parse_crtime(le64_t le, usec_t *usec) { + uint64_t u; + + assert(usec); + + u = le64toh(le); + if (u == 0 || u == (uint64_t) -1) + return -EIO; + + *usec = (usec_t) u; + return 0; +} + +int fd_getcrtime(int fd, usec_t *usec) { + le64_t le; + ssize_t n; + + assert(fd >= 0); + assert(usec); + + /* Until Linux gets a real concept of birthtime/creation time, + * let's fake one with xattrs */ + + n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le)); + if (n < 0) + return -errno; + if (n != sizeof(le)) + return -EIO; + + return parse_crtime(le, usec); +} + +int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) { + le64_t le; + ssize_t n; + + n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags); + if (n < 0) + return -errno; + if (n != sizeof(le)) + return -EIO; + + return parse_crtime(le, usec); +} + +int path_getcrtime(const char *p, usec_t *usec) { + le64_t le; + ssize_t n; + + assert(p); + assert(usec); + + n = getxattr(p, "user.crtime_usec", &le, sizeof(le)); + if (n < 0) + return -errno; + if (n != sizeof(le)) + return -EIO; + + return parse_crtime(le, usec); +} + +int fd_setcrtime(int fd, usec_t usec) { + le64_t le; + + assert(fd >= 0); + + if (usec <= 0) + usec = now(CLOCK_REALTIME); + + le = htole64((uint64_t) usec); + if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0) + return -errno; + + return 0; +} diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h new file mode 100644 index 0000000000..cf4cb12a25 --- /dev/null +++ b/src/basic/xattr-util.h @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/types.h> + +#include "time-util.h" + +int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); +int fgetxattr_malloc(int fd, const char *name, char **value); + +ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags); + +int fd_setcrtime(int fd, usec_t usec); + +int fd_getcrtime(int fd, usec_t *usec); +int path_getcrtime(const char *p, usec_t *usec); +int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags); diff --git a/src/basic/xml.c b/src/basic/xml.c index 15c629b188..8126bce212 100644 --- a/src/basic/xml.c +++ b/src/basic/xml.c @@ -21,6 +21,7 @@ #include <string.h> +#include "string-util.h" #include "util.h" #include "xml.h" diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index ddb5c88806..03fb413fe5 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -27,13 +27,17 @@ #include <stdlib.h> #include <string.h> +#include "alloc-util.h" #include "conf-files.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" +#include "string-util.h" #include "strv.h" #include "util.h" -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("binfmt.d"); static int delete_rule(const char *rule) { _cleanup_free_ char *x = NULL, *fn = NULL; @@ -90,8 +94,7 @@ static int apply_file(const char *path, bool ignore_enoent) { if (feof(f)) break; - log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); } p = strstrip(l); diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index f991e30cfa..4cf42d17f3 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -37,9 +37,14 @@ #include <sys/statfs.h> #include <unistd.h> +#include "alloc-util.h" #include "blkid-util.h" #include "efivars.h" +#include "fd-util.h" +#include "fileio.h" +#include "locale-util.h" #include "rm-rf.h" +#include "string-util.h" #include "util.h" static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) { diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index 83ad90c222..6a0e1d6b14 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -33,30 +33,37 @@ ***/ -#include <sys/resource.h> -#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> #include <signal.h> +#include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> +#include <sys/resource.h> #include <time.h> -#include <getopt.h> -#include <limits.h> -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include "systemd/sd-journal.h" +#include <unistd.h> -#include "util.h" +#include "sd-journal.h" + +#include "alloc-util.h" +#include "bootchart.h" +#include "conf-parser.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" +#include "list.h" #include "macro.h" -#include "conf-parser.h" -#include "strxcpyx.h" +#include "parse-util.h" #include "path-util.h" #include "store.h" +#include "string-util.h" +#include "strxcpyx.h" #include "svg.h" -#include "bootchart.h" -#include "list.h" +#include "util.h" static int exiting = 0; @@ -88,8 +95,6 @@ static void signal_handler(int sig) { exiting = 1; } -#define BOOTCHART_CONF "/etc/systemd/bootchart.conf" - #define BOOTCHART_MAX (16*1024*1024) static void parse_conf(void) { @@ -110,8 +115,8 @@ static void parse_conf(void) { { NULL, NULL, NULL, 0, NULL } }; - config_parse_many(BOOTCHART_CONF, - CONF_DIRS_NULSTR("systemd/bootchart.conf"), + config_parse_many(PKGSYSCONFDIR "/bootchart.conf", + CONF_PATHS_NULSTR("systemd/bootchart.conf.d"), NULL, config_item_table_lookup, items, true, NULL); if (init != NULL) diff --git a/src/bootchart/store.c b/src/bootchart/store.c index caa97b97fc..c1b1e77e44 100644 --- a/src/bootchart/store.c +++ b/src/bootchart/store.c @@ -22,22 +22,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <stdlib.h> +#include <dirent.h> +#include <fcntl.h> #include <limits.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <dirent.h> -#include <fcntl.h> #include <time.h> +#include <unistd.h> -#include "util.h" -#include "time-util.h" -#include "strxcpyx.h" -#include "store.h" +#include "alloc-util.h" #include "bootchart.h" #include "cgroup-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "fileio.h" +#include "parse-util.h" +#include "store.h" +#include "string-util.h" +#include "strxcpyx.h" +#include "time-util.h" +#include "util.h" /* * Alloc a static 4k buffer for stdio - primarily used to increase diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c index db5fc863b0..05330c0577 100644 --- a/src/bootchart/svg.c +++ b/src/bootchart/svg.c @@ -30,6 +30,7 @@ #include <sys/utsname.h> #include <fcntl.h> +#include "alloc-util.h" #include "architecture.h" #include "util.h" #include "fileio.h" @@ -39,6 +40,7 @@ #include "bootchart.h" #include "list.h" #include "utf8.h" +#include "fd-util.h" #define time_to_graph(t) ((t) * arg_scale_x) #define ps_to_graph(n) ((n) * arg_scale_y) diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c index 2bc265d9b4..6a7134644f 100644 --- a/src/bus-proxyd/bus-proxyd.c +++ b/src/bus-proxyd/bus-proxyd.c @@ -33,14 +33,18 @@ #include "sd-daemon.h" +#include "alloc-util.h" #include "bus-internal.h" #include "bus-xml-policy.h" -#include "capability.h" +#include "capability-util.h" #include "def.h" +#include "fd-util.h" #include "formats-util.h" #include "log.h" #include "proxy.h" +#include "string-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" static char *arg_address = NULL; @@ -85,11 +89,11 @@ static void *run_client(void *userdata) { int r; r = proxy_new(&p, c->fd, c->fd, arg_address); + c->fd = -1; + if (r < 0) goto exit; - c->fd = -1; - /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */ r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid); if (r >= (ssize_t)sizeof(comm)) @@ -116,13 +120,12 @@ static int loop_clients(int accept_fd, uid_t bus_uid) { int r; r = pthread_attr_init(&attr); - if (r < 0) { - return log_error_errno(errno, "Cannot initialize pthread attributes: %m"); - } + if (r != 0) + return log_error_errno(r, "Cannot initialize pthread attributes: %m"); r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (r < 0) { - r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m"); + if (r != 0) { + r = log_error_errno(r, "Cannot mark pthread attributes as detached: %m"); goto finish; } @@ -156,8 +159,8 @@ static int loop_clients(int accept_fd, uid_t bus_uid) { c->bus_uid = bus_uid; r = pthread_create(&tid, &attr, run_client, c); - if (r < 0) { - log_error("Cannot spawn thread: %m"); + if (r != 0) { + log_warning_errno(r, "Cannot spawn thread, ignoring: %m"); client_context_free(c); continue; } diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c index 9a3b451c56..f0834e9525 100644 --- a/src/bus-proxyd/bus-xml-policy.c +++ b/src/bus-proxyd/bus-xml-policy.c @@ -19,15 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "xml.h" -#include "fileio.h" -#include "strv.h" -#include "set.h" -#include "conf-files.h" +#include "sd-login.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-xml-policy.h" -#include "sd-login.h" +#include "conf-files.h" +#include "fileio.h" #include "formats-util.h" +#include "locale-util.h" +#include "set.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "xml.h" static void policy_item_free(PolicyItem *i) { assert(i); @@ -1186,14 +1192,14 @@ int shared_policy_new(SharedPolicy **out) { return log_oom(); r = pthread_mutex_init(&sp->lock, NULL); - if (r < 0) { - log_error_errno(r, "Cannot initialize shared policy mutex: %m"); + if (r != 0) { + r = log_error_errno(r, "Cannot initialize shared policy mutex: %m"); goto exit_free; } r = pthread_rwlock_init(&sp->rwlock, NULL); - if (r < 0) { - log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); + if (r != 0) { + r = log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); goto exit_mutex; } diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c index fa4aee691a..2e8bd83efd 100644 --- a/src/bus-proxyd/driver.c +++ b/src/bus-proxyd/driver.c @@ -21,21 +21,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> #include <stddef.h> +#include <string.h> -#include "util.h" #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" -#include "strv.h" -#include "set.h" #include "driver.h" +#include "env-util.h" #include "proxy.h" +#include "set.h" +#include "strv.h" #include "synthesize.h" -#include "env-util.h" +#include "util.h" static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c index 88800f5e7f..db399b24f2 100644 --- a/src/bus-proxyd/proxy.c +++ b/src/bus-proxyd/proxy.c @@ -22,27 +22,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <sys/types.h> -#include <string.h> #include <errno.h> #include <poll.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> -#include "log.h" -#include "util.h" -#include "sd-daemon.h" #include "sd-bus.h" +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" -#include "strv.h" -#include "bus-control.h" -#include "set.h" #include "bus-xml-policy.h" #include "driver.h" +#include "fd-util.h" +#include "formats-util.h" +#include "log.h" #include "proxy.h" +#include "set.h" +#include "strv.h" #include "synthesize.h" -#include "formats-util.h" +#include "user-util.h" +#include "util.h" static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) { _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; @@ -100,18 +104,24 @@ static int proxy_create_destination(Proxy *p, const char *destination, const cha return 0; } -static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) { - _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; +static int proxy_create_local(Proxy *p, bool negotiate_fds) { sd_id128_t server_id; + sd_bus *b; int r; r = sd_bus_new(&b); if (r < 0) return log_error_errno(r, "Failed to allocate bus: %m"); - r = sd_bus_set_fd(b, in_fd, out_fd); - if (r < 0) + r = sd_bus_set_fd(b, p->local_in, p->local_out); + if (r < 0) { + sd_bus_unref(b); return log_error_errno(r, "Failed to set fds: %m"); + } + + /* The fds are now owned by the bus, and we indicate that by + * storing the bus object in the proxy object. */ + p->local_bus = b; r = sd_bus_get_bus_id(p->destination_bus, &server_id); if (r < 0) @@ -139,8 +149,6 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd if (r < 0) return log_error_errno(r, "Failed to start bus client: %m"); - p->local_bus = b; - b = NULL; return 0; } @@ -224,9 +232,17 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { bool is_unix; int r; + /* This takes possession/destroys the file descriptors passed + * in even on failure. The caller should hence forget about + * the fds in all cases after calling this function and not + * close them. */ + p = new0(Proxy, 1); - if (!p) + if (!p) { + safe_close(in_fd); + safe_close(out_fd); return log_oom(); + } p->local_in = in_fd; p->local_out = out_fd; @@ -247,7 +263,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { if (r < 0) return r; - r = proxy_create_local(p, in_fd, out_fd, is_unix); + r = proxy_create_local(p, is_unix); if (r < 0) return r; @@ -257,6 +273,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { *out = p; p = NULL; + return 0; } @@ -273,7 +290,14 @@ Proxy *proxy_free(Proxy *p) { free(activation); } - sd_bus_flush_close_unref(p->local_bus); + if (p->local_bus) + sd_bus_flush_close_unref(p->local_bus); + else { + safe_close(p->local_in); + if (p->local_out != p->local_in) + safe_close(p->local_out); + } + sd_bus_flush_close_unref(p->destination_bus); set_free_free(p->owned_names); free(p); diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h index 6aac650ac9..7b2e5d422f 100644 --- a/src/bus-proxyd/proxy.h +++ b/src/bus-proxyd/proxy.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "bus-xml-policy.h" typedef struct Proxy Proxy; diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c index 168fc9ead0..6e47884209 100644 --- a/src/bus-proxyd/stdio-bridge.c +++ b/src/bus-proxyd/stdio-bridge.c @@ -30,6 +30,7 @@ #include "sd-daemon.h" #include "sd-bus.h" +#include "alloc-util.h" #include "bus-internal.h" #include "bus-util.h" #include "def.h" @@ -37,6 +38,7 @@ #include "log.h" #include "proxy.h" #include "strv.h" +#include "user-util.h" #include "util.h" static char *arg_address = NULL; diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c index 15d99103f6..7f1f9dc28d 100644 --- a/src/bus-proxyd/synthesize.c +++ b/src/bus-proxyd/synthesize.c @@ -23,13 +23,14 @@ #include <stddef.h> -#include "util.h" #include "sd-bus.h" + #include "bus-internal.h" +#include "bus-match.h" #include "bus-message.h" #include "bus-util.h" -#include "bus-match.h" #include "synthesize.h" +#include "util.h" int synthetic_driver_send(sd_bus *b, sd_bus_message *m) { int r; diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h index b596daddf2..ddfe2fd266 100644 --- a/src/bus-proxyd/synthesize.h +++ b/src/bus-proxyd/synthesize.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "proxy.h" int synthetic_driver_send(sd_bus *b, sd_bus_message *m); diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c index d19d0e1b60..1f465edd91 100644 --- a/src/bus-proxyd/test-bus-xml-policy.c +++ b/src/bus-proxyd/test-bus-xml-policy.c @@ -19,15 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> #include <stddef.h> +#include <unistd.h> -#include "log.h" -#include "util.h" #include "sd-bus.h" -#include "strv.h" + +#include "alloc-util.h" #include "bus-xml-policy.h" +#include "log.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static int test_policy_load(Policy *p, const char *name) { _cleanup_free_ char *path = NULL; diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index 41c539a1bc..22efc58ac9 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -27,6 +27,7 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "cgroup-show.h" @@ -164,8 +165,10 @@ static int get_cgroup_root(char **ret) { } static void show_cg_info(const char *controller, const char *path) { - if (cg_unified() <= 0) + + if (cg_unified() <= 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER)) printf("Controller %s; ", controller); + printf("Control group %s:\n", isempty(path) ? "/" : path); fflush(stdout); } @@ -269,6 +272,7 @@ int main(int argc, char *argv[]) { show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root); + printf("-.slice\n"); r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags); } } diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index b79519dd09..e48234f075 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -22,8 +22,9 @@ #include <stdlib.h> #include "sd-bus.h" -#include "log.h" + #include "bus-util.h" +#include "log.h" int main(int argc, char *argv[]) { _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index ad9cd2532f..eea8aea76b 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -30,11 +30,14 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "cgroup-util.h" +#include "fd-util.h" #include "fileio.h" #include "hashmap.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "terminal-util.h" diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c index 5a18e263a8..3ae46d8cfb 100644 --- a/src/core/audit-fd.c +++ b/src/core/audit-fd.c @@ -30,6 +30,7 @@ #include "log.h" #include "util.h" +#include "fd-util.h" static bool initialized = false; static int audit_fd; diff --git a/src/core/automount.c b/src/core/automount.c index e0535ec201..85b7b4e842 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -20,29 +20,37 @@ ***/ #include <errno.h> -#include <limits.h> -#include <sys/mount.h> -#include <unistd.h> #include <fcntl.h> +#include <limits.h> +#include <linux/auto_dev-ioctl.h> +#include <linux/auto_fs4.h> #include <sys/epoll.h> +#include <sys/mount.h> #include <sys/stat.h> -#include <linux/auto_fs4.h> -#include <linux/auto_dev-ioctl.h> +#include <unistd.h> -#include "unit.h" +#include "alloc-util.h" +#include "async.h" #include "automount.h" -#include "mount.h" -#include "unit-name.h" -#include "special.h" +#include "bus-error.h" +#include "bus-util.h" +#include "dbus-automount.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" #include "label.h" #include "mkdir.h" +#include "mount-util.h" +#include "mount.h" +#include "parse-util.h" #include "path-util.h" -#include "dbus-automount.h" -#include "bus-util.h" -#include "bus-error.h" -#include "formats-util.h" #include "process-util.h" -#include "async.h" +#include "special.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" +#include "unit-name.h" +#include "unit.h" static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { [AUTOMOUNT_DEAD] = UNIT_INACTIVE, @@ -81,26 +89,11 @@ static void automount_init(Unit *u) { UNIT(a)->ignore_on_isolate = true; } -static void repeat_unmount(const char *path) { - assert(path); - - for (;;) { - /* If there are multiple mounts on a mount point, this - * removes them all */ - - if (umount2(path, MNT_DETACH) >= 0) - continue; - - if (errno != EINVAL) - log_error_errno(errno, "Failed to unmount: %m"); - - break; - } -} - static int automount_send_ready(Automount *a, Set *tokens, int status); static void unmount_autofs(Automount *a) { + int r; + assert(a); if (a->pipe_fd < 0) @@ -116,8 +109,11 @@ static void unmount_autofs(Automount *a) { * around */ if (a->where && (UNIT(a)->manager->exit_code != MANAGER_RELOAD && - UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) - repeat_unmount(a->where); + UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) { + r = repeat_unmount(a->where, MNT_DETACH); + if (r < 0) + log_error_errno(r, "Failed to unmount: %m"); + } } static void automount_done(Unit *u) { @@ -137,13 +133,12 @@ static void automount_done(Unit *u) { static int automount_add_mount_links(Automount *a) { _cleanup_free_ char *parent = NULL; - int r; assert(a); - r = path_get_parent(a->where, &parent); - if (r < 0) - return r; + parent = dirname_malloc(a->where); + if (!parent) + return -ENOMEM; return unit_require_mounts_for(UNIT(a), parent); } @@ -153,6 +148,9 @@ static int automount_add_default_dependencies(Automount *a) { assert(a); + if (!UNIT(a)->default_dependencies) + return 0; + if (UNIT(a)->manager->running_as != MANAGER_SYSTEM) return 0; @@ -224,11 +222,9 @@ static int automount_load(Unit *u) { if (r < 0) return r; - if (UNIT(a)->default_dependencies) { - r = automount_add_default_dependencies(a); - if (r < 0) - return r; - } + r = automount_add_default_dependencies(a); + if (r < 0) + return r; } return automount_verify(a); @@ -608,12 +604,16 @@ static void automount_enter_waiting(Automount *a) { return; fail: + log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m"); + safe_close_pair(p); - if (mounted) - repeat_unmount(a->where); + if (mounted) { + r = repeat_unmount(a->where, MNT_DETACH); + if (r < 0) + log_error_errno(r, "Failed to unmount, ignoring: %m"); + } - log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m"); automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); } @@ -728,8 +728,7 @@ static void automount_enter_runnning(Automount *a) { if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) log_unit_info(UNIT(a), "Automount point already active?"); else { - r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), - JOB_REPLACE, true, &error, NULL); + r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL); if (r < 0) { log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r)); goto fail; @@ -974,7 +973,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo break; } - r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL); + r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL); if (r < 0) { log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r)); goto fail; diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c index 0c4b3e7c8b..d22a80c91f 100644 --- a/src/core/bus-endpoint.c +++ b/src/core/bus-endpoint.c @@ -19,10 +19,11 @@ #include <stdlib.h> -#include "kdbus.h" +#include "alloc-util.h" +#include "bus-endpoint.h" #include "bus-kernel.h" #include "bus-policy.h" -#include "bus-endpoint.h" +#include "kdbus.h" int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) { diff --git a/src/core/bus-policy.c b/src/core/bus-policy.c index a6a8fcd4d3..4907c268e8 100644 --- a/src/core/bus-policy.c +++ b/src/core/bus-policy.c @@ -19,10 +19,13 @@ #include <stdlib.h> -#include "kdbus.h" -#include "util.h" +#include "alloc-util.h" #include "bus-kernel.h" #include "bus-policy.h" +#include "kdbus.h" +#include "string-table.h" +#include "user-util.h" +#include "util.h" int bus_kernel_translate_access(BusPolicyAccess access) { assert(access >= 0); diff --git a/src/core/busname.c b/src/core/busname.c index 38becfc119..04fa12a4da 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -21,17 +21,23 @@ #include <sys/mman.h> -#include "special.h" -#include "formats-util.h" -#include "signal-util.h" -#include "bus-kernel.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-kernel.h" +#include "bus-policy.h" #include "bus-util.h" +#include "busname.h" +#include "dbus-busname.h" +#include "fd-util.h" +#include "formats-util.h" #include "kdbus.h" -#include "bus-policy.h" +#include "parse-util.h" +#include "process-util.h" #include "service.h" -#include "dbus-busname.h" -#include "busname.h" +#include "signal-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = { [BUSNAME_DEAD] = UNIT_INACTIVE, @@ -358,10 +364,9 @@ static int busname_coldplug(Unit *u) { if (n->deserialized_state == n->state) return 0; - if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) { - - if (n->control_pid <= 0) - return -EBADMSG; + if (n->control_pid > 0 && + pid_is_unwaited(n->control_pid) && + IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) { r = unit_watch_pid(UNIT(n), n->control_pid); if (r < 0) @@ -585,7 +590,13 @@ static void busname_enter_running(BusName *n) { } if (!pending) { - r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL); + if (!UNIT_ISSET(n->service)) { + log_unit_error(UNIT(n), "Service to activate vanished, refusing activation."); + r = -ENOENT; + goto fail; + } + + r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, &error, NULL); if (r < 0) goto fail; } diff --git a/src/core/busname.h b/src/core/busname.h index 1bc3290596..46f7b6f097 100644 --- a/src/core/busname.h +++ b/src/core/busname.h @@ -24,6 +24,8 @@ typedef struct BusName BusName; typedef struct BusNamePolicy BusNamePolicy; +#include "unit.h" + typedef enum BusNameResult { BUSNAME_SUCCESS, BUSNAME_FAILURE_RESOURCES, diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 0c790c33da..bed01fde21 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -22,12 +22,18 @@ #include <fcntl.h> #include <fnmatch.h> +#include "alloc-util.h" #include "cgroup-util.h" +#include "cgroup.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "special.h" - -#include "cgroup.h" +#include "string-table.h" +#include "string-util.h" #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC) @@ -1203,7 +1209,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret) { continue; /* Ignore processes that aren't our kids */ - if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid) + if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid) continue; if (pid != 0) diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c index 5162ce34cb..45f2c2ffd6 100644 --- a/src/core/dbus-automount.c +++ b/src/core/dbus-automount.c @@ -20,8 +20,9 @@ ***/ #include "automount.h" -#include "dbus-automount.h" #include "bus-util.h" +#include "string-util.h" +#include "dbus-automount.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult); diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c index b1ceb05b1a..05ac89c3c0 100644 --- a/src/core/dbus-busname.c +++ b/src/core/dbus-busname.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" +#include "bus-util.h" #include "busname.h" +#include "string-util.h" +#include "unit.h" #include "dbus-busname.h" -#include "bus-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index f334dc928d..3fd295baa9 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-util.h" -#include "path-util.h" #include "cgroup-util.h" #include "cgroup.h" #include "dbus-cgroup.h" +#include "fd-util.h" +#include "fileio.h" +#include "path-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); @@ -421,7 +424,9 @@ int bus_cgroup_set_property( fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); } - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(u, mode, name, buf); } @@ -495,7 +500,9 @@ int bus_cgroup_set_property( LIST_FOREACH(device_weights, a, c->blockio_device_weights) fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight); - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(u, mode, name, buf); } @@ -640,7 +647,9 @@ int bus_cgroup_set_property( LIST_FOREACH(device_allow, a, c->device_allow) fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(u, mode, name, buf); } diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h index c2a3910f3d..9dc187c066 100644 --- a/src/core/dbus-cgroup.h +++ b/src/core/dbus-cgroup.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "cgroup.h" extern const sd_bus_vtable bus_cgroup_vtable[]; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 030df55554..093179c003 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -25,22 +25,28 @@ #include <seccomp.h> #endif +#include "af-list.h" +#include "alloc-util.h" #include "bus-util.h" -#include "missing.h" -#include "ioprio.h" -#include "strv.h" -#include "fileio.h" -#include "execute.h" -#include "capability.h" +#include "capability-util.h" +#include "dbus-execute.h" #include "env-util.h" -#include "af-list.h" +#include "execute.h" +#include "fd-util.h" +#include "fileio.h" +#include "ioprio.h" +#include "missing.h" #include "namespace.h" +#include "parse-util.h" #include "path-util.h" -#include "dbus-execute.h" - +#include "process-util.h" +#include "rlimit-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "strv.h" +#include "syslog-util.h" +#include "utf8.h" BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput); @@ -83,45 +89,6 @@ static int property_get_environment_files( return sd_bus_message_close_container(reply); } -static int property_get_rlimit( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - struct rlimit *rl; - uint64_t u; - rlim_t x; - - assert(bus); - assert(reply); - assert(userdata); - - rl = *(struct rlimit**) userdata; - if (rl) - x = rl->rlim_max; - else { - struct rlimit buf = {}; - int z; - - z = rlimit_from_string(property); - assert(z >= 0); - - getrlimit(z, &buf); - x = buf.rlim_max; - } - - /* rlim_t might have different sizes, let's map - * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on - * all archs */ - u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x; - - return sd_bus_message_append(reply, "t", u); -} - static int property_get_oom_score_adjust( sd_bus *bus, const char *path, @@ -146,7 +113,7 @@ static int property_get_oom_score_adjust( n = 0; if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) - safe_atoi(t, &n); + safe_atoi32(t, &n); } return sd_bus_message_append(reply, "i", n); @@ -622,27 +589,64 @@ static int property_get_working_directory( return sd_bus_message_append(reply, "s", wd); } +static int property_get_syslog_level( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority)); +} + +static int property_get_syslog_facility( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority)); +} + const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -664,6 +668,8 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -882,6 +888,38 @@ int bus_exec_context_set_transient_property( } return 1; + } else if (streq(name, "SyslogLevel")) { + int level; + + r = sd_bus_message_read(message, "i", &level); + if (r < 0) + return r; + + if (!log_level_is_valid(level)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range"); + + if (mode != UNIT_CHECK) { + c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level; + unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level); + } + + return 1; + } else if (streq(name, "SyslogFacility")) { + int facility; + + r = sd_bus_message_read(message, "i", &facility); + if (r < 0) + return r; + + if (!log_facility_unshifted_is_valid(facility)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range"); + + if (mode != UNIT_CHECK) { + c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority); + unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility); + } + + return 1; } else if (streq(name, "Nice")) { int n; @@ -1124,18 +1162,299 @@ int bus_exec_context_set_transient_property( _cleanup_free_ char *joined = NULL; char **e; - e = strv_env_merge(2, c->environment, l); - if (!e) - return -ENOMEM; + if (strv_length(l) == 0) { + c->environment = strv_free(c->environment); + unit_write_drop_in_private_format(u, mode, name, "Environment=\n"); + } else { + e = strv_env_merge(2, c->environment, l); + if (!e) + return -ENOMEM; - strv_free(c->environment); - c->environment = e; + strv_free(c->environment); + c->environment = e; - joined = strv_join_quoted(c->environment); - if (!joined) - return -ENOMEM; + joined = strv_join_quoted(c->environment); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined); + } + } + + return 1; + + } else if (streq(name, "TimerSlackNSec")) { + + nsec_t n; + + r = sd_bus_message_read(message, "t", &n); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->timer_slack_nsec = n; + unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n); + } + + return 1; + + } else if (streq(name, "OOMScoreAdjust")) { + int oa; + + r = sd_bus_message_read(message, "i", &oa); + if (r < 0) + return r; + + if (!oom_score_adjust_is_valid(oa)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range"); + + if (mode != UNIT_CHECK) { + c->oom_score_adjust = oa; + c->oom_score_adjust_set = true; + unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa); + } + + return 1; + + } else if (streq(name, "EnvironmentFiles")) { + + _cleanup_free_ char *joined = NULL; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char **l = NULL; + size_t size = 0; + char **i; + + r = sd_bus_message_enter_container(message, 'a', "(sb)"); + if (r < 0) + return r; + + f = open_memstream(&joined, &size); + if (!f) + return -ENOMEM; + + STRV_FOREACH(i, c->environment_files) + fprintf(f, "EnvironmentFile=%s\n", *i); + + while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) { + const char *path; + int b; + + r = sd_bus_message_read(message, "sb", &path, &b); + if (r < 0) + return r; - unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined); + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (!isempty(path) && !path_is_absolute(path)) + return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path); + + if (mode != UNIT_CHECK) { + char *buf = NULL; + + buf = strjoin(b ? "-" : "", path, NULL); + if (!buf) + return -ENOMEM; + + fprintf(f, "EnvironmentFile=%s\n", buf); + + r = strv_consume(&l, buf); + if (r < 0) + return r; + } + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + r = fflush_and_check(f); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + if (strv_isempty(l)) { + c->environment_files = strv_free(c->environment_files); + unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n"); + } else { + r = strv_extend_strv(&c->environment_files, l, true); + if (r < 0) + return r; + + unit_write_drop_in_private(u, mode, name, joined); + } + } + + return 1; + + } else if (streq(name, "PassEnvironment")) { + + _cleanup_strv_free_ char **l = NULL; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + if (!strv_env_name_is_valid(l)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment block."); + + if (mode != UNIT_CHECK) { + if (strv_isempty(l)) { + c->pass_environment = strv_free(c->pass_environment); + unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=\n"); + } else { + _cleanup_free_ char *joined = NULL; + + r = strv_extend_strv(&c->pass_environment, l, true); + if (r < 0) + return r; + + joined = strv_join_quoted(c->pass_environment); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined); + } + } + + return 1; + + } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { + + _cleanup_strv_free_ char **l = NULL; + char ***dirs; + char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + STRV_FOREACH(p, l) { + int offset; + if (!utf8_is_valid(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name); + + offset = **p == '-'; + if (!path_is_absolute(*p + offset)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name); + } + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + + if (streq(name, "ReadWriteDirectories")) + dirs = &c->read_write_dirs; + else if (streq(name, "ReadOnlyDirectories")) + dirs = &c->read_only_dirs; + else if (streq(name, "InaccessibleDirectories")) + dirs = &c->inaccessible_dirs; + + if (strv_length(l) == 0) { + *dirs = strv_free(*dirs); + unit_write_drop_in_private_format(u, mode, name, "%s=\n", name); + } else { + r = strv_extend_strv(dirs, l, true); + + if (r < 0) + return -ENOMEM; + + joined = strv_join_quoted(*dirs); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined); + } + + } + + return 1; + + } else if (streq(name, "ProtectSystem")) { + const char *s; + ProtectSystem ps; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + r = parse_boolean(s); + if (r > 0) + ps = PROTECT_SYSTEM_YES; + else if (r == 0) + ps = PROTECT_SYSTEM_NO; + else { + ps = protect_system_from_string(s); + if (ps < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect system value"); + } + + if (mode != UNIT_CHECK) { + c->protect_system = ps; + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + } + + return 1; + + } else if (streq(name, "ProtectHome")) { + const char *s; + ProtectHome ph; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + r = parse_boolean(s); + if (r > 0) + ph = PROTECT_HOME_YES; + else if (r == 0) + ph = PROTECT_HOME_NO; + else { + ph = protect_home_from_string(s); + if (ph < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect home value"); + } + + if (mode != UNIT_CHECK) { + c->protect_home = ph; + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + } + + return 1; + + } else if (streq(name, "RuntimeDirectory")) { + _cleanup_strv_free_ char **l = NULL; + char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + STRV_FOREACH(p, l) { + if (!filename_is_valid(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p); + } + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + + if (strv_isempty(l)) { + c->runtime_directory = strv_free(c->runtime_directory); + unit_write_drop_in_private_format(u, mode, name, "%s=\n", name); + } else { + r = strv_extend_strv(&c->runtime_directory, l, true); + + if (r < 0) + return -ENOMEM; + + joined = strv_join_quoted(c->runtime_directory); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined); + } } return 1; diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index e4c2d5ddf6..c44517ea22 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "execute.h" #define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \ diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index cd6b909426..8c30d66250 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -19,12 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" #include "sd-bus.h" -#include "selinux-access.h" -#include "job.h" + +#include "alloc-util.h" #include "dbus-job.h" #include "dbus.h" +#include "job.h" +#include "log.h" +#include "selinux-access.h" +#include "string-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState); diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h index fb5f1b513e..0f2fbe2ee2 100644 --- a/src/core/dbus-job.h +++ b/src/core/dbus-job.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "job.h" extern const sd_bus_vtable bus_job_vtable[]; diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h index 7c15f3a90b..794c402048 100644 --- a/src/core/dbus-kill.h +++ b/src/core/dbus-kill.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" #include "kill.h" diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 3f4f60d6e2..d3bcc795ae 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -20,27 +20,33 @@ ***/ #include <errno.h> +#include <sys/prctl.h> #include <unistd.h> -#include "log.h" -#include "strv.h" +#include "alloc-util.h" +#include "architecture.h" #include "build.h" -#include "install.h" -#include "selinux-access.h" -#include "watchdog.h" +#include "bus-common-errors.h" #include "clock-util.h" -#include "path-util.h" -#include "virt.h" -#include "architecture.h" -#include "env-util.h" -#include "dbus.h" +#include "dbus-execute.h" #include "dbus-job.h" #include "dbus-manager.h" #include "dbus-unit.h" -#include "dbus-snapshot.h" -#include "dbus-execute.h" -#include "bus-common-errors.h" +#include "dbus.h" +#include "env-util.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "install.h" +#include "log.h" +#include "path-util.h" +#include "selinux-access.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "syslog-util.h" +#include "virt.h" +#include "watchdog.h" static int property_get_version( sd_bus *bus, @@ -346,6 +352,21 @@ static int property_set_runtime_watchdog( return watchdog_set_timeout(t); } +static int property_get_timer_slack_nsec( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + assert(bus); + assert(reply); + + return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK)); +} + static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *path = NULL; Manager *m = userdata; @@ -1079,66 +1100,8 @@ static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *er return sd_bus_reply_method_return(message, "s", dump); } -static int method_create_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_free_ char *path = NULL; - Manager *m = userdata; - const char *name; - int cleanup; - Snapshot *s = NULL; - int r; - - assert(message); - assert(m); - - r = mac_selinux_access_check(message, "start", error); - if (r < 0) - return r; - - r = sd_bus_message_read(message, "sb", &name, &cleanup); - if (r < 0) - return r; - - if (isempty(name)) - name = NULL; - - r = bus_verify_manage_units_async(m, message, error); - if (r < 0) - return r; - if (r == 0) - return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - - r = snapshot_create(m, name, cleanup, error, &s); - if (r < 0) - return r; - - path = unit_dbus_path(UNIT(s)); - if (!path) - return -ENOMEM; - - return sd_bus_reply_method_return(message, "o", path); -} - -static int method_remove_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) { - Manager *m = userdata; - const char *name; - Unit *u; - int r; - - assert(message); - assert(m); - - r = sd_bus_message_read(message, "s", &name); - if (r < 0) - return r; - - u = manager_get_unit(m, name); - if (!u) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name); - - if (u->type != UNIT_SNAPSHOT) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name); - - return bus_snapshot_method_remove(message, u, error); +static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed."); } static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) { @@ -1558,9 +1521,9 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; - state = unit_file_get_state(scope, NULL, name); - if (state < 0) - return state; + r = unit_file_get_state(scope, NULL, name, &state); + if (r < 0) + return r; return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state)); } @@ -1688,6 +1651,8 @@ static int method_enable_unit_files_generic( scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; r = call(scope, runtime, NULL, l, force, &changes, &n_changes); + if (r == -ESHUTDOWN) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked"); if (r < 0) return r; @@ -1922,6 +1887,8 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes); + if (r == -ESHUTDOWN) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked"); if (r < 0) return r; @@ -1977,6 +1944,23 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), @@ -2003,8 +1987,8 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0), diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index 24813c6d20..90a6d37073 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -19,13 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "mount.h" +#include "bus-util.h" +#include "dbus-cgroup.h" #include "dbus-execute.h" #include "dbus-kill.h" -#include "dbus-cgroup.h" +#include "mount.h" +#include "string-util.h" +#include "unit.h" #include "dbus-mount.h" -#include "bus-util.h" static int property_get_what( sd_bus *bus, diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h index f7004d252f..dd0bf51bb0 100644 --- a/src/core/dbus-mount.h +++ b/src/core/dbus-mount.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_mount_vtable[]; diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c index 683561999b..9e32b5fb06 100644 --- a/src/core/dbus-path.c +++ b/src/core/dbus-path.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" +#include "bus-util.h" #include "path.h" +#include "string-util.h" +#include "unit.h" #include "dbus-path.h" -#include "bus-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult); diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c index f8fb373bf0..16375b2311 100644 --- a/src/core/dbus-scope.c +++ b/src/core/dbus-scope.c @@ -19,17 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "selinux-access.h" -#include "unit.h" -#include "scope.h" -#include "dbus.h" -#include "bus-util.h" -#include "bus-internal.h" +#include "alloc-util.h" #include "bus-common-errors.h" -#include "dbus-unit.h" +#include "bus-internal.h" +#include "bus-util.h" #include "dbus-cgroup.h" #include "dbus-kill.h" #include "dbus-scope.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "scope.h" +#include "selinux-access.h" +#include "unit.h" static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) { Scope *s = userdata; diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index b636f8ba6a..24f611a593 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -19,16 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "async.h" -#include "strv.h" -#include "path-util.h" -#include "unit.h" -#include "service.h" +#include "bus-util.h" +#include "dbus-cgroup.h" #include "dbus-execute.h" #include "dbus-kill.h" -#include "dbus-cgroup.h" #include "dbus-service.h" -#include "bus-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "path-util.h" +#include "service.h" +#include "string-util.h" +#include "strv.h" +#include "unit.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult); @@ -59,7 +63,8 @@ const sd_bus_vtable bus_service_vtable[] = { SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", NULL, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0), SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -243,7 +248,9 @@ static int bus_service_set_transient_property( a); } - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(UNIT(s), mode, name, buf); } diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c deleted file mode 100644 index cfe44c9c15..0000000000 --- a/src/core/dbus-snapshot.c +++ /dev/null @@ -1,55 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include "selinux-access.h" -#include "unit.h" -#include "dbus.h" -#include "snapshot.h" -#include "dbus-snapshot.h" - -int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error) { - Snapshot *s = userdata; - int r; - - assert(message); - assert(s); - - r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error); - if (r < 0) - return r; - - r = bus_verify_manage_units_async(UNIT(s)->manager, message, error); - if (r < 0) - return r; - if (r == 0) - return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - - snapshot_remove(s); - - return sd_bus_reply_method_return(message, NULL); -} - -const sd_bus_vtable bus_snapshot_vtable[] = { - SD_BUS_VTABLE_START(0), - SD_BUS_PROPERTY("Cleanup", "b", bus_property_get_bool, offsetof(Snapshot, cleanup), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_VTABLE_END -}; diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 7444649f8b..be5ef261a6 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "socket.h" -#include "dbus-execute.h" +#include "alloc-util.h" +#include "bus-util.h" #include "dbus-cgroup.h" +#include "dbus-execute.h" #include "dbus-socket.h" -#include "bus-util.h" +#include "socket.h" +#include "string-util.h" +#include "unit.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index 0093371306..603ca95fd9 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -20,12 +20,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "swap.h" -#include "dbus-execute.h" +#include "bus-util.h" #include "dbus-cgroup.h" +#include "dbus-execute.h" +#include "string-util.h" +#include "swap.h" +#include "unit.h" #include "dbus-swap.h" -#include "bus-util.h" static int property_get_priority( sd_bus *bus, diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h index 4c4297bc9e..6be9c9f708 100644 --- a/src/core/dbus-target.h +++ b/src/core/dbus-target.h @@ -21,5 +21,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-bus.h" extern const sd_bus_vtable bus_target_vtable[]; diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index 8ea2cf84a4..a8a280d961 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "timer.h" -#include "dbus-timer.h" +#include "alloc-util.h" #include "bus-util.h" +#include "dbus-timer.h" #include "strv.h" +#include "timer.h" +#include "unit.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult); diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index cd88a87340..d9b7382c82 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -20,14 +20,19 @@ ***/ #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "cgroup-util.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "locale-util.h" #include "log.h" #include "selinux-access.h" -#include "cgroup-util.h" -#include "strv.h" -#include "bus-common-errors.h" #include "special.h" -#include "dbus.h" -#include "dbus-unit.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); @@ -113,6 +118,22 @@ static int property_get_dependencies( return sd_bus_message_close_container(reply); } +static int property_get_obsolete_dependencies( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + assert(bus); + assert(reply); + + /* For dependency types we don't support anymore always return an empty array */ + return sd_bus_message_append(reply, "as", 0); +} + static int property_get_description( sd_bus *bus, const char *path, @@ -616,16 +637,12 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0), SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST), @@ -639,6 +656,10 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -666,7 +687,6 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), @@ -679,7 +699,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("NetClass", "u", bus_property_get_unsigned, offsetof(Unit, cgroup_netclass_id), 0), + SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0), SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED), @@ -984,10 +1004,11 @@ int bus_unit_queue_job( if ((type == JOB_START && u->refuse_manual_start) || (type == JOB_STOP && u->refuse_manual_stop) || - ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) + ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || + (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); - r = manager_add_job(u->manager, type, u, mode, true, error, &j); + r = manager_add_job(u->manager, type, u, mode, error, &j); if (r < 0) return r; @@ -1103,9 +1124,15 @@ static int bus_unit_set_transient_property( UnitDependency d; const char *other; - d = unit_dependency_from_string(name); - if (d < 0) - return -EINVAL; + if (streq(name, "RequiresOverridable")) + d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */ + else if (streq(name, "RequisiteOverridable")) + d = UNIT_REQUISITE; /* same here */ + else { + d = unit_dependency_from_string(name); + if (d < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name); + } r = sd_bus_message_enter_container(message, 'a', "s"); if (r < 0) diff --git a/src/core/dbus.c b/src/core/dbus.c index 2d6a1ff836..7932130036 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -19,29 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/epoll.h> #include <errno.h> +#include <sys/epoll.h> #include <unistd.h> #include "sd-bus.h" -#include "log.h" -#include "strv.h" -#include "mkdir.h" -#include "missing.h" -#include "dbus-unit.h" -#include "dbus-job.h" -#include "dbus-manager.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-error.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "dbus-cgroup.h" #include "dbus-execute.h" +#include "dbus-job.h" #include "dbus-kill.h" -#include "dbus-cgroup.h" -#include "special.h" +#include "dbus-manager.h" +#include "dbus-unit.h" #include "dbus.h" -#include "bus-util.h" -#include "bus-error.h" -#include "bus-common-errors.h" -#include "strxcpyx.h" -#include "bus-internal.h" +#include "fd-util.h" +#include "log.h" +#include "missing.h" +#include "mkdir.h" #include "selinux-access.h" +#include "special.h" +#include "string-util.h" +#include "strv.h" +#include "strxcpyx.h" +#include "user-util.h" #define CONNECTIONS_MAX 4096 @@ -172,7 +177,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd goto failed; } - r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL); + r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL); if (r < 0) goto failed; @@ -777,9 +782,9 @@ static int bus_setup_api(Manager *m, sd_bus *bus) { return r; HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) { - r = unit_install_bus_match(bus, u, name); + r = unit_install_bus_match(u, bus, name); if (r < 0) - log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m"); + log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name); } r = sd_bus_add_match( diff --git a/src/core/device.c b/src/core/device.c index a819ab8d4e..bcd4d1146b 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -21,16 +21,21 @@ #include <errno.h> #include <sys/epoll.h> -#include <libudev.h> -#include "log.h" -#include "unit-name.h" +#include "libudev.h" + +#include "alloc-util.h" #include "dbus-device.h" +#include "device.h" +#include "log.h" +#include "parse-util.h" #include "path-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "swap.h" #include "udev-util.h" +#include "unit-name.h" #include "unit.h" -#include "swap.h" -#include "device.h" static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { [DEVICE_DEAD] = UNIT_INACTIVE, @@ -112,7 +117,6 @@ static void device_init(Unit *u) { u->job_timeout = u->manager->default_timeout_start_usec; u->ignore_on_isolate = true; - u->ignore_on_snapshot = true; } static void device_done(Unit *u) { @@ -597,7 +601,7 @@ static void device_shutdown(Manager *m) { m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs); } -static int device_enumerate(Manager *m) { +static void device_enumerate(Manager *m) { _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL; struct udev_list_entry *item = NULL, *first = NULL; int r; @@ -607,7 +611,7 @@ static int device_enumerate(Manager *m) { if (!m->udev_monitor) { m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"); if (!m->udev_monitor) { - r = -ENOMEM; + log_oom(); goto fail; } @@ -617,37 +621,49 @@ static int device_enumerate(Manager *m) { (void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024); r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd"); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to add udev tag match: %m"); goto fail; + } r = udev_monitor_enable_receiving(m->udev_monitor); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to enable udev event reception: %m"); goto fail; + } r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to watch udev file descriptor: %m"); goto fail; + } (void) sd_event_source_set_description(m->udev_event_source, "device"); } e = udev_enumerate_new(m->udev); if (!e) { - r = -ENOMEM; + log_oom(); goto fail; } r = udev_enumerate_add_match_tag(e, "systemd"); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to create udev tag enumeration: %m"); goto fail; + } r = udev_enumerate_add_match_is_initialized(e); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to install initialization match into enumeration: %m"); goto fail; + } r = udev_enumerate_scan_devices(e); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to enumerate devices: %m"); goto fail; + } first = udev_enumerate_get_list_entry(e); udev_list_entry_foreach(item, first) { @@ -670,13 +686,10 @@ static int device_enumerate(Manager *m) { device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false); } - return 0; + return; fail: - log_error_errno(r, "Failed to enumerate devices: %m"); - device_shutdown(m); - return r; } static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { diff --git a/src/core/execute.c b/src/core/execute.c index d6217840c0..07979bf8b3 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -53,46 +53,54 @@ #include "sd-messages.h" #include "af-list.h" +#include "alloc-util.h" +#ifdef HAVE_APPARMOR +#include "apparmor-util.h" +#endif #include "async.h" #include "barrier.h" #include "bus-endpoint.h" #include "cap-list.h" -#include "capability.h" +#include "capability-util.h" #include "def.h" #include "env-util.h" #include "errno-list.h" +#include "execute.h" #include "exit-status.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "glob-util.h" +#include "io-util.h" #include "ioprio.h" #include "log.h" #include "macro.h" #include "missing.h" #include "mkdir.h" #include "namespace.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "rlimit-util.h" #include "rm-rf.h" +#ifdef HAVE_SECCOMP +#include "seccomp-util.h" +#endif #include "securebits.h" #include "selinux-util.h" #include "signal-util.h" #include "smack-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" +#include "syslog-util.h" #include "terminal-util.h" #include "unit.h" +#include "user-util.h" #include "util.h" #include "utmp-wtmp.h" -#ifdef HAVE_APPARMOR -#include "apparmor-util.h" -#endif - -#ifdef HAVE_SECCOMP -#include "seccomp-util.h" -#endif - -#include "execute.h" - #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC) #define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC) @@ -1324,6 +1332,34 @@ static int build_environment( return 0; } +static int build_pass_environment(const ExecContext *c, char ***ret) { + _cleanup_strv_free_ char **pass_env = NULL; + size_t n_env = 0, n_bufsize = 0; + char **i; + + STRV_FOREACH(i, c->pass_environment) { + _cleanup_free_ char *x = NULL; + char *v; + + v = getenv(*i); + if (!v) + continue; + x = strjoin(*i, "=", v, NULL); + if (!x) + return -ENOMEM; + if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2)) + return -ENOMEM; + pass_env[n_env++] = x; + pass_env[n_env] = NULL; + x = NULL; + } + + *ret = pass_env; + pass_env = NULL; + + return 0; +} + static bool exec_needs_mount_namespace( const ExecContext *context, const ExecParameters *params, @@ -1404,7 +1440,7 @@ static int exec_child( char **files_env, int *exit_status) { - _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; + _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; const char *username = NULL, *home = NULL, *shell = NULL, *wd; uid_t uid = UID_INVALID; @@ -1920,9 +1956,16 @@ static int exec_child( return r; } - final_env = strv_env_merge(5, + r = build_pass_environment(context, &pass_env); + if (r < 0) { + *exit_status = EXIT_MEMORY; + return r; + } + + final_env = strv_env_merge(6, params->environment, our_env, + pass_env, context->environment, files_env, pam_env, @@ -2080,6 +2123,7 @@ void exec_context_done(ExecContext *c) { c->environment = strv_free(c->environment); c->environment_files = strv_free(c->environment_files); + c->pass_environment = strv_free(c->pass_environment); for (l = 0; l < ELEMENTSOF(c->rlimit); l++) c->rlimit[l] = mfree(c->rlimit[l]); @@ -2314,7 +2358,7 @@ static void strv_fprintf(FILE *f, char **l) { } void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { - char **e; + char **e, **d; unsigned i; assert(c); @@ -2350,6 +2394,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { STRV_FOREACH(e, c->environment_files) fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e); + STRV_FOREACH(e, c->pass_environment) + fprintf(f, "%sPassEnvironment: %s\n", prefix, *e); + + fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode); + + STRV_FOREACH(d, c->runtime_directory) + fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d); + if (c->nice_set) fprintf(f, "%sNice: %i\n", diff --git a/src/core/execute.h b/src/core/execute.h index f8995a4203..1faff160cb 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -99,6 +99,7 @@ struct ExecRuntime { struct ExecContext { char **environment; char **environment_files; + char **pass_environment; struct rlimit *rlimit[_RLIMIT_MAX]; char *working_directory, *root_directory; diff --git a/src/core/failure-action.c b/src/core/failure-action.c index 3412accf3e..f67fb05af0 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -23,10 +23,11 @@ #include <sys/reboot.h> #include <linux/reboot.h> -#include "bus-util.h" #include "bus-error.h" -#include "special.h" +#include "bus-util.h" #include "failure-action.h" +#include "special.h" +#include "string-table.h" #include "terminal-util.h" static void log_and_status(Manager *m, const char *message) { @@ -41,8 +42,6 @@ int failure_action( FailureAction action, const char *reboot_arg) { - int r; - assert(m); assert(action >= 0); assert(action < _FAILURE_ACTION_MAX); @@ -61,18 +60,13 @@ int failure_action( switch (action) { - case FAILURE_ACTION_REBOOT: { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - + case FAILURE_ACTION_REBOOT: log_and_status(m, "Rebooting as result of failure."); update_reboot_param_file(reboot_arg); - r = manager_add_job_by_name(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL); - if (r < 0) - log_error("Failed to reboot: %s.", bus_error_message(&error, r)); + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL); break; - } case FAILURE_ACTION_REBOOT_FORCE: log_and_status(m, "Forcibly rebooting as result of failure."); @@ -95,17 +89,10 @@ int failure_action( reboot(RB_AUTOBOOT); break; - case FAILURE_ACTION_POWEROFF: { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - + case FAILURE_ACTION_POWEROFF: log_and_status(m, "Powering off as result of failure."); - - r = manager_add_job_by_name(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, true, &error, NULL); - if (r < 0) - log_error("Failed to poweroff: %s.", bus_error_message(&error, r)); - + (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL); break; - } case FAILURE_ACTION_POWEROFF_FORCE: log_and_status(m, "Forcibly powering off as result of failure."); diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c index 932ddbf95a..3645f9c515 100644 --- a/src/core/hostname-setup.c +++ b/src/core/hostname-setup.c @@ -19,15 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> +#include <stdio.h> #include <stdlib.h> -#include "macro.h" -#include "util.h" -#include "log.h" +#include "alloc-util.h" #include "fileio.h" #include "hostname-util.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" +#include "util.h" #include "hostname-setup.h" int hostname_setup(void) { @@ -59,8 +61,9 @@ int hostname_setup(void) { hn = "localhost"; } - if (sethostname_idempotent(hn) < 0) - return log_warning_errno(errno, "Failed to set hostname to <%s>: %m", hn); + r = sethostname_idempotent(hn); + if (r < 0) + return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn); log_info("Set hostname to <%s>.", hn); return 0; diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c index 42a3e97459..9572fa17d9 100644 --- a/src/core/ima-setup.c +++ b/src/core/ima-setup.c @@ -24,9 +24,11 @@ #include <unistd.h> #include <errno.h> +#include "fd-util.h" +#include "fileio.h" #include "ima-setup.h" -#include "util.h" #include "log.h" +#include "util.h" #define IMA_SECFS_DIR "/sys/kernel/security/ima" #define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy" diff --git a/src/core/job.c b/src/core/job.c index 558d8d2d52..53e0947215 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -23,17 +23,24 @@ #include "sd-id128.h" #include "sd-messages.h" -#include "set.h" -#include "unit.h" -#include "macro.h" -#include "strv.h" -#include "log.h" -#include "dbus-job.h" -#include "special.h" + +#include "alloc-util.h" #include "async.h" -#include "virt.h" +#include "dbus-job.h" #include "dbus.h" +#include "escape.h" +#include "job.h" +#include "log.h" +#include "macro.h" +#include "parse-util.h" +#include "set.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" +#include "unit.h" +#include "virt.h" Job* job_new_raw(Unit *unit) { Job *j; @@ -168,7 +175,6 @@ static void job_merge_into_installed(Job *j, Job *other) { else assert(other->type == JOB_NOP); - j->override = j->override || other->override; j->irreversible = j->irreversible || other->irreversible; j->ignore_order = j->ignore_order || other->ignore_order; } @@ -300,12 +306,10 @@ void job_dump(Job *j, FILE*f, const char *prefix) { "%s-> Job %u:\n" "%s\tAction: %s -> %s\n" "%s\tState: %s\n" - "%s\tForced: %s\n" "%s\tIrreversible: %s\n", prefix, j->id, prefix, j->unit->id, job_type_to_string(j->type), prefix, job_state_to_string(j->state), - prefix, yes_no(j->override), prefix, yes_no(j->irreversible)); } @@ -834,8 +838,6 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) { job_fail_dependencies(u, UNIT_REQUIRED_BY); job_fail_dependencies(u, UNIT_REQUISITE_OF); job_fail_dependencies(u, UNIT_BOUND_BY); - job_fail_dependencies(u, UNIT_REQUIRED_BY_OVERRIDABLE); - job_fail_dependencies(u, UNIT_REQUISITE_OF_OVERRIDABLE); } else if (t == JOB_STOP) job_fail_dependencies(u, UNIT_CONFLICTED_BY); } @@ -960,7 +962,6 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) { fprintf(f, "job-id=%u\n", j->id); fprintf(f, "job-type=%s\n", job_type_to_string(j->type)); fprintf(f, "job-state=%s\n", job_state_to_string(j->state)); - fprintf(f, "job-override=%s\n", yes_no(j->override)); fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible)); fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal)); fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order)); @@ -1028,15 +1029,6 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) { else job_set_state(j, s); - } else if (streq(l, "job-override")) { - int b; - - b = parse_boolean(v); - if (b < 0) - log_debug("Failed to parse job override flag %s", v); - else - j->override = j->override || b; - } else if (streq(l, "job-irreversible")) { int b; diff --git a/src/core/job.h b/src/core/job.h index 1d1b10f1d3..60d8bd4f3e 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -23,6 +23,10 @@ #include <stdbool.h> +#include "sd-event.h" + +#include "list.h" + typedef struct Job Job; typedef struct JobDependency JobDependency; typedef enum JobType JobType; @@ -105,9 +109,7 @@ enum JobResult { _JOB_RESULT_INVALID = -1 }; -#include "sd-event.h" #include "unit.h" -#include "list.h" struct JobDependency { /* Encodes that the 'subject' job needs the 'object' job in @@ -160,7 +162,6 @@ struct Job { bool installed:1; bool in_run_queue:1; bool matters_to_anchor:1; - bool override:1; bool in_dbus_queue:1; bool sent_dbus_new_signal:1; bool ignore_order:1; diff --git a/src/core/kill.c b/src/core/kill.c index bddfa4460f..1466d5ce64 100644 --- a/src/core/kill.c +++ b/src/core/kill.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "signal-util.h" #include "kill.h" +#include "signal-util.h" +#include "string-table.h" +#include "util.h" void kill_context_init(KillContext *c) { assert(c); diff --git a/src/core/killall.c b/src/core/killall.c index ee5d388560..77f145b4d1 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -19,17 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/wait.h> -#include <signal.h> #include <errno.h> +#include <signal.h> +#include <sys/wait.h> #include <unistd.h> -#include "util.h" -#include "killall.h" -#include "set.h" +#include "alloc-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "killall.h" +#include "parse-util.h" #include "process-util.h" +#include "set.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" #define TIMEOUT_USEC (10 * USEC_PER_SEC) diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index 2068ffd69b..651f79a1fe 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -27,7 +27,7 @@ #endif #include "macro.h" -#include "capability.h" +#include "capability-util.h" #include "bus-util.h" #include "kmod-setup.h" diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 89e624b557..4c5376d601 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -33,6 +33,7 @@ $1.CPUAffinity, config_parse_exec_cpu_affinity, 0, $1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask) $1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment) $1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files) +$1.PassEnvironment, config_parse_pass_environ, 0, offsetof($1, exec_context.pass_environment) $1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input) $1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output) $1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error) @@ -58,22 +59,22 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0, $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') -$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) -$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) -$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) -$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) -$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) -$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) +$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) $1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) -$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) +$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) $1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) -$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) +$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) $1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) -$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) +$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) -$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) $1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) $1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs) $1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) @@ -133,9 +134,7 @@ Unit.Description, config_parse_unit_string_printf, 0, Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation) Unit.SourcePath, config_parse_path, 0, offsetof(Unit, source_path) Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0 -Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0 Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0 -Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0 Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0 Unit.BindsTo, config_parse_unit_deps, UNIT_BINDS_TO, 0 Unit.BindTo, config_parse_unit_deps, UNIT_BINDS_TO, 0 @@ -149,6 +148,8 @@ Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0 Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0 Unit.JoinsNamespaceOf, config_parse_unit_deps, UNIT_JOINS_NAMESPACE_OF, 0 +Unit.RequiresOverridable, config_parse_obsolete_unit_deps, UNIT_REQUIRES, 0 +Unit.RequisiteOverridable, config_parse_obsolete_unit_deps, UNIT_REQUISITE, 0 Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0 Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded) Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start) @@ -158,7 +159,7 @@ Unit.DefaultDependencies, config_parse_bool, 0, Unit.OnFailureJobMode, config_parse_job_mode, 0, offsetof(Unit, on_failure_job_mode) Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode) Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate) -Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Unit, ignore_on_snapshot) +Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0 Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout) Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action) Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index b1d4c6b57d..62cad0a0c0 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -32,6 +32,7 @@ #include <sys/resource.h> #include <sys/stat.h> +#include "alloc-util.h" #include "af-list.h" #include "bus-error.h" #include "bus-internal.h" @@ -42,21 +43,29 @@ #include "cpu-set-util.h" #include "env-util.h" #include "errno-list.h" +#include "escape.h" +#include "fd-util.h" +#include "fs-util.h" #include "ioprio.h" +#include "load-fragment.h" #include "log.h" #include "missing.h" +#include "parse-util.h" #include "path-util.h" +#include "process-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif #include "securebits.h" #include "signal-util.h" +#include "stat-util.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" #include "unit-printf.h" #include "unit.h" #include "utf8.h" -#include "load-fragment.h" +#include "web-util.h" int config_parse_warn_compat( const char *unit, @@ -89,35 +98,42 @@ int config_parse_warn_compat( return 0; } -int config_parse_unit_deps(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_deps( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { UnitDependency d = ltype; Unit *u = userdata; - const char *word, *state; - size_t l; + const char *p; assert(filename); assert(lvalue); assert(rvalue); - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *t = NULL, *k = NULL; + p = rvalue; + for(;;) { + _cleanup_free_ char *word = NULL, *k = NULL; int r; - t = strndup(word, l); - if (!t) + r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); + break; + } - r = unit_name_printf(u, t, &k); + r = unit_name_printf(u, word, &k); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); continue; @@ -127,12 +143,28 @@ int config_parse_unit_deps(const char *unit, if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring."); return 0; } +int config_parse_obsolete_unit_deps( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype)); + + return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata); +} + int config_parse_unit_string_printf( const char *unit, const char *filename, @@ -522,9 +554,7 @@ int config_parse_exec( assert(e); e += ltype; - rvalue += strspn(rvalue, WHITESPACE); - p = rvalue; if (isempty(rvalue)) { /* An empty assignment resets the list */ @@ -532,14 +562,15 @@ int config_parse_exec( return 0; } + p = rvalue; do { - int i; + _cleanup_free_ char *path = NULL, *firstword = NULL; + bool separate_argv0 = false, ignore = false; + _cleanup_free_ ExecCommand *nce = NULL; _cleanup_strv_free_ char **n = NULL; size_t nlen = 0, nbufsize = 0; - _cleanup_free_ ExecCommand *nce = NULL; - _cleanup_free_ char *path = NULL, *firstword = NULL; char *f; - bool separate_argv0 = false, ignore = false; + int i; semicolon = false; @@ -962,22 +993,22 @@ int config_parse_exec_secure_bits(const char *unit, return 0; } -int config_parse_bounding_set(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_bounding_set( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { uint64_t *capability_bounding_set_drop = data; - const char *word, *state; - size_t l; + uint64_t capability_bounding_set, sum = 0; bool invert = false; - uint64_t sum = 0; + const char *p; assert(filename); assert(lvalue); @@ -994,46 +1025,54 @@ int config_parse_bounding_set(const char *unit, * non-inverted everywhere to have a fully normalized * interface. */ - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *t = NULL; - int cap; + p = rvalue; + for (;;) { + _cleanup_free_ char *word = NULL; + int cap, r; - t = strndup(word, l); - if (!t) + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue); + break; + } - cap = capability_from_name(t); + cap = capability_from_name(word); if (cap < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word); continue; } - sum |= ((uint64_t) 1ULL) << (uint64_t) cap; + sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap; } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); - if (invert) - *capability_bounding_set_drop |= sum; + capability_bounding_set = invert ? ~sum : sum; + if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0) + *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); else - *capability_bounding_set_drop |= ~sum; + *capability_bounding_set_drop = ~capability_bounding_set; return 0; } -int config_parse_limit(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { struct rlimit **rl = data; - unsigned long long u; + rlim_t v; + int r; assert(filename); assert(lvalue); @@ -1043,15 +1082,172 @@ int config_parse_limit(const char *unit, rl += ltype; if (streq(rvalue, "infinity")) - u = (unsigned long long) RLIM_INFINITY; + v = RLIM_INFINITY; else { - int r; + uint64_t u; + + /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */ + assert_cc(sizeof(rlim_t) == sizeof(uint64_t)); + + r = safe_atou64(rvalue, &u); + if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) + r = -ERANGE; + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; + } + + v = (rlim_t) u; + } + + if (!*rl) { + *rl = new(struct rlimit, 1); + if (!*rl) + return log_oom(); + } + + (*rl)->rlim_cur = (*rl)->rlim_max = v; + return 0; +} + +int config_parse_bytes_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct rlimit **rl = data; + rlim_t bytes; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + rl += ltype; + + if (streq(rvalue, "infinity")) + bytes = RLIM_INFINITY; + else { + uint64_t u; + + r = parse_size(rvalue, 1024, &u); + if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) + r = -ERANGE; + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; + } + + bytes = (rlim_t) u; + } + + if (!*rl) { + *rl = new(struct rlimit, 1); + if (!*rl) + return log_oom(); + } + + (*rl)->rlim_cur = (*rl)->rlim_max = bytes; + return 0; +} + +int config_parse_sec_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct rlimit **rl = data; + rlim_t seconds; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + rl += ltype; + + if (streq(rvalue, "infinity")) + seconds = RLIM_INFINITY; + else { + usec_t t; + + r = parse_sec(rvalue, &t); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; + } + + if (t == USEC_INFINITY) + seconds = RLIM_INFINITY; + else + seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); + } + + if (!*rl) { + *rl = new(struct rlimit, 1); + if (!*rl) + return log_oom(); + } + + (*rl)->rlim_cur = (*rl)->rlim_max = seconds; + return 0; +} + + +int config_parse_usec_limit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct rlimit **rl = data; + rlim_t useconds; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + rl += ltype; + + if (streq(rvalue, "infinity")) + useconds = RLIM_INFINITY; + else { + usec_t t; - r = safe_atollu(rvalue, &u); + r = parse_time(rvalue, &t, 1); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); return 0; } + + if (t == USEC_INFINITY) + useconds = RLIM_INFINITY; + else + useconds = (rlim_t) t; } if (!*rl) { @@ -1060,7 +1256,7 @@ int config_parse_limit(const char *unit, return log_oom(); } - (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u; + (*rl)->rlim_cur = (*rl)->rlim_max = useconds; return 0; } @@ -1564,8 +1760,7 @@ int config_parse_service_sockets( void *userdata) { Service *s = data; - const char *word, *state; - size_t l; + const char *p; int r; assert(filename); @@ -1573,14 +1768,21 @@ int config_parse_service_sockets( assert(rvalue); assert(data); - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *t = NULL, *k = NULL; + p = rvalue; + for(;;) { + _cleanup_free_ char *word = NULL, *k = NULL; - t = strndup(word, l); - if (!t) + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue); + break; + } - r = unit_name_printf(UNIT(s), t, &k); + r = unit_name_printf(UNIT(s), word, &k); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); continue; @@ -1599,8 +1801,6 @@ int config_parse_service_sockets( if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -2015,6 +2215,70 @@ int config_parse_environ(const char *unit, return 0; } +int config_parse_pass_environ(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *whole_rvalue = rvalue; + char*** passenv = data; + _cleanup_strv_free_ char **n = NULL; + size_t nlen = 0, nbufsize = 0; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *passenv = strv_free(*passenv); + return 0; + } + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue); + break; + } + + if (!env_name_is_valid(word)) { + log_syntax(unit, LOG_ERR, filename, line, EINVAL, + "Invalid environment name for %s, ignoring: %s", lvalue, word); + continue; + } + + if (!GREEDY_REALLOC(n, nbufsize, nlen + 2)) + return log_oom(); + n[nlen++] = word; + n[nlen] = NULL; + word = NULL; + } + + if (n) { + r = strv_extend_strv(passenv, n, true); + if (r < 0) + return r; + } + + return 0; +} + int config_parse_ip_tos(const char *unit, const char *filename, unsigned line, @@ -2742,6 +3006,7 @@ int config_parse_tasks_max( return 0; } + c->tasks_max = u; return 0; } @@ -3192,8 +3457,8 @@ int config_parse_namespace_path_strv( void *userdata) { char*** sv = data; - const char *word, *state; - size_t l; + const char *prev; + const char *cur; int r; assert(filename); @@ -3207,35 +3472,43 @@ int config_parse_namespace_path_strv( return 0; } - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *n; + prev = cur = rvalue; + for (;;) { + _cleanup_free_ char *word = NULL; int offset; - n = strndup(word, l); - if (!n) + r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev); + return 0; + } - if (!utf8_is_valid(n)) { - log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); + if (!utf8_is_valid(word)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word); + prev = cur; continue; } - offset = n[0] == '-'; - if (!path_is_absolute(n + offset)) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue); + offset = word[0] == '-'; + if (!path_is_absolute(word + offset)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word); + prev = cur; continue; } - path_kill_slashes(n); + path_kill_slashes(word + offset); - r = strv_push(sv, n); + r = strv_push(sv, word); if (r < 0) return log_oom(); - n = NULL; + prev = cur; + word = NULL; } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 8661cbfedc..62300c10f9 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -31,6 +31,7 @@ void unit_dump_config_items(FILE *f); int config_parse_warn_compat(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_deps(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_obsolete_unit_deps(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_string_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_path_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); @@ -56,6 +57,9 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); @@ -81,6 +85,7 @@ int config_parse_syscall_filter(const char *unit, const char *filename, unsigned int config_parse_syscall_archs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_syscall_errno(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_pass_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index 6961c26674..bd632131b9 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -19,16 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> +#include <stdlib.h> -#include "locale-setup.h" -#include "util.h" -#include "virt.h" -#include "fileio.h" -#include "strv.h" #include "env-util.h" +#include "fileio.h" #include "locale-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" +#include "virt.h" +#include "locale-setup.h" int locale_setup(char ***environment) { char **add; diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c index 4503fc9dcc..4a57793104 100644 --- a/src/core/loopback-setup.c +++ b/src/core/loopback-setup.c @@ -23,9 +23,10 @@ #include <stdlib.h> #include "sd-netlink.h" -#include "netlink-util.h" -#include "missing.h" + #include "loopback-setup.h" +#include "missing.h" +#include "netlink-util.h" static int start_loopback(sd_netlink *rtnl) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 363ffaaf05..145ba2a28d 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -29,15 +29,24 @@ #include "sd-id128.h" +#include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "hexdecoct.h" +#include "io-util.h" #include "log.h" +#include "machine-id-setup.h" #include "macro.h" #include "mkdir.h" +#include "mount-util.h" #include "path-util.h" #include "process-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "umask-util.h" #include "util.h" #include "virt.h" -#include "machine-id-setup.h" static int shorten_uuid(char destination[34], const char source[36]) { unsigned i, j; diff --git a/src/core/main.c b/src/core/main.c index 87b3af92bc..33529c3e76 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -40,20 +40,23 @@ #include "sd-daemon.h" #include "sd-bus.h" +#include "alloc-util.h" #include "architecture.h" #include "build.h" #include "bus-error.h" #include "bus-util.h" -#include "capability.h" +#include "capability-util.h" #include "clock-util.h" #include "conf-parser.h" #include "cpu-set-util.h" #include "dbus-manager.h" #include "def.h" #include "env-util.h" +#include "fd-util.h" #include "fdset.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" #include "hostname-setup.h" #include "ima-setup.h" #include "killall.h" @@ -66,15 +69,21 @@ #include "missing.h" #include "mount-setup.h" #include "pager.h" +#include "parse-util.h" +#include "proc-cmdline.h" #include "process-util.h" +#include "rlimit-util.h" #include "selinux-setup.h" #include "selinux-util.h" #include "signal-util.h" #include "smack-setup.h" #include "special.h" +#include "stat-util.h" +#include "stdio-util.h" #include "strv.h" #include "switch-root.h" #include "terminal-util.h" +#include "user-util.h" #include "virt.h" #include "watchdog.h" @@ -292,20 +301,6 @@ static int parse_crash_chvt(const char *value) { static int parse_proc_cmdline_item(const char *key, const char *value) { - static const char * const rlmap[] = { - "emergency", SPECIAL_EMERGENCY_TARGET, - "-b", SPECIAL_EMERGENCY_TARGET, - "rescue", SPECIAL_RESCUE_TARGET, - "single", SPECIAL_RESCUE_TARGET, - "-s", SPECIAL_RESCUE_TARGET, - "s", SPECIAL_RESCUE_TARGET, - "S", SPECIAL_RESCUE_TARGET, - "1", SPECIAL_RESCUE_TARGET, - "2", SPECIAL_MULTI_USER_TARGET, - "3", SPECIAL_MULTI_USER_TARGET, - "4", SPECIAL_MULTI_USER_TARGET, - "5", SPECIAL_GRAPHICAL_TARGET, - }; int r; assert(key); @@ -406,12 +401,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { log_set_target(LOG_TARGET_CONSOLE); } else if (!in_initrd() && !value) { - unsigned i; + const char *target; /* SysV compatibility */ - for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(key, rlmap[i])) - return free_and_strdup(&arg_default_unit, rlmap[i+1]); + target = runlevel_to_target(key); + if (target) + return free_and_strdup(&arg_default_unit, target); } return 0; @@ -663,18 +658,18 @@ static int parse_config_file(void) { { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] }, - { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, - { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, - { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, - { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, - { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, + { "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, + { "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, + { "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, + { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, + { "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] }, - { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, + { "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] }, - { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, + { "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] }, { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] }, - { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, + { "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] }, { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, @@ -687,8 +682,14 @@ static int parse_config_file(void) { const char *fn, *conf_dirs_nulstr; - fn = arg_running_as == MANAGER_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf"; - conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf"); + fn = arg_running_as == MANAGER_SYSTEM ? + PKGSYSCONFDIR "/system.conf" : + PKGSYSCONFDIR "/user.conf"; + + conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? + CONF_PATHS_NULSTR("systemd/system.conf.d") : + CONF_PATHS_NULSTR("systemd/user.conf.d"); + config_parse_many(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL); @@ -1104,33 +1105,6 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { return 0; } -static void test_mtab(void) { - - static const char ok[] = - "/proc/self/mounts\0" - "/proc/mounts\0" - "../proc/self/mounts\0" - "../proc/mounts\0"; - - _cleanup_free_ char *p = NULL; - int r; - - /* Check that /etc/mtab is a symlink to the right place or - * non-existing. But certainly not a file, or a symlink to - * some weird place... */ - - r = readlink_malloc("/etc/mtab", &p); - if (r == -ENOENT) - return; - if (r >= 0 && nulstr_contains(ok, p)) - return; - - log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " - "This is not supported anymore. " - "Please replace /etc/mtab with a symlink to /proc/self/mounts."); - freeze_or_reboot(); -} - static void test_usr(void) { /* Check that /usr is not a separate fs */ @@ -1233,12 +1207,50 @@ static int status_welcome(void) { static int write_container_id(void) { const char *c; + int r; c = getenv("container"); if (isempty(c)) return 0; - return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE); + r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE); + if (r < 0) + return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m"); + + return 1; +} + +static int bump_unix_max_dgram_qlen(void) { + _cleanup_free_ char *qlen = NULL; + unsigned long v; + int r; + + /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel + * default of 16 is simply too low. We set the value really + * really early during boot, so that it is actually applied to + * all our sockets, including the $NOTIFY_SOCKET one. */ + + r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen); + if (r < 0) + return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m"); + + r = safe_atolu(qlen, &v); + if (r < 0) + return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m"); + + if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN) + return 0; + + qlen = mfree(qlen); + if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0) + return log_oom(); + + r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0); + if (r < 0) + return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to bump AF_UNIX datagram queue length, ignoring: %m"); + + return 1; } int main(int argc, char *argv[]) { @@ -1604,8 +1616,8 @@ int main(int argc, char *argv[]) { hostname_setup(); machine_id_setup(NULL); loopback_setup(); + bump_unix_max_dgram_qlen(); - test_mtab(); test_usr(); } @@ -1732,11 +1744,13 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); } - r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, false, &error, &default_unit_job); + r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job); if (r == -EPERM) { log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r)); - r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job); + sd_bus_error_free(&error); + + r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job); if (r < 0) { log_emergency("Failed to start default target: %s", bus_error_message(&error, r)); error_message = "Failed to start default target"; diff --git a/src/core/manager.c b/src/core/manager.c index 526d4d1cef..f695b8a66c 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -40,6 +40,7 @@ #include "sd-daemon.h" #include "sd-messages.h" +#include "alloc-util.h" #include "audit-fd.h" #include "boot-timestamps.h" #include "bus-common-errors.h" @@ -51,13 +52,20 @@ #include "dbus-unit.h" #include "dbus.h" #include "env-util.h" +#include "escape.h" #include "exit-status.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "hashmap.h" +#include "io-util.h" #include "locale-setup.h" #include "log.h" #include "macro.h" +#include "manager.h" #include "missing.h" #include "mkdir.h" +#include "parse-util.h" #include "path-lookup.h" #include "path-util.h" #include "process-util.h" @@ -65,15 +73,20 @@ #include "rm-rf.h" #include "signal-util.h" #include "special.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "time-util.h" #include "transaction.h" +#include "umask-util.h" #include "unit-name.h" #include "util.h" #include "virt.h" #include "watchdog.h" -#include "manager.h" + +#define NOTIFY_RCVBUF_SIZE (8*1024*1024) /* Initial delay and the interval for printing status messages about running jobs */ #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) @@ -473,7 +486,7 @@ static int manager_setup_signals(Manager *m) { * later than notify_fd processing, so that the notify * processing can still figure out to which process/service a * message belongs, before we reap the process. */ - r = sd_event_source_set_priority(m->signal_event_source, -5); + r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-5); if (r < 0) return r; @@ -678,6 +691,8 @@ static int manager_setup_notify(Manager *m) { if (fd < 0) return log_error_errno(errno, "Failed to allocate notification socket: %m"); + fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE); + if (m->running_as == MANAGER_SYSTEM) m->notify_socket = strdup("/run/systemd/notify"); else { @@ -719,7 +734,7 @@ static int manager_setup_notify(Manager *m) { /* Process signals a bit earlier than SIGCHLD, so that we can * still identify to which service an exit message belongs */ - r = sd_event_source_set_priority(m->notify_event_source, -7); + r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-7); if (r < 0) return log_error_errno(r, "Failed to set priority of notify event source: %m"); @@ -978,8 +993,7 @@ Manager* manager_free(Manager *m) { return NULL; } -int manager_enumerate(Manager *m) { - int r = 0; +void manager_enumerate(Manager *m) { UnitType c; assert(m); @@ -987,8 +1001,6 @@ int manager_enumerate(Manager *m) { /* Let's ask every type to load all units from disk/kernel * that it might know */ for (c = 0; c < _UNIT_TYPE_MAX; c++) { - int q; - if (!unit_type_supported(c)) { log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c)); continue; @@ -997,13 +1009,10 @@ int manager_enumerate(Manager *m) { if (!unit_vtable[c]->enumerate) continue; - q = unit_vtable[c]->enumerate(m); - if (q < 0) - r = q; + unit_vtable[c]->enumerate(m); } manager_dispatch_load_queue(m); - return r; } static void manager_coldplug(Manager *m) { @@ -1085,10 +1094,9 @@ fail: } -static int manager_distribute_fds(Manager *m, FDSet *fds) { - Unit *u; +static void manager_distribute_fds(Manager *m, FDSet *fds) { Iterator i; - int r; + Unit *u; assert(m); @@ -1097,14 +1105,11 @@ static int manager_distribute_fds(Manager *m, FDSet *fds) { if (fdset_size(fds) <= 0) break; - if (UNIT_VTABLE(u)->distribute_fds) { - r = UNIT_VTABLE(u)->distribute_fds(u, fds); - if (r < 0) - return r; - } - } + if (!UNIT_VTABLE(u)->distribute_fds) + continue; - return 0; + UNIT_VTABLE(u)->distribute_fds(u, fds); + } } int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { @@ -1137,7 +1142,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { /* First, enumerate what we can from all config files */ dual_timestamp_get(&m->units_load_start_timestamp); - r = manager_enumerate(m); + manager_enumerate(m); dual_timestamp_get(&m->units_load_finish_timestamp); /* Second, deserialize if there is something to deserialize */ @@ -1148,11 +1153,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { * useful to allow container managers to pass some file * descriptors to us pre-initialized. This enables * socket-based activation of entire containers. */ - if (fdset_size(fds) > 0) { - q = manager_distribute_fds(m, fds); - if (q < 0 && r == 0) - r = q; - } + manager_distribute_fds(m, fds); /* We might have deserialized the notify fd, but if we didn't * then let's create the bus now */ @@ -1182,7 +1183,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) { return r; } -int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) { +int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) { int r; Transaction *tr; @@ -1205,7 +1206,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove if (!tr) return -ENOMEM; - r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false, + r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false, mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS, mode == JOB_IGNORE_DEPENDENCIES, e); if (r < 0) @@ -1237,7 +1238,7 @@ tr_abort: return r; } -int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) { +int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) { Unit *unit; int r; @@ -1250,7 +1251,23 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode if (r < 0) return r; - return manager_add_job(m, type, unit, mode, override, e, _ret); + return manager_add_job(m, type, unit, mode, e, ret); +} + +int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(m); + assert(type < _JOB_TYPE_MAX); + assert(name); + assert(mode < _JOB_MODE_MAX); + + r = manager_add_job_by_name(m, type, name, mode, &error, ret); + if (r < 0) + return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r)); + + return r; } Job *manager_get_job(Manager *m, uint32_t id) { @@ -1477,7 +1494,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { return n; } -static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) { +static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) { _cleanup_strv_free_ char **tags = NULL; assert(m); @@ -1498,9 +1515,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char * } static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_fdset_free_ FDSet *fds = NULL; Manager *m = userdata; + + char buf[NOTIFY_BUFFER_MAX+1]; + struct iovec iovec = { + .iov_base = buf, + .iov_len = sizeof(buf)-1, + }; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; + } control = {}; + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + + struct cmsghdr *cmsg; + struct ucred *ucred = NULL; + bool found = false; + Unit *u1, *u2, *u3; + int r, *fd_array = NULL; + unsigned n_fds = 0; ssize_t n; - int r; assert(m); assert(m->notify_fd == fd); @@ -1510,106 +1551,80 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } - for (;;) { - _cleanup_fdset_free_ FDSet *fds = NULL; - char buf[NOTIFY_BUFFER_MAX+1]; - struct iovec iovec = { - .iov_base = buf, - .iov_len = sizeof(buf)-1, - }; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + - CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; - } control = {}; - struct msghdr msghdr = { - .msg_iov = &iovec, - .msg_iovlen = 1, - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - struct ucred *ucred = NULL; - bool found = false; - Unit *u1, *u2, *u3; - int *fd_array = NULL; - unsigned n_fds = 0; - - n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (errno == EAGAIN || errno == EINTR) - break; + n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; - return -errno; - } + return -errno; + } - CMSG_FOREACH(cmsg, &msghdr) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - fd_array = (int*) CMSG_DATA(cmsg); - n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + fd_array = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_CREDENTIALS && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { - ucred = (struct ucred*) CMSG_DATA(cmsg); - } + ucred = (struct ucred*) CMSG_DATA(cmsg); } + } - if (n_fds > 0) { - assert(fd_array); + if (n_fds > 0) { + assert(fd_array); - r = fdset_new_array(&fds, fd_array, n_fds); - if (r < 0) { - close_many(fd_array, n_fds); - return log_oom(); - } + r = fdset_new_array(&fds, fd_array, n_fds); + if (r < 0) { + close_many(fd_array, n_fds); + return log_oom(); } + } - if (!ucred || ucred->pid <= 0) { - log_warning("Received notify message without valid credentials. Ignoring."); - continue; - } + if (!ucred || ucred->pid <= 0) { + log_warning("Received notify message without valid credentials. Ignoring."); + return 0; + } - if ((size_t) n >= sizeof(buf)) { - log_warning("Received notify message exceeded maximum size. Ignoring."); - continue; - } + if ((size_t) n >= sizeof(buf)) { + log_warning("Received notify message exceeded maximum size. Ignoring."); + return 0; + } - buf[n] = 0; + buf[n] = 0; - /* Notify every unit that might be interested, but try - * to avoid notifying the same one multiple times. */ - u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid); - if (u1) { - manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); - found = true; - } + /* Notify every unit that might be interested, but try + * to avoid notifying the same one multiple times. */ + u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid); + if (u1) { + manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); + found = true; + } - u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid)); - if (u2 && u2 != u1) { - manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); - found = true; - } + u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid)); + if (u2 && u2 != u1) { + manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); + found = true; + } - u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid)); - if (u3 && u3 != u2 && u3 != u1) { - manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); - found = true; - } + u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid)); + if (u3 && u3 != u2 && u3 != u1) { + manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); + found = true; + } - if (!found) - log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); + if (!found) + log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); - if (fdset_size(fds) > 0) - log_warning("Got auxiliary fds with notification message, closing all."); - } + if (fdset_size(fds) > 0) + log_warning("Got auxiliary fds with notification message, closing all."); return 0; } -static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { +static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) { assert(m); assert(u); assert(si); @@ -1688,7 +1703,7 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) { log_debug("Activating special unit %s", name); - r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL); + r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL); if (r < 0) log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r)); @@ -1991,8 +2006,7 @@ int manager_loop(Manager *m) { m->exit_code = MANAGER_OK; /* Release the path cache */ - set_free_free(m->unit_path_cache); - m->unit_path_cache = NULL; + m->unit_path_cache = set_free_free(m->unit_path_cache); manager_check_finished(m); @@ -2012,7 +2026,6 @@ int manager_loop(Manager *m) { /* Yay, something is going seriously wrong, pause a little */ log_warning("Looping too fast. Throttling execution a little."); sleep(1); - continue; } if (manager_dispatch_load_queue(m) > 0) @@ -2102,6 +2115,9 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { const char *msg; int audit_fd, r; + if (m->running_as != MANAGER_SYSTEM) + return; + audit_fd = get_audit_fd(); if (audit_fd < 0) return; @@ -2111,9 +2127,6 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { if (m->n_reloading > 0) return; - if (m->running_as != MANAGER_SYSTEM) - return; - if (u->type != UNIT_SERVICE) return; @@ -2543,9 +2556,7 @@ int manager_reload(Manager *m) { manager_build_unit_path_cache(m); /* First, enumerate what we can from all config files */ - q = manager_enumerate(m); - if (q < 0 && r >= 0) - r = q; + manager_enumerate(m); /* Second, deserialize our stored data */ q = manager_deserialize(m, f, fds); @@ -2762,8 +2773,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name) return log_oom(); if (!mkdtemp(p)) { - log_error_errno(errno, "Failed to create generator directory %s: %m", - p); + log_error_errno(errno, "Failed to create generator directory %s: %m", p); free(p); return -errno; } @@ -2952,9 +2962,9 @@ void manager_set_show_status(Manager *m, ShowStatus mode) { m->show_status = mode; if (mode > 0) - touch("/run/systemd/show-status"); + (void) touch("/run/systemd/show-status"); else - unlink("/run/systemd/show-status"); + (void) unlink("/run/systemd/show-status"); } static bool manager_get_show_status(Manager *m, StatusType type) { @@ -3013,30 +3023,6 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons va_end(ap); } -int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) { - _cleanup_free_ char *p = NULL; - Unit *found; - int r; - - assert(m); - assert(path); - assert(suffix); - assert(_found); - - r = unit_name_from_path(path, suffix, &p); - if (r < 0) - return r; - - found = manager_get_unit(m, p); - if (!found) { - *_found = NULL; - return 0; - } - - *_found = found; - return 1; -} - Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) { char p[strlen(path)+1]; diff --git a/src/core/manager.h b/src/core/manager.h index fad10aaacf..bc3f02f872 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -141,8 +141,6 @@ struct Manager { sd_event_source *jobs_in_progress_event_source; - unsigned n_snapshots; - LookupPaths lookup_paths; Set *unit_path_cache; @@ -316,22 +314,21 @@ struct Manager { int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m); Manager* manager_free(Manager *m); -int manager_enumerate(Manager *m); +void manager_enumerate(Manager *m); int manager_startup(Manager *m, FILE *serialization, FDSet *fds); Job *manager_get_job(Manager *m, uint32_t id); Unit *manager_get_unit(Manager *m, const char *name); -int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found); - int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j); int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u); -int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, sd_bus_error *e, Job **_ret); -int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, sd_bus_error *e, Job **_ret); +int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret); +int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret); +int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret); void manager_dump_units(Manager *s, FILE *f, const char *prefix); void manager_dump_jobs(Manager *s, FILE *f, const char *prefix); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 9b16eaa0e2..b2596d1cd1 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -25,22 +25,25 @@ #include <unistd.h> #include <ftw.h> -#include "mount-setup.h" -#include "dev-setup.h" +#include "alloc-util.h" #include "bus-util.h" +#include "cgroup-util.h" +#include "dev-setup.h" +#include "efivars.h" +#include "label.h" #include "log.h" #include "macro.h" -#include "util.h" -#include "label.h" -#include "set.h" -#include "strv.h" +#include "missing.h" #include "mkdir.h" +#include "mount-setup.h" +#include "mount-util.h" #include "path-util.h" -#include "missing.h" -#include "virt.h" -#include "efivars.h" +#include "set.h" #include "smack-util.h" -#include "cgroup-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" +#include "virt.h" typedef enum MountMode { MNT_NONE = 0, diff --git a/src/core/mount.c b/src/core/mount.c index 8611129453..9b44357e90 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -20,25 +20,33 @@ ***/ #include <errno.h> +#include <signal.h> #include <stdio.h> #include <sys/epoll.h> -#include <signal.h> -#include "manager.h" -#include "unit.h" -#include "mount.h" -#include "log.h" #include "sd-messages.h" -#include "strv.h" -#include "mkdir.h" -#include "path-util.h" -#include "mount-setup.h" -#include "unit-name.h" + +#include "alloc-util.h" #include "dbus-mount.h" -#include "special.h" +#include "escape.h" #include "exit-status.h" -#include "fstab-util.h" #include "formats-util.h" +#include "fstab-util.h" +#include "log.h" +#include "manager.h" +#include "mkdir.h" +#include "mount-setup.h" +#include "mount-util.h" +#include "mount.h" +#include "parse-util.h" +#include "path-util.h" +#include "process-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit.h" #define RETRY_UMOUNT_MAX 32 @@ -246,9 +254,10 @@ static int mount_add_mount_links(Mount *m) { if (!path_equal(m->where, "/")) { /* Adds in links to other mount points that might lie further * up in the hierarchy */ - r = path_get_parent(m->where, &parent); - if (r < 0) - return r; + + parent = dirname_malloc(m->where); + if (!parent) + return -ENOMEM; r = unit_require_mounts_for(UNIT(m), parent); if (r < 0) @@ -376,12 +385,15 @@ static bool should_umount(Mount *m) { } static int mount_add_default_dependencies(Mount *m) { - const char *after, *after2, *online; MountParameters *p; + const char *after; int r; assert(m); + if (!UNIT(m)->default_dependencies) + return 0; + if (UNIT(m)->manager->running_as != MANAGER_SYSTEM) return 0; @@ -402,30 +414,34 @@ static int mount_add_default_dependencies(Mount *m) { return 0; if (mount_is_network(p)) { - after = SPECIAL_REMOTE_FS_PRE_TARGET; - after2 = SPECIAL_NETWORK_TARGET; - online = SPECIAL_NETWORK_ONLINE_TARGET; - } else { - after = SPECIAL_LOCAL_FS_PRE_TARGET; - after2 = NULL; - online = NULL; - } - - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true); - if (r < 0) - return r; + /* We order ourselves after network.target. This is + * primarily useful at shutdown: services that take + * down the network should order themselves before + * network.target, so that they are shut down only + * after this mount unit is stopped. */ - if (after2) { - r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after2, NULL, true); + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true); if (r < 0) return r; - } - if (online) { - r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, online, NULL, true); + /* We pull in network-online.target, and order + * ourselves after it. This is useful at start-up to + * actively pull in tools that want to be started + * before we start mounting network file systems, and + * whose purpose it is to delay this until the network + * is "up". */ + + r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true); if (r < 0) return r; - } + + after = SPECIAL_REMOTE_FS_PRE_TARGET; + } else + after = SPECIAL_LOCAL_FS_PRE_TARGET; + + r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true); + if (r < 0) + return r; if (should_umount(m)) { r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); @@ -522,11 +538,9 @@ static int mount_add_extras(Mount *m) { if (r < 0) return r; - if (u->default_dependencies) { - r = mount_add_default_dependencies(m); - if (r < 0) - return r; - } + r = mount_add_default_dependencies(m); + if (r < 0) + return r; return 0; } @@ -621,19 +635,19 @@ static int mount_coldplug(Unit *u) { if (new_state == m->state) return 0; - if (new_state == MOUNT_MOUNTING || - new_state == MOUNT_MOUNTING_DONE || - new_state == MOUNT_REMOUNTING || - new_state == MOUNT_UNMOUNTING || - new_state == MOUNT_MOUNTING_SIGTERM || - new_state == MOUNT_MOUNTING_SIGKILL || - new_state == MOUNT_UNMOUNTING_SIGTERM || - new_state == MOUNT_UNMOUNTING_SIGKILL || - new_state == MOUNT_REMOUNTING_SIGTERM || - new_state == MOUNT_REMOUNTING_SIGKILL) { - - if (m->control_pid <= 0) - return -EBADMSG; + if (m->control_pid > 0 && + pid_is_unwaited(m->control_pid) && + IN_SET(new_state, + MOUNT_MOUNTING, + MOUNT_MOUNTING_DONE, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, + MOUNT_MOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL)) { r = unit_watch_pid(UNIT(m), m->control_pid); if (r < 0) @@ -852,6 +866,11 @@ fail: mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES); } +static int mount_get_opts(Mount *m, char **ret) { + return fstab_filter_options(m->parameters_fragment.options, + "nofail\0" "noauto\0" "auto\0", NULL, NULL, ret); +} + static void mount_enter_mounting(Mount *m) { int r; MountParameters *p; @@ -877,8 +896,7 @@ static void mount_enter_mounting(Mount *m) { if (m->from_fragment) { _cleanup_free_ char *opts = NULL; - r = fstab_filter_options(m->parameters_fragment.options, - "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts); + r = mount_get_opts(m, &opts); if (r < 0) goto fail; @@ -1559,7 +1577,7 @@ static int mount_get_timeout(Unit *u, uint64_t *timeout) { return 1; } -static int mount_enumerate(Manager *m) { +static void mount_enumerate(Manager *m) { int r; assert(m); @@ -1571,29 +1589,40 @@ static int mount_enumerate(Manager *m) { m->mount_monitor = mnt_new_monitor(); if (!m->mount_monitor) { - r = -ENOMEM; + log_oom(); goto fail; } r = mnt_monitor_enable_kernel(m->mount_monitor, 1); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to enable watching of kernel mount events: %m"); goto fail; + } + r = mnt_monitor_enable_userspace(m->mount_monitor, 1, NULL); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to enable watching of userspace mount events: %m"); goto fail; + } /* mnt_unref_monitor() will close the fd */ fd = r = mnt_monitor_get_fd(m->mount_monitor); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to acquire watch file descriptor: %m"); goto fail; + } r = sd_event_add_io(m->event, &m->mount_event_source, fd, EPOLLIN, mount_dispatch_io, m); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to watch mount file descriptor: %m"); goto fail; + } r = sd_event_source_set_priority(m->mount_event_source, -10); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to adjust mount watch priority: %m"); goto fail; + } (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch"); } @@ -1602,11 +1631,10 @@ static int mount_enumerate(Manager *m) { if (r < 0) goto fail; - return 0; + return; fail: mount_shutdown(m); - return r; } static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) { diff --git a/src/core/namespace.c b/src/core/namespace.c index 2b8b707df5..81ba09ea5d 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -20,23 +20,31 @@ ***/ #include <errno.h> -#include <sys/mount.h> -#include <string.h> +#include <sched.h> #include <stdio.h> -#include <unistd.h> +#include <string.h> +#include <sys/mount.h> #include <sys/stat.h> -#include <sched.h> +#include <unistd.h> #include <linux/fs.h> -#include "strv.h" -#include "util.h" -#include "path-util.h" -#include "missing.h" -#include "loopback-setup.h" +#include "alloc-util.h" #include "dev-setup.h" -#include "selinux-util.h" -#include "namespace.h" +#include "fd-util.h" +#include "loopback-setup.h" +#include "missing.h" #include "mkdir.h" +#include "mount-util.h" +#include "namespace.h" +#include "path-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "umask-util.h" +#include "user-util.h" +#include "util.h" typedef enum MountMode { /* This is ordered by priority! */ diff --git a/src/core/path.c b/src/core/path.c index 081ac2040d..02fb134bb9 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -19,20 +19,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/inotify.h> -#include <sys/epoll.h> #include <errno.h> +#include <sys/epoll.h> +#include <sys/inotify.h> #include <unistd.h> -#include "unit.h" -#include "unit-name.h" -#include "path.h" -#include "mkdir.h" +#include "bus-error.h" +#include "bus-util.h" #include "dbus-path.h" -#include "special.h" +#include "fd-util.h" +#include "fs-util.h" +#include "glob-util.h" #include "macro.h" -#include "bus-util.h" -#include "bus-error.h" +#include "mkdir.h" +#include "path.h" +#include "special.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "unit-name.h" +#include "unit.h" static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { [PATH_DEAD] = UNIT_INACTIVE, @@ -309,20 +315,20 @@ static int path_add_default_dependencies(Path *p) { assert(p); - r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, - SPECIAL_PATHS_TARGET, NULL, true); + if (!UNIT(p)->default_dependencies) + return 0; + + r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true); if (r < 0) return r; if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) { - r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, - SPECIAL_SYSINIT_TARGET, NULL, true); + r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); if (r < 0) return r; } - return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, - SPECIAL_SHUTDOWN_TARGET, NULL, true); + return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); } static int path_load(Unit *u) { @@ -354,11 +360,9 @@ static int path_load(Unit *u) { if (r < 0) return r; - if (UNIT(p)->default_dependencies) { - r = path_add_default_dependencies(p); - if (r < 0) - return r; - } + r = path_add_default_dependencies(p); + if (r < 0) + return r; } return path_verify(p); @@ -470,8 +474,7 @@ static void path_enter_running(Path *p) { if (unit_stop_pending(UNIT(p))) return; - r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)), - JOB_REPLACE, true, &error, NULL); + r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)), JOB_REPLACE, &error, NULL); if (r < 0) goto fail; diff --git a/src/core/scope.c b/src/core/scope.c index ea7d846578..5f6527c155 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -22,14 +22,17 @@ #include <errno.h> #include <unistd.h> +#include "alloc-util.h" +#include "dbus-scope.h" +#include "load-dropin.h" #include "log.h" -#include "strv.h" +#include "scope.h" #include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" #include "unit-name.h" #include "unit.h" -#include "scope.h" -#include "dbus-scope.h" -#include "load-dropin.h" static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = { [SCOPE_DEAD] = UNIT_INACTIVE, @@ -51,7 +54,6 @@ static void scope_init(Unit *u) { s->timeout_stop_usec = u->manager->default_timeout_stop_usec; UNIT(s)->ignore_on_isolate = true; - UNIT(s)->ignore_on_snapshot = true; } static void scope_done(Unit *u) { @@ -120,6 +122,9 @@ static int scope_add_default_dependencies(Scope *s) { assert(s); + if (!UNIT(s)->default_dependencies) + return 0; + /* Make sure scopes are unloaded on shutdown */ r = unit_add_two_dependencies_by_name( UNIT(s), @@ -171,11 +176,9 @@ static int scope_load(Unit *u) { if (r < 0) return r; - if (u->default_dependencies) { - r = scope_add_default_dependencies(s); - if (r < 0) - return r; - } + r = scope_add_default_dependencies(s); + if (r < 0) + return r; return scope_verify(s); } @@ -507,7 +510,7 @@ _pure_ static const char *scope_sub_state_to_string(Unit *u) { return scope_state_to_string(SCOPE(u)->state); } -static int scope_enumerate(Manager *m) { +static void scope_enumerate(Manager *m) { Unit *u; int r; @@ -521,13 +524,16 @@ static int scope_enumerate(Manager *m) { u = manager_get_unit(m, SPECIAL_INIT_SCOPE); if (!u) { u = unit_new(m, sizeof(Scope)); - if (!u) - return log_oom(); + if (!u) { + log_oom(); + return; + } r = unit_add_name(u, SPECIAL_INIT_SCOPE); if (r < 0) { unit_free(u); - return log_error_errno(r, "Failed to add init.scope name"); + log_error_errno(r, "Failed to add init.scope name"); + return; } } @@ -548,8 +554,6 @@ static int scope_enumerate(Manager *m) { unit_add_to_load_queue(u); unit_add_to_dbus_queue(u); - - return 0; } static const char* const scope_result_table[_SCOPE_RESULT_MAX] = { diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index 40ca0c6166..4bcdd27389 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -32,13 +32,16 @@ #endif #include "sd-bus.h" + +#include "alloc-util.h" +#include "audit-fd.h" #include "bus-util.h" -#include "util.h" #include "log.h" +#include "path-util.h" #include "selinux-util.h" -#include "audit-fd.h" +#include "stdio-util.h" #include "strv.h" -#include "path-util.h" +#include "util.h" static bool initialized = false; @@ -178,17 +181,6 @@ static int mac_selinux_access_init(sd_bus_error *error) { } #endif -void mac_selinux_access_free(void) { - -#ifdef HAVE_SELINUX - if (!initialized) - return; - - avc_destroy(); - initialized = false; -#endif -} - /* This function communicates with the kernel to check whether or not it should allow the access. diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index e6b4dd7fee..30725521cb 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -25,8 +25,6 @@ #include "bus-util.h" #include "manager.h" -void mac_selinux_access_free(void); - int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error); #ifdef HAVE_SELINUX diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index ff1ea23528..d9b00fb95c 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -19,19 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <stdio.h> #include <errno.h> +#include <stdio.h> +#include <unistd.h> #ifdef HAVE_SELINUX #include <selinux/selinux.h> #endif -#include "selinux-setup.h" -#include "selinux-util.h" +#include "log.h" #include "macro.h" +#include "selinux-util.h" +#include "string-util.h" #include "util.h" -#include "log.h" +#include "selinux-setup.h" #ifdef HAVE_SELINUX _printf_(2,3) diff --git a/src/core/service.c b/src/core/service.c index 1e4f707bf4..c27b70fa3c 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -23,31 +23,38 @@ #include <signal.h> #include <unistd.h> +#include "alloc-util.h" #include "async.h" -#include "manager.h" -#include "unit.h" -#include "service.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "log.h" -#include "strv.h" -#include "unit-name.h" -#include "unit-printf.h" +#include "bus-error.h" +#include "bus-kernel.h" +#include "bus-util.h" #include "dbus-service.h" -#include "special.h" -#include "exit-status.h" #include "def.h" -#include "path-util.h" -#include "util.h" -#include "utf8.h" #include "env-util.h" +#include "escape.h" +#include "exit-status.h" +#include "fd-util.h" #include "fileio.h" -#include "bus-error.h" -#include "bus-util.h" -#include "bus-kernel.h" #include "formats-util.h" +#include "fs-util.h" +#include "load-dropin.h" +#include "load-fragment.h" +#include "log.h" +#include "manager.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" +#include "service.h" #include "signal-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" +#include "utf8.h" +#include "util.h" static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { [SERVICE_DEAD] = UNIT_INACTIVE, @@ -168,7 +175,7 @@ static int service_set_main_pid(Service *s, pid_t pid) { s->main_pid = pid; s->main_pid_known = true; - if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) { + if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid()) { log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid); s->main_pid_alien = true; } else @@ -413,7 +420,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) { } if (fdset_size(fds) > 0) - log_unit_warning(UNIT(s), "Tried to store more fds than FDStoreMax=%u allows, closing remaining.", s->n_fd_store_max); + log_unit_warning(UNIT(s), "Tried to store more fds than FileDescriptorStoreMax=%u allows, closing remaining.", s->n_fd_store_max); return 0; } @@ -508,15 +515,38 @@ static int service_add_default_dependencies(Service *s) { assert(s); + if (!UNIT(s)->default_dependencies) + return 0; + /* Add a number of automatic dependencies useful for the * majority of services. */ - /* First, pull in base system */ - r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true); + if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) { + /* First, pull in the really early boot stuff, and + * require it, so that we fail if we can't acquire + * it. */ + + r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true); + if (r < 0) + return r; + } else { + + /* In the --user instance there's no sysinit.target, + * in that case require basic.target instead. */ + + r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true); + if (r < 0) + return r; + } + + /* Second, if the rest of the base system is in the same + * transaction, order us after it, but do not pull it in or + * even require it. */ + r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true); if (r < 0) return r; - /* Second, activate normal shutdown */ + /* Third, add us in for normal shutdown. */ return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); } @@ -538,6 +568,43 @@ static void service_fix_output(Service *s) { s->exec_context.std_output = UNIT(s)->manager->default_std_output; } +static int service_setup_bus_name(Service *s) { + int r; + + assert(s); + + if (!s->bus_name) + return 0; + + if (is_kdbus_available()) { + const char *n; + + n = strjoina(s->bus_name, ".busname"); + r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to add dependency to .busname unit: %m"); + + } else { + /* If kdbus is not available, we know the dbus socket is required, hence pull it in, and require it */ + r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); + } + + /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */ + r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m"); + + r = unit_watch_bus_name(UNIT(s), s->bus_name); + if (r == -EEXIST) + return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name); + + return 0; +} + static int service_add_extras(Service *s) { int r; @@ -577,26 +644,13 @@ static int service_add_extras(Service *s) { if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE) s->notify_access = NOTIFY_MAIN; - if (s->bus_name) { - const char *n; - - n = strjoina(s->bus_name, ".busname"); - r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true); - if (r < 0) - return r; - - r = unit_watch_bus_name(UNIT(s), s->bus_name); - if (r == -EEXIST) - return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name); - if (r < 0) - return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name); - } + r = service_add_default_dependencies(s); + if (r < 0) + return r; - if (UNIT(s)->default_dependencies) { - r = service_add_default_dependencies(s); - if (r < 0) - return r; - } + r = service_setup_bus_name(s); + if (r < 0) + return r; return 0; } @@ -905,66 +959,67 @@ static int service_coldplug(Unit *u) { assert(s); assert(s->state == SERVICE_DEAD); - if (s->deserialized_state != s->state) { - - if (IN_SET(s->deserialized_state, - SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, - SERVICE_RELOAD, - SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - - usec_t k; - - k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec; + if (s->deserialized_state == s->state) + return 0; - /* For the start/stop timeouts 0 means off */ - if (k > 0) { - r = service_arm_timer(s, k); - if (r < 0) - return r; - } - } + if (IN_SET(s->deserialized_state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - if (s->deserialized_state == SERVICE_AUTO_RESTART) { + usec_t k; - /* The restart timeouts 0 means immediately */ - r = service_arm_timer(s, s->restart_usec); - if (r < 0) - return r; - } + k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec; - if (pid_is_unwaited(s->main_pid) && - ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) || - IN_SET(s->deserialized_state, - SERVICE_START, SERVICE_START_POST, - SERVICE_RUNNING, SERVICE_RELOAD, - SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { - r = unit_watch_pid(UNIT(s), s->main_pid); + /* For the start/stop timeouts 0 means off */ + if (k > 0) { + r = service_arm_timer(s, k); if (r < 0) return r; } + } - if (pid_is_unwaited(s->control_pid) && - IN_SET(s->deserialized_state, - SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, - SERVICE_RELOAD, - SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - r = unit_watch_pid(UNIT(s), s->control_pid); - if (r < 0) - return r; - } + if (s->deserialized_state == SERVICE_AUTO_RESTART) { - if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) - unit_watch_all_pids(UNIT(s)); + /* The restart timeouts 0 means immediately */ + r = service_arm_timer(s, s->restart_usec); + if (r < 0) + return r; + } - if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) - service_start_watchdog(s); + if (s->main_pid > 0 && + pid_is_unwaited(s->main_pid) && + ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) || + IN_SET(s->deserialized_state, + SERVICE_START, SERVICE_START_POST, + SERVICE_RUNNING, SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { + r = unit_watch_pid(UNIT(s), s->main_pid); + if (r < 0) + return r; + } - service_set_state(s, s->deserialized_state); + if (s->control_pid > 0 && + pid_is_unwaited(s->control_pid) && + IN_SET(s->deserialized_state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { + r = unit_watch_pid(UNIT(s), s->control_pid); + if (r < 0) + return r; } + if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) + unit_watch_all_pids(UNIT(s)); + + if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) + service_start_watchdog(s); + + service_set_state(s, s->deserialized_state); return 0; } @@ -1215,7 +1270,7 @@ static int service_spawn( if (is_control && UNIT(s)->cgroup_path) { path = strjoina(UNIT(s)->cgroup_path, "/control"); - cg_create(SYSTEMD_CGROUP_CONTROLLER, path); + (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path); } else path = UNIT(s)->cgroup_path; @@ -1794,7 +1849,7 @@ static void service_enter_restart(Service *s) { * restarted. We use JOB_RESTART (instead of the more obvious * JOB_START) here so that those dependency jobs will be added * as well. */ - r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, false, &error, NULL); + r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, &error, NULL); if (r < 0) goto fail; @@ -2357,14 +2412,6 @@ static bool service_check_gc(Unit *u) { return false; } -_pure_ static bool service_check_snapshot(Unit *u) { - Service *s = SERVICE(u); - - assert(s); - - return s->socket_fd < 0; -} - static int service_retry_pid_file(Service *s) { int r; @@ -3286,7 +3333,6 @@ const UnitVTable service_vtable = { .sub_state_to_string = service_sub_state_to_string, .check_gc = service_check_gc, - .check_snapshot = service_check_snapshot, .sigchld_event = service_sigchld_event, diff --git a/src/core/show-status.c b/src/core/show-status.c index 02b1be73e3..e4e12a3365 100644 --- a/src/core/show-status.c +++ b/src/core/show-status.c @@ -19,7 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "parse-util.h" #include "show-status.h" +#include "string-util.h" +#include "terminal-util.h" #include "util.h" int parse_show_status(const char *v, ShowStatus *ret) { @@ -40,3 +46,81 @@ int parse_show_status(const char *v, ShowStatus *ret) { *ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO; return 0; } + +int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { + static const char status_indent[] = " "; /* "[" STATUS "] " */ + _cleanup_free_ char *s = NULL; + _cleanup_close_ int fd = -1; + struct iovec iovec[6] = {}; + int n = 0; + static bool prev_ephemeral; + + assert(format); + + /* This is independent of logging, as status messages are + * optional and go exclusively to the console. */ + + if (vasprintf(&s, format, ap) < 0) + return log_oom(); + + fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + if (ellipse) { + char *e; + size_t emax, sl; + int c; + + c = fd_columns(fd); + if (c <= 0) + c = 80; + + sl = status ? sizeof(status_indent)-1 : 0; + + emax = c - sl - 1; + if (emax < 3) + emax = 3; + + e = ellipsize(s, emax, 50); + if (e) { + free(s); + s = e; + } + } + + if (prev_ephemeral) + IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); + prev_ephemeral = ephemeral; + + if (status) { + if (!isempty(status)) { + IOVEC_SET_STRING(iovec[n++], "["); + IOVEC_SET_STRING(iovec[n++], status); + IOVEC_SET_STRING(iovec[n++], "] "); + } else + IOVEC_SET_STRING(iovec[n++], status_indent); + } + + IOVEC_SET_STRING(iovec[n++], s); + if (!ephemeral) + IOVEC_SET_STRING(iovec[n++], "\n"); + + if (writev(fd, iovec, n) < 0) + return -errno; + + return 0; +} + +int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) { + va_list ap; + int r; + + assert(format); + + va_start(ap, format); + r = status_vprintf(status, ellipse, ephemeral, format, ap); + va_end(ap); + + return r; +} diff --git a/src/core/show-status.h b/src/core/show-status.h index a2b2153746..c79d4acb66 100644 --- a/src/core/show-status.h +++ b/src/core/show-status.h @@ -21,6 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <stdbool.h> + +#include "macro.h" + /* Manager status */ typedef enum ShowStatus { @@ -32,3 +36,6 @@ typedef enum ShowStatus { } ShowStatus; int parse_show_status(const char *v, ShowStatus *ret); + +int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); +int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 27c581d9c1..3a95b5fd72 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -19,31 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/mman.h> -#include <sys/reboot.h> -#include <linux/reboot.h> -#include <sys/stat.h> -#include <sys/mount.h> #include <errno.h> -#include <unistd.h> +#include <getopt.h> +#include <linux/reboot.h> #include <signal.h> #include <stdbool.h> #include <stdlib.h> -#include <getopt.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/reboot.h> +#include <sys/stat.h> +#include <unistd.h> -#include "missing.h" -#include "log.h" +#include "alloc-util.h" +#include "cgroup-util.h" +#include "def.h" #include "fileio.h" +#include "killall.h" +#include "log.h" +#include "missing.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" +#include "switch-root.h" +#include "terminal-util.h" #include "umount.h" #include "util.h" #include "virt.h" #include "watchdog.h" -#include "killall.h" -#include "cgroup-util.h" -#include "def.h" -#include "switch-root.h" -#include "process-util.h" -#include "terminal-util.h" #define FINALIZE_ATTEMPTS 50 diff --git a/src/core/slice.c b/src/core/slice.c index 1542e83eb6..39dabae055 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -21,13 +21,15 @@ #include <errno.h> +#include "alloc-util.h" +#include "dbus-slice.h" #include "log.h" -#include "strv.h" #include "special.h" +#include "string-util.h" +#include "strv.h" #include "unit-name.h" #include "unit.h" #include "slice.h" -#include "dbus-slice.h" static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = { [SLICE_DEAD] = UNIT_INACTIVE, @@ -83,6 +85,9 @@ static int slice_add_default_dependencies(Slice *s) { assert(s); + if (!UNIT(s)->default_dependencies) + return 0; + /* Make sure slices are unloaded on shutdown */ r = unit_add_two_dependencies_by_name( UNIT(s), @@ -94,7 +99,6 @@ static int slice_add_default_dependencies(Slice *s) { return 0; } - static int slice_verify(Slice *s) { _cleanup_free_ char *parent = NULL; int r; @@ -142,11 +146,9 @@ static int slice_load(Unit *u) { if (r < 0) return r; - if (u->default_dependencies) { - r = slice_add_default_dependencies(s); - if (r < 0) - return r; - } + r = slice_add_default_dependencies(s); + if (r < 0) + return r; } return slice_verify(s); @@ -253,7 +255,7 @@ _pure_ static const char *slice_sub_state_to_string(Unit *u) { return slice_state_to_string(SLICE(u)->state); } -static int slice_enumerate(Manager *m) { +static void slice_enumerate(Manager *m) { Unit *u; int r; @@ -262,13 +264,16 @@ static int slice_enumerate(Manager *m) { u = manager_get_unit(m, SPECIAL_ROOT_SLICE); if (!u) { u = unit_new(m, sizeof(Slice)); - if (!u) - return log_oom(); + if (!u) { + log_oom(); + return; + } r = unit_add_name(u, SPECIAL_ROOT_SLICE); if (r < 0) { unit_free(u); - return log_error_errno(r, "Failed to add -.slice name"); + log_error_errno(r, "Failed to add -.slice name"); + return; } } @@ -286,8 +291,6 @@ static int slice_enumerate(Manager *m) { unit_add_to_load_queue(u); unit_add_to_dbus_queue(u); - - return 0; } const UnitVTable slice_vtable = { diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index 761582c7a2..0661ff9ecd 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -21,18 +21,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <dirent.h> #include <errno.h> -#include <string.h> -#include <stdlib.h> #include <fcntl.h> -#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" #include "macro.h" #include "smack-setup.h" +#include "string-util.h" #include "util.h" -#include "fileio.h" -#include "log.h" #ifdef HAVE_SMACK diff --git a/src/core/snapshot.c b/src/core/snapshot.c deleted file mode 100644 index 867f3765e7..0000000000 --- a/src/core/snapshot.c +++ /dev/null @@ -1,299 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <errno.h> - -#include "unit.h" -#include "snapshot.h" -#include "unit-name.h" -#include "dbus-snapshot.h" -#include "bus-common-errors.h" - -static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = { - [SNAPSHOT_DEAD] = UNIT_INACTIVE, - [SNAPSHOT_ACTIVE] = UNIT_ACTIVE -}; - -static void snapshot_init(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(UNIT(s)->load_state == UNIT_STUB); - - UNIT(s)->ignore_on_isolate = true; - UNIT(s)->ignore_on_snapshot = true; - UNIT(s)->allow_isolate = true; -} - -static void snapshot_set_state(Snapshot *s, SnapshotState state) { - SnapshotState old_state; - assert(s); - - old_state = s->state; - s->state = state; - - if (state != old_state) - log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state)); - - unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true); -} - -static int snapshot_load(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(u); - assert(u->load_state == UNIT_STUB); - - /* Make sure that only snapshots created via snapshot_create() - * can be loaded */ - if (!u->transient && UNIT(s)->manager->n_reloading <= 0) - return -ENOENT; - - u->load_state = UNIT_LOADED; - return 0; -} - -static int snapshot_coldplug(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(s->state == SNAPSHOT_DEAD); - - if (s->deserialized_state != s->state) - snapshot_set_state(s, s->deserialized_state); - - return 0; -} - -static void snapshot_dump(Unit *u, FILE *f, const char *prefix) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(f); - - fprintf(f, - "%sSnapshot State: %s\n" - "%sClean Up: %s\n", - prefix, snapshot_state_to_string(s->state), - prefix, yes_no(s->cleanup)); -} - -static int snapshot_start(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(s->state == SNAPSHOT_DEAD); - - snapshot_set_state(s, SNAPSHOT_ACTIVE); - - if (s->cleanup) - unit_add_to_cleanup_queue(u); - - return 1; -} - -static int snapshot_stop(Unit *u) { - Snapshot *s = SNAPSHOT(u); - - assert(s); - assert(s->state == SNAPSHOT_ACTIVE); - - snapshot_set_state(s, SNAPSHOT_DEAD); - return 1; -} - -static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) { - Snapshot *s = SNAPSHOT(u); - Unit *other; - Iterator i; - - assert(s); - assert(f); - assert(fds); - - unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state)); - unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup)); - SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) - unit_serialize_item(u, f, "wants", other->id); - - return 0; -} - -static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) { - Snapshot *s = SNAPSHOT(u); - int r; - - assert(u); - assert(key); - assert(value); - assert(fds); - - if (streq(key, "state")) { - SnapshotState state; - - state = snapshot_state_from_string(value); - if (state < 0) - log_unit_debug(u, "Failed to parse state value: %s", value); - else - s->deserialized_state = state; - - } else if (streq(key, "cleanup")) { - - r = parse_boolean(value); - if (r < 0) - log_unit_debug(u, "Failed to parse cleanup value: %s", value); - else - s->cleanup = r; - - } else if (streq(key, "wants")) { - - r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true); - if (r < 0) - return r; - } else - log_unit_debug(u, "Unknown serialization key: %s", key); - - return 0; -} - -_pure_ static UnitActiveState snapshot_active_state(Unit *u) { - assert(u); - - return state_translation_table[SNAPSHOT(u)->state]; -} - -_pure_ static const char *snapshot_sub_state_to_string(Unit *u) { - assert(u); - - return snapshot_state_to_string(SNAPSHOT(u)->state); -} - -int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) { - _cleanup_free_ char *n = NULL; - Unit *other, *u = NULL; - Iterator i; - int r; - const char *k; - - assert(m); - assert(_s); - - if (name) { - if (!unit_name_is_valid(name, UNIT_NAME_PLAIN)) - return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name); - - if (!endswith(name, ".snapshot")) - return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name); - - if (manager_get_unit(m, name)) - return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name); - - } else { - - for (;;) { - if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0) - return -ENOMEM; - - if (!manager_get_unit(m, n)) { - name = n; - break; - } - - n = mfree(n); - } - } - - r = manager_load_unit_prepare(m, name, NULL, e, &u); - if (r < 0) - goto fail; - - u->transient = true; - manager_dispatch_load_queue(m); - assert(u->load_state == UNIT_LOADED); - - HASHMAP_FOREACH_KEY(other, k, m->units, i) { - - if (other->ignore_on_snapshot || - other->transient) - continue; - - if (k != other->id) - continue; - - if (UNIT_VTABLE(other)->check_snapshot) - if (!UNIT_VTABLE(other)->check_snapshot(other)) - continue; - - if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - continue; - - r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true); - if (r < 0) - goto fail; - } - - SNAPSHOT(u)->cleanup = cleanup; - *_s = SNAPSHOT(u); - - log_unit_info(u, "Created snapshot."); - - return 0; - -fail: - if (u) - unit_add_to_cleanup_queue(u); - - return r; -} - -void snapshot_remove(Snapshot *s) { - assert(s); - - log_unit_info(UNIT(s), "Removing snapshot."); - - unit_add_to_cleanup_queue(UNIT(s)); -} - -const UnitVTable snapshot_vtable = { - .object_size = sizeof(Snapshot), - - .no_alias = true, - .no_instances = true, - .no_gc = true, - - .init = snapshot_init, - .load = snapshot_load, - - .coldplug = snapshot_coldplug, - - .dump = snapshot_dump, - - .start = snapshot_start, - .stop = snapshot_stop, - - .serialize = snapshot_serialize, - .deserialize_item = snapshot_deserialize_item, - - .active_state = snapshot_active_state, - .sub_state_to_string = snapshot_sub_state_to_string, - - .bus_vtable = bus_snapshot_vtable -}; diff --git a/src/core/socket.c b/src/core/socket.c index e42ed62ef1..5b9e32ce9d 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -31,27 +31,34 @@ #include "sd-event.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "copy.h" #include "dbus-socket.h" #include "def.h" #include "exit-status.h" +#include "fd-util.h" #include "formats-util.h" #include "label.h" #include "log.h" #include "missing.h" #include "mkdir.h" +#include "parse-util.h" #include "path-util.h" +#include "process-util.h" #include "selinux-util.h" #include "signal-util.h" #include "smack-util.h" #include "socket.h" #include "special.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" #include "unit-printf.h" #include "unit.h" +#include "user-util.h" static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = UNIT_INACTIVE, @@ -107,11 +114,9 @@ static void socket_unwatch_control_pid(Socket *s) { } static void socket_cleanup_fd_list(SocketPort *p) { - int k = p->n_auxiliary_fds; - - while (k--) - safe_close(p->auxiliary_fds[k]); + assert(p); + close_many(p->auxiliary_fds, p->n_auxiliary_fds); p->auxiliary_fds = mfree(p->auxiliary_fds); p->n_auxiliary_fds = 0; } @@ -291,6 +296,9 @@ static int socket_add_default_dependencies(Socket *s) { int r; assert(s); + if (!UNIT(s)->default_dependencies) + return 0; + r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true); if (r < 0) return r; @@ -360,11 +368,9 @@ static int socket_add_extras(Socket *s) { return r; } - if (u->default_dependencies) { - r = socket_add_default_dependencies(s); - if (r < 0) - return r; - } + r = socket_add_default_dependencies(s); + if (r < 0) + return r; return 0; } @@ -1167,9 +1173,9 @@ static int usbffs_dispatch_eps(SocketPort *p) { _cleanup_free_ char *path = NULL; int r, i, n, k; - r = path_get_parent(p->path, &path); - if (r < 0) - return r; + path = dirname_malloc(p->path); + if (!path) + return -ENOMEM; r = scandir(path, &ent, usbffs_select_ep, alphasort); if (r < 0) @@ -1450,7 +1456,9 @@ static int socket_coldplug(Unit *u) { if (s->deserialized_state == s->state) return 0; - if (IN_SET(s->deserialized_state, + if (s->control_pid > 0 && + pid_is_unwaited(s->control_pid) && + IN_SET(s->deserialized_state, SOCKET_START_PRE, SOCKET_START_CHOWN, SOCKET_START_POST, @@ -1461,9 +1469,6 @@ static int socket_coldplug(Unit *u) { SOCKET_FINAL_SIGTERM, SOCKET_FINAL_SIGKILL)) { - if (s->control_pid <= 0) - return -EBADMSG; - r = unit_watch_pid(UNIT(s), s->control_pid); if (r < 0) return r; @@ -1916,7 +1921,7 @@ static void socket_enter_running(Socket *s, int cfd) { goto fail; } - r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL); + r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &error, NULL); if (r < 0) goto fail; } @@ -1974,7 +1979,7 @@ static void socket_enter_running(Socket *s, int cfd) { cfd = -1; s->n_connections ++; - r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL); + r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL); if (r < 0) goto fail; @@ -2328,7 +2333,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value, return 0; } -static int socket_distribute_fds(Unit *u, FDSet *fds) { +static void socket_distribute_fds(Unit *u, FDSet *fds) { Socket *s = SOCKET(u); SocketPort *p; @@ -2352,8 +2357,6 @@ static int socket_distribute_fds(Unit *u, FDSet *fds) { } } } - - return 0; } _pure_ static UnitActiveState socket_active_state(Unit *u) { diff --git a/src/core/swap.c b/src/core/swap.c index f42d151075..ee0838e676 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -20,22 +20,30 @@ ***/ #include <errno.h> -#include <unistd.h> #include <sys/epoll.h> #include <sys/stat.h> -#include <libudev.h> +#include <unistd.h> -#include "unit.h" -#include "swap.h" -#include "unit-name.h" +#include "libudev.h" + +#include "alloc-util.h" #include "dbus-swap.h" -#include "special.h" +#include "escape.h" #include "exit-status.h" +#include "fd-util.h" +#include "formats-util.h" +#include "fstab-util.h" +#include "parse-util.h" #include "path-util.h" -#include "virt.h" +#include "process-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "swap.h" #include "udev-util.h" -#include "fstab-util.h" -#include "formats-util.h" +#include "unit-name.h" +#include "unit.h" +#include "virt.h" static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { [SWAP_DEAD] = UNIT_INACTIVE, @@ -205,6 +213,9 @@ static int swap_add_device_links(Swap *s) { static int swap_add_default_dependencies(Swap *s) { assert(s); + if (!UNIT(s)->default_dependencies) + return 0; + if (UNIT(s)->manager->running_as != MANAGER_SYSTEM) return 0; @@ -323,11 +334,9 @@ static int swap_load(Unit *u) { if (r < 0) return r; - if (UNIT(s)->default_dependencies) { - r = swap_add_default_dependencies(s); - if (r < 0) - return r; - } + r = swap_add_default_dependencies(s); + if (r < 0) + return r; } return swap_verify(s); @@ -520,16 +529,16 @@ static int swap_coldplug(Unit *u) { if (new_state == s->state) return 0; - if (new_state == SWAP_ACTIVATING || - new_state == SWAP_ACTIVATING_SIGTERM || - new_state == SWAP_ACTIVATING_SIGKILL || - new_state == SWAP_ACTIVATING_DONE || - new_state == SWAP_DEACTIVATING || - new_state == SWAP_DEACTIVATING_SIGTERM || - new_state == SWAP_DEACTIVATING_SIGKILL) { - - if (s->control_pid <= 0) - return -EBADMSG; + if (s->control_pid > 0 && + pid_is_unwaited(s->control_pid) && + IN_SET(new_state, + SWAP_ACTIVATING, + SWAP_ACTIVATING_SIGTERM, + SWAP_ACTIVATING_SIGKILL, + SWAP_ACTIVATING_DONE, + SWAP_DEACTIVATING, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL)) { r = unit_watch_pid(UNIT(s), s->control_pid); if (r < 0) @@ -1198,7 +1207,7 @@ static Unit *swap_following(Unit *u) { if (other->from_fragment) return UNIT(other); - /* Otherwise make everybody follow the unit that's named after + /* Otherwise, make everybody follow the unit that's named after * the swap device in the kernel */ if (streq_ptr(s->what, s->devnode)) @@ -1260,26 +1269,36 @@ static void swap_shutdown(Manager *m) { m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode); } -static int swap_enumerate(Manager *m) { +static void swap_enumerate(Manager *m) { int r; assert(m); if (!m->proc_swaps) { m->proc_swaps = fopen("/proc/swaps", "re"); - if (!m->proc_swaps) - return errno == ENOENT ? 0 : -errno; + if (!m->proc_swaps) { + if (errno == ENOENT) + log_debug("Not swap enabled, skipping enumeration"); + else + log_error_errno(errno, "Failed to open /proc/swaps: %m"); + + return; + } r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to watch /proc/swaps: %m"); goto fail; + } /* Dispatch this before we dispatch SIGCHLD, so that * we always get the events from /proc/swaps before * the SIGCHLD of /sbin/swapon. */ r = sd_event_source_set_priority(m->swap_event_source, -10); - if (r < 0) + if (r < 0) { + log_error_errno(r, "Failed to change /proc/swaps priority: %m"); goto fail; + } (void) sd_event_source_set_description(m->swap_event_source, "swap-proc"); } @@ -1288,11 +1307,10 @@ static int swap_enumerate(Manager *m) { if (r < 0) goto fail; - return 0; + return; fail: swap_shutdown(m); - return r; } int swap_process_device_new(Manager *m, struct udev_device *dev) { diff --git a/src/core/swap.h b/src/core/swap.h index 7f29603c32..303b926568 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -22,7 +22,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <libudev.h> +#include "libudev.h" typedef struct Swap Swap; diff --git a/src/core/target.c b/src/core/target.c index a905a1adf6..14f9b2e26a 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -19,13 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "unit.h" -#include "target.h" -#include "log.h" #include "dbus-target.h" +#include "log.h" #include "special.h" +#include "string-util.h" #include "unit-name.h" +#include "unit.h" +#include "target.h" static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = { [TARGET_DEAD] = UNIT_INACTIVE, @@ -52,9 +52,7 @@ static int target_add_default_dependencies(Target *t) { static const UnitDependency deps[] = { UNIT_REQUIRES, - UNIT_REQUIRES_OVERRIDABLE, UNIT_REQUISITE, - UNIT_REQUISITE_OVERRIDABLE, UNIT_WANTS, UNIT_BINDS_TO, UNIT_PART_OF diff --git a/src/core/timer.c b/src/core/timer.c index 800e58261c..51b1d875be 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -21,13 +21,20 @@ #include <errno.h> -#include "unit.h" -#include "unit-name.h" -#include "timer.h" +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" #include "dbus-timer.h" +#include "fs-util.h" +#include "parse-util.h" #include "special.h" -#include "bus-util.h" -#include "bus-error.h" +#include "string-table.h" +#include "string-util.h" +#include "timer.h" +#include "unit-name.h" +#include "unit.h" +#include "user-util.h" +#include "virt.h" static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { [TIMER_DEAD] = UNIT_INACTIVE, @@ -95,6 +102,9 @@ static int timer_add_default_dependencies(Timer *t) { assert(t); + if (!UNIT(t)->default_dependencies) + return 0; + r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true); if (r < 0) return r; @@ -185,11 +195,9 @@ static int timer_load(Unit *u) { if (r < 0) return r; - if (u->default_dependencies) { - r = timer_add_default_dependencies(t); - if (r < 0) - return r; - } + r = timer_add_default_dependencies(t); + if (r < 0) + return r; } return timer_verify(t); @@ -353,10 +361,14 @@ static void timer_enter_waiting(Timer *t, bool initial) { break; case TIMER_BOOT: - /* CLOCK_MONOTONIC equals the uptime on Linux */ - base = 0; - break; - + if (detect_container() <= 0) { + /* CLOCK_MONOTONIC equals the uptime on Linux */ + base = 0; + break; + } + /* In a container we don't want to include the time the host + * was already up when the container started, so count from + * our own startup. Fall through. */ case TIMER_STARTUP: base = UNIT(t)->manager->userspace_timestamp.monotonic; break; @@ -499,15 +511,14 @@ static void timer_enter_running(Timer *t) { if (unit_stop_pending(UNIT(t))) return; - r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)), - JOB_REPLACE, true, &error, NULL); + r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)), JOB_REPLACE, &error, NULL); if (r < 0) goto fail; dual_timestamp_get(&t->last_trigger); if (t->stamp_path) - touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0); + touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID); timer_set_state(t, TIMER_RUNNING); return; @@ -543,7 +554,7 @@ static int timer_start(Unit *u) { /* The timer has never run before, * make sure a stamp file exists. */ - touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0); + touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); } t->result = TIMER_SUCCESS; diff --git a/src/core/transaction.c b/src/core/transaction.c index d1c1b9a3cd..cf37b5eb75 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -22,10 +22,11 @@ #include <unistd.h> #include <fcntl.h> +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-error.h" -#include "transaction.h" #include "terminal-util.h" +#include "transaction.h" static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); @@ -98,9 +99,7 @@ static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other j->type = t; j->state = JOB_WAITING; - j->override = j->override || other->override; j->irreversible = j->irreversible || other->irreversible; - j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor; /* Patch us in as new owner of the JobDependency objects */ @@ -744,7 +743,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error return 0; } -static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) { +static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool *is_new) { Job *j, *f; assert(tr); @@ -773,7 +772,6 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b j->generation = 0; j->marker = NULL; j->matters_to_anchor = false; - j->override = override; j->irreversible = tr->irreversible; LIST_PREPEND(transaction, f, j); @@ -832,7 +830,6 @@ int transaction_add_job_and_dependencies( Unit *unit, Job *by, bool matters, - bool override, bool conflicts, bool ignore_requirements, bool ignore_order, @@ -894,7 +891,7 @@ int transaction_add_job_and_dependencies( /* First add the job. */ - ret = transaction_add_one_job(tr, type, unit, override, &is_new); + ret = transaction_add_one_job(tr, type, unit, &is_new); if (!ret) return -ENOMEM; @@ -917,7 +914,7 @@ int transaction_add_job_and_dependencies( * add all dependencies of everybody following. */ if (unit_following_set(ret->unit, &following) > 0) { SET_FOREACH(dep, following, i) { - r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, false, false, ignore_order, e); if (r < 0) { log_unit_warning(dep, "Cannot add dependency job for, ignoring: %s", bus_error_message(e, r)); sd_bus_error_free(e); @@ -930,7 +927,7 @@ int transaction_add_job_and_dependencies( /* Finally, recursively add in all dependencies. */ if (type == JOB_START || type == JOB_RESTART) { SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) goto fail; @@ -940,7 +937,7 @@ int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) goto fail; @@ -949,19 +946,8 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e); - if (r < 0) { - log_unit_full(dep, - r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r, - "Cannot add dependency job, ignoring: %s", - bus_error_message(e, r)); - sd_bus_error_free(e); - } - } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { - r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e); if (r < 0) { log_unit_full(dep, r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r, @@ -972,7 +958,7 @@ int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { - r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) goto fail; @@ -981,19 +967,8 @@ int transaction_add_job_and_dependencies( } } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) { - r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e); - if (r < 0) { - log_unit_full(dep, - r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r, - "Cannot add dependency job, ignoring: %s", - bus_error_message(e, r)); - sd_bus_error_free(e); - } - } - SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { - r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e); if (r < 0) { if (r != -EBADR) goto fail; @@ -1003,7 +978,7 @@ int transaction_add_job_and_dependencies( } SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) { - r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e); if (r < 0) { log_unit_warning(dep, "Cannot add dependency job, ignoring: %s", @@ -1038,7 +1013,7 @@ int transaction_add_job_and_dependencies( if (nt == JOB_NOP) continue; - r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, false, false, ignore_order, e); if (r < 0) { if (r != -EBADR) goto fail; @@ -1051,7 +1026,7 @@ int transaction_add_job_and_dependencies( if (type == JOB_RELOAD) { SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) { - r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e); + r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, false, false, ignore_order, e); if (r < 0) { log_unit_warning(dep, "Cannot add dependency reload job, ignoring: %s", @@ -1096,7 +1071,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) { if (hashmap_get(tr->jobs, u)) continue; - r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL); + r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, NULL); if (r < 0) log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m"); } diff --git a/src/core/transaction.h b/src/core/transaction.h index d949b21b8d..f7aa3df085 100644 --- a/src/core/transaction.h +++ b/src/core/transaction.h @@ -44,7 +44,6 @@ int transaction_add_job_and_dependencies( Unit *unit, Job *by, bool matters, - bool override, bool conflicts, bool ignore_requirements, bool ignore_order, diff --git a/src/core/umount.c b/src/core/umount.c index 22dbe67259..9d1f7660db 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -21,23 +21,30 @@ #include <errno.h> #include <fcntl.h> +#include <linux/dm-ioctl.h> +#include <linux/loop.h> #include <string.h> #include <sys/mount.h> #include <sys/swap.h> -#include <linux/loop.h> -#include <linux/dm-ioctl.h> +#include "libudev.h" + +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fstab-util.h" #include "list.h" #include "mount-setup.h" -#include "umount.h" #include "path-util.h" +#include "string-util.h" +#include "udev-util.h" +#include "umount.h" #include "util.h" #include "virt.h" -#include "libudev.h" -#include "udev-util.h" typedef struct MountPoint { char *path; + char *options; dev_t devnum; LIST_FIELDS(struct MountPoint, mount_point); } MountPoint; @@ -71,7 +78,7 @@ static int mount_points_list_get(MountPoint **head) { return -errno; for (i = 1;; i++) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *options = NULL; char *p = NULL; MountPoint *m; int k; @@ -82,15 +89,15 @@ static int mount_points_list_get(MountPoint **head) { "%*s " /* (3) major:minor */ "%*s " /* (4) root */ "%ms " /* (5) mount point */ - "%*s" /* (6) mount options */ + "%*s" /* (6) mount flags */ "%*[^-]" /* (7) optional fields */ "- " /* (8) separator */ "%*s " /* (9) file system type */ "%*s" /* (10) mount source */ - "%*s" /* (11) mount options 2 */ + "%ms" /* (11) mount options */ "%*[^\n]", /* some rubbish at the end */ - &path); - if (k != 1) { + &path, &options); + if (k != 2) { if (k == EOF) break; @@ -125,6 +132,9 @@ static int mount_points_list_get(MountPoint **head) { } m->path = p; + m->options = options; + options = NULL; + LIST_PREPEND(mount_point, *head, m); } @@ -369,6 +379,14 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e benefits, but might confuse the host, as we remount the superblock here, not the bind mound. */ if (detect_container() <= 0) { + _cleanup_free_ char *options = NULL; + /* MS_REMOUNT requires that the data parameter + * should be the same from the original mount + * except for the desired changes. Since we want + * to remount read-only, we should filter out + * rw (and ro too, because it confuses the kernel) */ + (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options); + /* We always try to remount directories * read-only first, before we go on and umount * them. @@ -385,7 +403,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e * alias read-only we hence should be * relatively safe regarding keeping the fs we * can otherwise not see dirty. */ - (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL); + log_info("Remounting '%s' read-only with options '%s'.", m->path, options); + (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options); } /* Skip / and /usr since we cannot unmount that diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 0889769d03..f587a5a141 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -19,14 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" +#include "alloc-util.h" +#include "cgroup-util.h" +#include "formats-util.h" +#include "macro.h" #include "specifier.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" #include "unit-printf.h" -#include "macro.h" -#include "cgroup-util.h" -#include "formats-util.h" +#include "unit.h" +#include "user-util.h" static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { Unit *u = userdata; @@ -63,10 +66,7 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda assert(u); - if (!u->instance) - return -EINVAL; - - return unit_name_unescape(u->instance, ret); + return unit_name_unescape(strempty(u->instance), ret); } static int specifier_filename(char specifier, void *data, void *userdata, char **ret) { @@ -128,6 +128,8 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch n = unit_default_cgroup_path(slice); } else n = strdup(u->manager->cgroup_root); + if (!n) + return -ENOMEM; *ret = n; return 0; @@ -157,162 +159,43 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char ** } static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { - char *printed = NULL; - Unit *u = userdata; - ExecContext *c; - int r = 0; - - assert(u); - - c = unit_get_exec_context(u); - if (!c) - return -EINVAL; - - if (u->manager->running_as == MANAGER_SYSTEM) { - - /* We cannot use NSS from PID 1, hence try to make the - * best of it in that case, and fail if we can't help - * it */ + char *t; - if (!c->user || streq(c->user, "root") || streq(c->user, "0")) - printed = strdup(specifier == 'u' ? "root" : "0"); - else { - if (specifier == 'u') - printed = strdup(c->user); - else { - uid_t uid; + /* If we are UID 0 (root), this will not result in NSS, + * otherwise it might. This is good, as we want to be able to + * run this in PID 1, where our user ID is 0, but where NSS + * lookups are not allowed. */ - r = parse_uid(c->user, &uid); - if (r < 0) - return -ENODATA; - - r = asprintf(&printed, UID_FMT, uid); - } - } - - } else { - _cleanup_free_ char *tmp = NULL; - const char *username = NULL; - uid_t uid; - - if (c->user) - username = c->user; - else - /* get USER env from env or our own uid */ - username = tmp = getusername_malloc(); - - /* fish username from passwd */ - r = get_user_creds(&username, &uid, NULL, NULL, NULL); - if (r < 0) - return r; - - if (specifier == 'u') - printed = strdup(username); - else - r = asprintf(&printed, UID_FMT, uid); - } - - if (r < 0 || !printed) + t = getusername_malloc(); + if (!t) return -ENOMEM; - *ret = printed; + *ret = t; return 0; } -static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { - Unit *u = userdata; - ExecContext *c; - char *n; - int r; - - assert(u); - - c = unit_get_exec_context(u); - if (!c) - return -EOPNOTSUPP; - - if (u->manager->running_as == MANAGER_SYSTEM) { +static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) { - /* We cannot use NSS from PID 1, hence try to make the - * best of it if we can, but fail if we can't */ - - if (!c->user || streq(c->user, "root") || streq(c->user, "0")) - n = strdup("/root"); - else - return -EOPNOTSUPP; - - } else { - - /* return HOME if set, otherwise from passwd */ - if (!c || !c->user) { - r = get_home_dir(&n); - if (r < 0) - return r; - } else { - const char *username, *home; - - username = c->user; - r = get_user_creds(&username, NULL, NULL, &home, NULL); - if (r < 0) - return r; - - n = strdup(home); - } - } - - if (!n) + if (asprintf(ret, UID_FMT, getuid()) < 0) return -ENOMEM; - *ret = n; return 0; } -static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { - Unit *u = userdata; - ExecContext *c; - char *n; - int r; - - assert(u); - - c = unit_get_exec_context(u); - if (!c) - return -EOPNOTSUPP; - - if (u->manager->running_as == MANAGER_SYSTEM) { - - /* We cannot use NSS from PID 1, hence try to make the - * best of it if we can, but fail if we can't */ - - if (!c->user || streq(c->user, "root") || streq(c->user, "0")) - n = strdup("/bin/sh"); - else - return -EOPNOTSUPP; - - } else { +static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) { - /* return /bin/sh for root, otherwise the value from passwd */ - if (!c->user) { - r = get_shell(&n); - if (r < 0) - return r; - } else { - const char *username, *shell; + /* On PID 1 (which runs as root) this will not result in NSS, + * which is good. See above */ - username = c->user; - r = get_user_creds(&username, NULL, NULL, NULL, &shell); - if (r < 0) - return r; + return get_home_dir(ret); +} - n = strdup(shell); - } - } +static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) { - if (!n) - return -ENOMEM; + /* On PID 1 (which runs as root) this will not result in NSS, + * which is good. See above */ - *ret = n; - return 0; + return get_shell(ret); } int unit_name_printf(Unit *u, const char* format, char **ret) { @@ -352,10 +235,10 @@ int unit_full_printf(Unit *u, const char *format, char **ret) { * %r where units in this slice are placed in the cgroup tree * %R the root of this systemd's instance tree * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR) - * %U the UID of the configured user or running user - * %u the username of the configured user or running user - * %h the homedir of the configured user or running user - * %s the shell of the configured user or running user + * %U the UID of the running user + * %u the username of the running user + * %h the homedir of the running user + * %s the shell of the running user * %m the machine ID of the running system * %H the host name of the running system * %b the boot ID of the running system @@ -375,7 +258,8 @@ int unit_full_printf(Unit *u, const char *format, char **ret) { { 'r', specifier_cgroup_slice, NULL }, { 'R', specifier_cgroup_root, NULL }, { 't', specifier_runtime, NULL }, - { 'U', specifier_user_name, NULL }, + + { 'U', specifier_user_id, NULL }, { 'u', specifier_user_name, NULL }, { 'h', specifier_user_home, NULL }, { 's', specifier_user_shell, NULL }, diff --git a/src/core/unit.c b/src/core/unit.c index 39cd89f1e3..f553f24829 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -20,43 +20,49 @@ ***/ #include <errno.h> -#include <string.h> #include <stdlib.h> -#include <unistd.h> +#include <string.h> #include <sys/stat.h> +#include <unistd.h> #include "sd-id128.h" #include "sd-messages.h" -#include "set.h" -#include "macro.h" -#include "strv.h" -#include "path-util.h" -#include "log.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-util.h" #include "cgroup-util.h" -#include "missing.h" -#include "mkdir.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "dropin.h" +#include "escape.h" +#include "execute.h" #include "fileio-label.h" #include "formats-util.h" +#include "load-dropin.h" +#include "load-fragment.h" +#include "log.h" +#include "macro.h" +#include "missing.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" -#include "virt.h" -#include "bus-common-errors.h" -#include "bus-util.h" -#include "dropin.h" -#include "unit-name.h" +#include "set.h" #include "special.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" #include "unit.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "dbus.h" -#include "dbus-unit.h" -#include "execute.h" +#include "user-util.h" +#include "virt.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, [UNIT_SOCKET] = &socket_vtable, [UNIT_BUSNAME] = &busname_vtable, [UNIT_TARGET] = &target_vtable, - [UNIT_SNAPSHOT] = &snapshot_vtable, [UNIT_DEVICE] = &device_vtable, [UNIT_MOUNT] = &mount_vtable, [UNIT_AUTOMOUNT] = &automount_vtable, @@ -412,12 +418,11 @@ static void unit_remove_transient(Unit *u) { STRV_FOREACH(i, u->dropin_paths) { _cleanup_free_ char *p = NULL; - int r; (void) unlink(*i); - r = path_get_parent(*i, &p); - if (r >= 0) + p = dirname_malloc(*i); + if (p) (void) rmdir(p); } } @@ -992,15 +997,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tRefuseManualStop: %s\n" "%s\tDefaultDependencies: %s\n" "%s\tOnFailureJobMode: %s\n" - "%s\tIgnoreOnIsolate: %s\n" - "%s\tIgnoreOnSnapshot: %s\n", + "%s\tIgnoreOnIsolate: %s\n", prefix, yes_no(u->stop_when_unneeded), prefix, yes_no(u->refuse_manual_start), prefix, yes_no(u->refuse_manual_stop), prefix, yes_no(u->default_dependencies), prefix, job_mode_to_string(u->on_failure_job_mode), - prefix, yes_no(u->ignore_on_isolate), - prefix, yes_no(u->ignore_on_snapshot)); + prefix, yes_no(u->ignore_on_isolate)); if (UNIT_VTABLE(u)->dump) UNIT_VTABLE(u)->dump(u, f, prefix2); @@ -1098,9 +1101,7 @@ static int unit_add_target_dependencies(Unit *u) { static const UnitDependency deps[] = { UNIT_REQUIRED_BY, - UNIT_REQUIRED_BY_OVERRIDABLE, UNIT_REQUISITE_OF, - UNIT_REQUISITE_OF_OVERRIDABLE, UNIT_WANTED_BY, UNIT_BOUND_BY }; @@ -1602,11 +1603,11 @@ bool unit_can_reload(Unit *u) { static void unit_check_unneeded(Unit *u) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + static const UnitDependency needed_dependencies[] = { UNIT_REQUIRED_BY, - UNIT_REQUIRED_BY_OVERRIDABLE, UNIT_REQUISITE_OF, - UNIT_REQUISITE_OF_OVERRIDABLE, UNIT_WANTED_BY, UNIT_BOUND_BY, }; @@ -1643,12 +1644,13 @@ static void unit_check_unneeded(Unit *u) { log_unit_info(u, "Unit not needed anymore. Stopping."); /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */ - r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL); + r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL); if (r < 0) - log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m"); + log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r)); } static void unit_check_binds_to(Unit *u) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; bool stop = false; Unit *other; Iterator i; @@ -1688,9 +1690,9 @@ static void unit_check_binds_to(Unit *u) { log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id); /* A unit we need to run is gone. Sniff. Let's stop this. */ - r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL); + r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL); if (r < 0) - log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m"); + log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r)); } static void retroactively_start_dependencies(Unit *u) { @@ -1703,30 +1705,25 @@ static void retroactively_start_dependencies(Unit *u) { SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i) if (!set_get(u->dependencies[UNIT_AFTER], other) && !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); + manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL); SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) if (!set_get(u->dependencies[UNIT_AFTER], other) && !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL); - - SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if (!set_get(u->dependencies[UNIT_AFTER], other) && - !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); + manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL); SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) if (!set_get(u->dependencies[UNIT_AFTER], other) && !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other))) - manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL); + manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL); SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); + manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL); SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); + manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL); } static void retroactively_stop_dependencies(Unit *u) { @@ -1739,7 +1736,7 @@ static void retroactively_stop_dependencies(Unit *u) { /* Pull down units which are bound to us recursively if enabled */ SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL); + manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL); } static void check_unneeded_dependencies(Unit *u) { @@ -1753,18 +1750,12 @@ static void check_unneeded_dependencies(Unit *u) { SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); - SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); SET_FOREACH(other, u->dependencies[UNIT_WANTS], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); - SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) - if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) - unit_check_unneeded(other); SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other))) unit_check_unneeded(other); @@ -1784,7 +1775,7 @@ void unit_start_on_failure(Unit *u) { SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) { int r; - r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, true, NULL, NULL); + r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, NULL); if (r < 0) log_unit_error_errno(u, r, "Failed to enqueue OnFailure= job: %m"); } @@ -2132,16 +2123,12 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUIRES] = UNIT_REQUIRED_BY, - [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE, [UNIT_WANTS] = UNIT_WANTED_BY, [UNIT_REQUISITE] = UNIT_REQUISITE_OF, - [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUISITE_OF_OVERRIDABLE, [UNIT_BINDS_TO] = UNIT_BOUND_BY, [UNIT_PART_OF] = UNIT_CONSISTS_OF, [UNIT_REQUIRED_BY] = UNIT_REQUIRES, - [UNIT_REQUIRED_BY_OVERRIDABLE] = UNIT_REQUIRES_OVERRIDABLE, [UNIT_REQUISITE_OF] = UNIT_REQUISITE, - [UNIT_REQUISITE_OF_OVERRIDABLE] = UNIT_REQUISITE_OVERRIDABLE, [UNIT_WANTED_BY] = UNIT_WANTS, [UNIT_BOUND_BY] = UNIT_BINDS_TO, [UNIT_CONSISTS_OF] = UNIT_PART_OF, @@ -2320,47 +2307,9 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency return unit_add_two_dependencies(u, d, e, other, add_reference); } -int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { - _cleanup_free_ char *buf = NULL; - Unit *other; - int r; - - assert(u); - assert(name || path); - - r = resolve_template(u, name, path, &buf, &name); - if (r < 0) - return r; - - r = manager_load_unit(u->manager, name, path, NULL, &other); - if (r < 0) - return r; - - return unit_add_dependency(other, d, u, add_reference); -} - -int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { - _cleanup_free_ char *buf = NULL; - Unit *other; - int r; - - assert(u); - assert(name || path); - - r = resolve_template(u, name, path, &buf, &name); - if (r < 0) - return r; - - r = manager_load_unit(u->manager, name, path, NULL, &other); - if (r < 0) - return r; - - return unit_add_two_dependencies(other, d, e, u, add_reference); -} - int set_unit_path(const char *p) { /* This is mostly for debug purposes */ - if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0) + if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 0) return -errno; return 0; @@ -2508,26 +2457,23 @@ static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd return 0; } -int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) { - _cleanup_free_ char *match = NULL; - Manager *m = u->manager; +int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) { + const char *match; - assert(m); + assert(u); + assert(bus); + assert(name); if (u->match_bus_slot) return -EBUSY; - match = strjoin("type='signal'," + match = strjoina("type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," - "arg0='", - name, - "'", + "arg0='", name, "'", NULL); - if (!match) - return -ENOMEM; return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u); } @@ -2544,9 +2490,9 @@ int unit_watch_bus_name(Unit *u, const char *name) { if (u->manager->api_bus) { /* If the bus is already available, install the match directly. * Otherwise, just put the name in the list. bus_setup_api() will take care later. */ - r = unit_install_bus_match(u->manager->api_bus, u, name); + r = unit_install_bus_match(u, u->manager->api_bus, name); if (r < 0) - return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m"); + return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name); } r = hashmap_put(u->manager->watch_bus, name, u); @@ -2925,7 +2871,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { } int unit_coldplug(Unit *u) { - int r; + int r = 0, q = 0; assert(u); @@ -2936,17 +2882,16 @@ int unit_coldplug(Unit *u) { u->coldplugged = true; - if (UNIT_VTABLE(u)->coldplug) { + if (UNIT_VTABLE(u)->coldplug) r = UNIT_VTABLE(u)->coldplug(u); - if (r < 0) - return r; - } - if (u->job) { - r = job_coldplug(u->job); - if (r < 0) - return r; - } + if (u->job) + q = job_coldplug(u->job); + + if (r < 0) + return r; + if (q < 0) + return q; return 0; } @@ -3187,12 +3132,19 @@ int unit_following_set(Unit *u, Set **s) { } UnitFileState unit_get_unit_file_state(Unit *u) { + int r; + assert(u); - if (u->unit_file_state < 0 && u->fragment_path) - u->unit_file_state = unit_file_get_state( + if (u->unit_file_state < 0 && u->fragment_path) { + r = unit_file_get_state( u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, - NULL, basename(u->fragment_path)); + NULL, + basename(u->fragment_path), + &u->unit_file_state); + if (r < 0) + u->unit_file_state = UNIT_FILE_BAD; + } return u->unit_file_state; } @@ -3203,7 +3155,8 @@ int unit_get_unit_file_preset(Unit *u) { if (u->unit_file_preset < 0 && u->fragment_path) u->unit_file_preset = unit_file_query_preset( u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, - NULL, basename(u->fragment_path)); + NULL, + basename(u->fragment_path)); return u->unit_file_preset; } @@ -3368,19 +3321,6 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, return 0; } -static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) { - _cleanup_free_ char *dir = NULL; - int r; - - assert(u); - - r = unit_drop_in_dir(u, mode, u->transient, &dir); - if (r < 0) - return r; - - return drop_in_file(dir, u->id, 50, name, p, q); -} - int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL; @@ -3479,28 +3419,6 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const return unit_write_drop_in_private(u, mode, name, p); } -int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) { - _cleanup_free_ char *p = NULL, *q = NULL; - int r; - - assert(u); - - if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) - return 0; - - r = unit_drop_in_file(u, mode, name, &p, &q); - if (r < 0) - return r; - - if (unlink(q) < 0) - r = errno == ENOENT ? 0 : -errno; - else - r = 1; - - rmdir(p); - return r; -} - int unit_make_transient(Unit *u) { assert(u); diff --git a/src/core/unit.h b/src/core/unit.h index a4a1b011fc..14e3072146 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -203,9 +203,6 @@ struct Unit { /* Ignore this unit when isolating */ bool ignore_on_isolate; - /* Ignore this unit when snapshotting */ - bool ignore_on_snapshot; - /* Did the last condition check succeed? */ bool condition_result; bool assert_result; @@ -248,7 +245,6 @@ typedef enum UnitSetPropertiesMode { #include "socket.h" #include "busname.h" #include "target.h" -#include "snapshot.h" #include "device.h" #include "automount.h" #include "swap.h" @@ -322,7 +318,7 @@ struct UnitVTable { int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds); /* Try to match up fds with what we need for this unit */ - int (*distribute_fds)(Unit *u, FDSet *fds); + void (*distribute_fds)(Unit *u, FDSet *fds); /* Boils down the more complex internal state of this unit to * a simpler one that the engine can understand */ @@ -343,9 +339,6 @@ struct UnitVTable { * shall release its runtime resources */ void (*release_resources)(Unit *u); - /* Return true when this unit is suitable for snapshotting */ - bool (*check_snapshot)(Unit *u); - /* Invoked on every child that died */ void (*sigchld_event)(Unit *u, pid_t pid, int code, int status); @@ -389,7 +382,7 @@ struct UnitVTable { * everything that is loaded here should still stay in * inactive state. It is the job of the coldplug() call above * to put the units into the initial state. */ - int (*enumerate)(Manager *m); + void (*enumerate)(Manager *m); /* Type specific cleanups. */ void (*shutdown)(Manager *m); @@ -443,7 +436,6 @@ DEFINE_CAST(SERVICE, Service); DEFINE_CAST(SOCKET, Socket); DEFINE_CAST(BUSNAME, BusName); DEFINE_CAST(TARGET, Target); -DEFINE_CAST(SNAPSHOT, Snapshot); DEFINE_CAST(DEVICE, Device); DEFINE_CAST(MOUNT, Mount); DEFINE_CAST(AUTOMOUNT, Automount); @@ -464,9 +456,6 @@ int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); -int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); -int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); - int unit_add_exec_dependencies(Unit *u, ExecContext *c); int unit_choose_id(Unit *u, const char *name); @@ -520,7 +509,7 @@ void unit_unwatch_all_pids(Unit *u); void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2); -int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name); +int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name); int unit_watch_bus_name(Unit *u, const char *name); void unit_unwatch_bus_name(Unit *u, const char *name); @@ -592,8 +581,6 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data); int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5); -int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name); - int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien); int unit_make_transient(Unit *u); diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index ab91afec4d..ae53bac600 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -21,13 +21,19 @@ #include <errno.h> +#include "alloc-util.h" #include "dropin.h" +#include "fd-util.h" +#include "fileio.h" +#include "fstab-util.h" #include "generator.h" #include "hashmap.h" #include "log.h" #include "mkdir.h" +#include "parse-util.h" #include "path-util.h" -#include "fstab-util.h" +#include "proc-cmdline.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" #include "util.h" diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index cc03ad3ca8..98fe52a81b 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -19,21 +19,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> -#include <sys/mman.h> +#include <libcryptsetup.h> #include <mntent.h> +#include <string.h> +#include <sys/mman.h> -#include <libcryptsetup.h> +#include "sd-device.h" +#include "alloc-util.h" +#include "ask-password-api.h" +#include "device-util.h" +#include "escape.h" #include "fileio.h" #include "log.h" -#include "util.h" +#include "mount-util.h" +#include "parse-util.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" -#include "ask-password-api.h" -#include "sd-device.h" -#include "device-util.h" +#include "util.h" static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */ static char *arg_cipher = NULL; @@ -312,15 +317,16 @@ static char *disk_mount_point(const char *label) { return NULL; } -static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***passwords) { +static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***ret) { _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL; + _cleanup_strv_free_erase_ char **passwords = NULL; const char *name = NULL; char **p, *id; int r = 0; assert(vol); assert(src); - assert(passwords); + assert(ret); description = disk_description(src); mount_point = disk_mount_point(vol); @@ -360,14 +366,16 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc id = strjoina("cryptsetup:", escaped_name); - r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE|(accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0), passwords); + r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, + ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED), + &passwords); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); if (arg_verify) { - _cleanup_strv_free_ char **passwords2 = NULL; + _cleanup_strv_free_erase_ char **passwords2 = NULL; - assert(strv_length(*passwords) == 1); + assert(strv_length(passwords) == 1); if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) return log_oom(); @@ -380,22 +388,23 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc assert(strv_length(passwords2) == 1); - if (!streq(*passwords[0], passwords2[0])) { + if (!streq(passwords[0], passwords2[0])) { log_warning("Passwords did not match, retrying."); return -EAGAIN; } } - strv_uniq(*passwords); + strv_uniq(passwords); - STRV_FOREACH(p, *passwords) { + STRV_FOREACH(p, passwords) { char *c; if (strlen(*p)+1 >= arg_key_size) continue; /* Pad password if necessary */ - if (!(c = new(char, arg_key_size))) + c = new(char, arg_key_size); + if (!c) return log_oom(); strncpy(c, *p, arg_key_size); @@ -403,14 +412,19 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc *p = c; } + *ret = passwords; + passwords = NULL; + return 0; } -static int attach_tcrypt(struct crypt_device *cd, - const char *name, - const char *key_file, - char **passwords, - uint32_t flags) { +static int attach_tcrypt( + struct crypt_device *cd, + const char *name, + const char *key_file, + char **passwords, + uint32_t flags) { + int r = 0; _cleanup_free_ char *passphrase = NULL; struct crypt_params_tcrypt params = { @@ -520,8 +534,7 @@ static int attach_luks_or_plain(struct crypt_device *cd, * it just configures encryption * parameters when used for plain * mode. */ - r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, - NULL, NULL, arg_keyfile_size, ¶ms); + r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, NULL, NULL, arg_keyfile_size, ¶ms); /* hash == NULL implies the user passed "plain" */ pass_volume_key = (params.hash == NULL); @@ -537,9 +550,7 @@ static int attach_luks_or_plain(struct crypt_device *cd, crypt_get_device_name(cd)); if (key_file) { - r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, - key_file, arg_keyfile_size, - arg_keyfile_offset, flags); + r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags); if (r < 0) { log_error_errno(r, "Failed to activate with key file '%s': %m", key_file); return -EAGAIN; @@ -631,7 +642,6 @@ int main(int argc, char *argv[]) { k = crypt_init(&cd, arg_header); } else k = crypt_init(&cd, argv[3]); - if (k) { log_error_errno(k, "crypt_init() failed: %m"); goto finish; @@ -669,7 +679,7 @@ int main(int argc, char *argv[]) { } for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) { - _cleanup_strv_free_ char **passwords = NULL; + _cleanup_strv_free_erase_ char **passwords = NULL; if (!key_file) { k = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords); diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c index 7bbec5467e..6861a592fe 100644 --- a/src/dbus1-generator/dbus1-generator.c +++ b/src/dbus1-generator/dbus1-generator.c @@ -19,14 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "cgroup-util.h" #include "conf-parser.h" -#include "special.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" #include "mkdir.h" -#include "bus-util.h" -#include "bus-internal.h" +#include "special.h" #include "unit-name.h" -#include "cgroup-util.h" +#include "util.h" static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp"; @@ -223,8 +227,7 @@ static int parse_dbus_fragments(const char *path, const char *type) { if (errno == -ENOENT) return 0; - log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m"); - return -errno; + return log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m"); } r = 0; @@ -242,8 +245,7 @@ static int parse_dbus_fragments(const char *path, const char *type) { return r; fail: - log_error_errno(errno, "Failed to read D-Bus services directory: %m"); - return -errno; + return log_error_errno(errno, "Failed to read D-Bus services directory: %m"); } static int link_busnames_target(const char *units) { diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c index 8b29e8fd09..413cfd0388 100644 --- a/src/debug-generator/debug-generator.c +++ b/src/debug-generator/debug-generator.c @@ -19,11 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" -#include "mkdir.h" +#include "util.h" +static char *arg_default_unit = NULL; static const char *arg_dest = "/tmp"; static char **arg_mask = NULL; static char **arg_wants = NULL; @@ -76,6 +82,24 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { arg_debug_shell = r; } else arg_debug_shell = true; + } else if (streq(key, "systemd.unit")) { + + if (!value) + log_error("Missing argument for systemd.unit= kernel command line parameter."); + else { + r = free_and_strdup(&arg_default_unit, value); + if (r < 0) + return log_error_errno(r, "Failed to set default unit %s: %m", value); + } + } else if (!value) { + const char *target; + + target = runlevel_to_target(key); + if (target) { + r = free_and_strdup(&arg_default_unit, target); + if (r < 0) + return log_error_errno(r, "Failed to set default unit %s: %m", target); + } } return 0; @@ -114,7 +138,7 @@ static int generate_wants_symlinks(void) { STRV_FOREACH(u, arg_wants) { _cleanup_free_ char *p = NULL, *f = NULL; - p = strjoin(arg_dest, "/default.target.wants/", *u, NULL); + p = strjoin(arg_dest, "/", arg_default_unit, ".wants/", *u, NULL); if (!p) return log_oom(); @@ -150,6 +174,12 @@ int main(int argc, char *argv[]) { umask(0022); + r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); + if (r < 0) { + log_error_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET); + goto finish; + } + r = parse_proc_cmdline(parse_proc_cmdline_item); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/delta/delta.c b/src/delta/delta.c index 4edafc7cdf..8bf678c28f 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -26,12 +26,20 @@ #include <sys/prctl.h> #include <unistd.h> +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "hashmap.h" +#include "locale-util.h" #include "log.h" #include "pager.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "signal-util.h" +#include "stat-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "util.h" @@ -311,8 +319,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open %s: %m", path); - return -errno; + return log_error_errno(errno, "Failed to open %s: %m", path); } for (;;) { diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c index dcf4e9749e..0a256c29be 100644 --- a/src/detect-virt/detect-virt.c +++ b/src/detect-virt/detect-virt.c @@ -31,7 +31,8 @@ static bool arg_quiet = false; static enum { ANY_VIRTUALIZATION, ONLY_VM, - ONLY_CONTAINER + ONLY_CONTAINER, + ONLY_CHROOT, } arg_mode = ANY_VIRTUALIZATION; static void help(void) { @@ -41,6 +42,7 @@ static void help(void) { " --version Show package version\n" " -c --container Only detect whether we are run in a container\n" " -v --vm Only detect whether we are run in a VM\n" + " -r --chroot Detect whether we are run in a chroot() environment\n" " -q --quiet Don't output anything, just set return value\n" , program_invocation_short_name); } @@ -55,7 +57,8 @@ static int parse_argv(int argc, char *argv[]) { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "container", no_argument, NULL, 'c' }, - { "vm", optional_argument, NULL, 'v' }, + { "vm", no_argument, NULL, 'v' }, + { "chroot", no_argument, NULL, 'r' }, { "quiet", no_argument, NULL, 'q' }, {} }; @@ -65,7 +68,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hqcvr", options, NULL)) >= 0) switch (c) { @@ -88,6 +91,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = ONLY_VM; break; + case 'r': + arg_mode = ONLY_CHROOT; + break; + case '?': return -EINVAL; @@ -137,6 +144,15 @@ int main(int argc, char *argv[]) { break; + case ONLY_CHROOT: + r = running_in_chroot(); + if (r < 0) { + log_error_errno(r, "Failed to check for chroot() environment: %m"); + return EXIT_FAILURE; + } + + return r ? EXIT_SUCCESS : EXIT_FAILURE; + case ANY_VIRTUALIZATION: default: r = detect_virtualization(); diff --git a/src/escape/escape.c b/src/escape/escape.c index a4bfeb5df5..e857affbc4 100644 --- a/src/escape/escape.c +++ b/src/escape/escape.c @@ -23,7 +23,9 @@ #include <stdio.h> #include <stdlib.h> +#include "alloc-util.h" #include "log.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 1562ccf0d7..642d36912c 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -24,17 +24,24 @@ #include <shadow.h> #include <unistd.h> +#include "alloc-util.h" #include "ask-password-api.h" #include "copy.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "hostname-util.h" #include "locale-util.h" #include "mkdir.h" +#include "parse-util.h" #include "path-util.h" #include "random-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "time-util.h" +#include "umask-util.h" +#include "user-util.h" static char *arg_root = NULL; static char *arg_locale = NULL; /* $LANG */ @@ -51,15 +58,6 @@ static bool arg_copy_locale = false; static bool arg_copy_timezone = false; static bool arg_copy_root_password = false; -static void clear_string(char *x) { - - if (!x) - return; - - /* A delicious drop of snake-oil! */ - memset(x, 'x', strlen(x)); -} - static bool press_any_key(void) { char k = 0; bool need_nl = true; @@ -464,7 +462,7 @@ static int prompt_root_password(void) { msg2 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: "); for (;;) { - _cleanup_free_ char *a = NULL, *b = NULL; + _cleanup_string_free_erase_ char *a = NULL, *b = NULL; r = ask_password_tty(msg1, NULL, 0, 0, NULL, &a); if (r < 0) @@ -476,19 +474,14 @@ static int prompt_root_password(void) { } r = ask_password_tty(msg2, NULL, 0, 0, NULL, &b); - if (r < 0) { - clear_string(a); + if (r < 0) return log_error_errno(r, "Failed to query root password: %m"); - } if (!streq(a, b)) { log_error("Entered passwords did not match, please try again."); - clear_string(a); - clear_string(b); continue; } - clear_string(b); arg_root_password = a; a = NULL; break; @@ -547,7 +540,7 @@ static int process_root_password(void) { mkdir_parents(etc_shadow, 0755); - lock = take_password_lock(arg_root); + lock = take_etc_passwd_lock(arg_root); if (lock < 0) return lock; @@ -561,8 +554,7 @@ static int process_root_password(void) { if (!errno) errno = EIO; - log_error_errno(errno, "Failed to find shadow entry for root: %m"); - return -errno; + return log_error_errno(errno, "Failed to find shadow entry for root: %m"); } r = write_root_shadow(etc_shadow, p); @@ -597,10 +589,9 @@ static int process_root_password(void) { item.sp_pwdp = crypt(arg_root_password, salt); if (!item.sp_pwdp) { if (!errno) - errno = -EINVAL; + errno = EINVAL; - log_error_errno(errno, "Failed to encrypt password: %m"); - return -errno; + return log_error_errno(errno, "Failed to encrypt password: %m"); } item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); @@ -704,16 +695,9 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_ROOT: - free(arg_root); - arg_root = path_make_absolute_cwd(optarg); - if (!arg_root) - return log_oom(); - - path_kill_slashes(arg_root); - - if (path_equal(arg_root, "/")) - arg_root = mfree(arg_root); - + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case ARG_LOCALE: @@ -881,7 +865,7 @@ finish: free(arg_locale_messages); free(arg_timezone); free(arg_hostname); - clear_string(arg_root_password); + string_erase(arg_root_password); free(arg_root_password); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 30c846f01d..5b806a1e69 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -32,16 +32,22 @@ #include "sd-bus.h" #include "sd-device.h" -#include "util.h" -#include "process-util.h" -#include "signal-util.h" -#include "special.h" -#include "bus-util.h" -#include "bus-error.h" +#include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-error.h" +#include "bus-util.h" #include "device-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "parse-util.h" #include "path-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "signal-util.h" #include "socket-util.h" +#include "special.h" +#include "stdio-util.h" +#include "util.h" /* exit codes as defined in fsck(8) */ enum { @@ -366,12 +372,12 @@ int main(int argc, char *argv[]) { r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type); if (r >= 0) { r = fsck_exists(type); - if (r == -ENOENT) { - log_info("fsck.%s doesn't exist, not checking file system on %s", type, device); - r = 0; + if (r < 0) + log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s, proceeding: %m", type, device); + else if (r == 0) { + log_info("fsck.%s doesn't exist, not checking file system on %s.", type, device); goto finish; - } else if (r < 0) - log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s: %m", type, device); + } } if (arg_show_progress) { diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 3f8ea5647c..f7c8d11ace 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -19,22 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <mntent.h> #include <errno.h> +#include <mntent.h> +#include <stdio.h> #include <string.h> #include <unistd.h> -#include "log.h" -#include "util.h" -#include "unit-name.h" -#include "path-util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "fstab-util.h" +#include "generator.h" +#include "log.h" +#include "mkdir.h" #include "mount-setup.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "special.h" -#include "mkdir.h" -#include "generator.h" +#include "stat-util.h" +#include "string-util.h" #include "strv.h" +#include "unit-name.h" +#include "util.h" #include "virt.h" static const char *arg_dest = "/tmp"; diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c index 9a4b038ef3..03df7365b5 100644 --- a/src/getty-generator/getty-generator.c +++ b/src/getty-generator/getty-generator.c @@ -19,20 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> -#include <unistd.h> #include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "log.h" -#include "util.h" #include "mkdir.h" -#include "unit-name.h" -#include "virt.h" -#include "fileio.h" #include "path-util.h" #include "process-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "unit-name.h" +#include "util.h" +#include "virt.h" static const char *arg_dest = "/tmp"; diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 96425c5b07..34852ce381 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -24,23 +24,32 @@ #include <sys/statfs.h> #include <blkid/blkid.h> -#include "sd-id128.h" #include "libudev.h" -#include "path-util.h" -#include "util.h" -#include "mkdir.h" +#include "sd-id128.h" + +#include "alloc-util.h" +#include "blkid-util.h" +#include "btrfs-util.h" +#include "dirent-util.h" +#include "efivars.h" +#include "fd-util.h" +#include "fileio.h" +#include "fstab-util.h" +#include "generator.h" +#include "gpt.h" #include "missing.h" -#include "udev-util.h" +#include "mkdir.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "special.h" +#include "stat-util.h" +#include "string-util.h" +#include "udev-util.h" #include "unit-name.h" +#include "util.h" #include "virt.h" -#include "generator.h" -#include "gpt.h" -#include "fileio.h" -#include "efivars.h" -#include "fstab-util.h" -#include "blkid-util.h" -#include "btrfs-util.h" static const char *arg_dest = "/tmp"; static bool arg_enabled = true; @@ -293,8 +302,7 @@ static int probe_and_add_mount( if (!b) { if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to allocate prober: %m"); - return -errno; + return log_error_errno(errno, "Failed to allocate prober: %m"); } blkid_probe_enable_superblocks(b, 1); @@ -493,8 +501,7 @@ static int add_boot(const char *what) { if (!b) { if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to allocate prober: %m"); - return -errno; + return log_error_errno(errno, "Failed to allocate prober: %m"); } blkid_probe_enable_partitions(b, 1); diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index 9fb6233336..da719f2a30 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -19,14 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> +#include <stdio.h> +#include "alloc-util.h" +#include "fstab-util.h" #include "log.h" -#include "util.h" -#include "special.h" #include "mkdir.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" #include "unit-name.h" +#include "util.h" static const char *arg_dest = "/tmp"; static char *arg_resume_dev = NULL; diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index 1f3b169905..316a2803d3 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -23,9 +23,10 @@ #include <errno.h> #include <sys/stat.h> +#include "alloc-util.h" +#include "fileio.h" #include "log.h" #include "util.h" -#include "fileio.h" int main(int argc, char *argv[]) { struct stat st; diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 0724fcc16d..bf09fb8fbb 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -28,6 +28,7 @@ #include "sd-bus.h" #include "sd-id128.h" +#include "alloc-util.h" #include "architecture.h" #include "bus-error.h" #include "bus-util.h" diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index dd508aefb5..92061532b8 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -24,16 +24,20 @@ #include <unistd.h> #include <sys/utsname.h> -#include "util.h" -#include "strv.h" +#include "alloc-util.h" +#include "bus-util.h" #include "def.h" -#include "virt.h" #include "env-util.h" -#include "fileio-label.h" -#include "bus-util.h" #include "event-util.h" -#include "selinux-util.h" +#include "fileio-label.h" #include "hostname-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "selinux-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" +#include "virt.h" #define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:") diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 1e415db845..de59b797a6 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -22,11 +22,16 @@ #include <stdlib.h> #include <string.h> +#include "alloc-util.h" #include "conf-files.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "hwdb-internal.h" #include "hwdb-util.h" #include "mkdir.h" #include "strbuf.h" +#include "string-util.h" #include "strv.h" #include "util.h" #include "verbs.h" diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c index 18c42b8b6d..7b1ac134a0 100644 --- a/src/import/aufs-util.c +++ b/src/import/aufs-util.c @@ -21,8 +21,9 @@ #include <ftw.h> -#include "util.h" #include "rm-rf.h" +#include "string-util.h" +#include "util.h" #include "aufs-util.h" static int nftw_cb( diff --git a/src/import/curl-util.c b/src/import/curl-util.c index d390cfb1f3..4278466df1 100644 --- a/src/import/curl-util.c +++ b/src/import/curl-util.c @@ -19,7 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "curl-util.h" +#include "fd-util.h" +#include "string-util.h" static void curl_glue_check_finished(CurlGlue *g) { CURLMsg *msg; diff --git a/src/import/curl-util.h b/src/import/curl-util.h index c249069ffa..6a2aa81c76 100644 --- a/src/import/curl-util.h +++ b/src/import/curl-util.h @@ -24,9 +24,10 @@ #include <sys/types.h> #include <curl/curl.h> -#include "hashmap.h" #include "sd-event.h" +#include "hashmap.h" + typedef struct CurlGlue CurlGlue; struct CurlGlue { diff --git a/src/import/export-raw.c b/src/import/export-raw.c index 8f9c9bbc80..103d45bf21 100644 --- a/src/import/export-raw.c +++ b/src/import/export-raw.c @@ -24,12 +24,17 @@ #undef basename #include "sd-daemon.h" -#include "util.h" -#include "ratelimit.h" + +#include "alloc-util.h" #include "btrfs-util.h" #include "copy.h" -#include "import-common.h" #include "export-raw.h" +#include "fd-util.h" +#include "fileio.h" +#include "import-common.h" +#include "ratelimit.h" +#include "string-util.h" +#include "util.h" #define COPY_BUFFER_SIZE (16*1024) diff --git a/src/import/export-tar.c b/src/import/export-tar.c index 43fa9d1b03..2bbec661e6 100644 --- a/src/import/export-tar.c +++ b/src/import/export-tar.c @@ -19,15 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/sendfile.h> - #include "sd-daemon.h" -#include "util.h" -#include "ratelimit.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "import-common.h" #include "export-tar.h" +#include "fd-util.h" +#include "fileio.h" +#include "import-common.h" #include "process-util.h" +#include "ratelimit.h" +#include "string-util.h" +#include "util.h" #define COPY_BUFFER_SIZE (16*1024) @@ -78,7 +81,7 @@ TarExport *tar_export_unref(TarExport *e) { } if (e->temp_path) { - (void) btrfs_subvol_remove(e->temp_path, false); + (void) btrfs_subvol_remove(e->temp_path, BTRFS_REMOVE_QUOTA); free(e->temp_path); } @@ -283,7 +286,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */ BtrfsQuotaInfo q; - r = btrfs_subvol_get_quota_fd(sfd, &q); + r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q); if (r >= 0) e->quota_referenced = q.referenced; diff --git a/src/import/export.c b/src/import/export.c index d34105e4ca..2b33d778d3 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -23,13 +23,17 @@ #include "sd-event.h" +#include "alloc-util.h" #include "event-util.h" #include "export-raw.h" #include "export-tar.h" +#include "fd-util.h" +#include "fs-util.h" #include "hostname-util.h" #include "import-util.h" #include "machine-image.h" #include "signal-util.h" +#include "string-util.h" #include "verbs.h" static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN; diff --git a/src/import/import-common.c b/src/import/import-common.c index 9b86dbfa79..a8551ca9e8 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -25,10 +25,11 @@ #include <unistd.h> #include "btrfs-util.h" -#include "capability.h" +#include "capability-util.h" +#include "fd-util.h" +#include "import-common.h" #include "signal-util.h" #include "util.h" -#include "import-common.h" int import_make_read_only_fd(int fd) { int r; diff --git a/src/import/import-compress.c b/src/import/import-compress.c index d6b8133036..d4ff178f60 100644 --- a/src/import/import-compress.c +++ b/src/import/import-compress.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "import-compress.h" +#include "string-table.h" +#include "util.h" void import_compress_free(ImportCompress *c) { assert(c); diff --git a/src/import/import-raw.c b/src/import/import-raw.c index 5f7d25d063..7593f064fc 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -23,19 +23,27 @@ #include "sd-daemon.h" #include "sd-event.h" -#include "util.h" -#include "path-util.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "hostname-util.h" +#include "chattr-util.h" #include "copy.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "ratelimit.h" -#include "machine-pool.h" -#include "qcow2-util.h" -#include "import-compress.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" #include "import-common.h" +#include "import-compress.h" #include "import-raw.h" +#include "io-util.h" +#include "machine-pool.h" +#include "mkdir.h" +#include "path-util.h" +#include "qcow2-util.h" +#include "ratelimit.h" +#include "rm-rf.h" +#include "string-util.h" +#include "util.h" struct RawImport { sd_event *event; @@ -191,7 +199,7 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) { r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", t); + log_warning_errno(r, "Failed to set file attributes on %s: %m", t); log_info("Unpacking QCOW2 file."); @@ -279,7 +287,7 @@ static int raw_import_open_disk(RawImport *i) { r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path); + log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path); return 0; } diff --git a/src/import/import-tar.c b/src/import/import-tar.c index d2bfb30238..c7983c04be 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -23,20 +23,27 @@ #include "sd-daemon.h" #include "sd-event.h" -#include "util.h" -#include "path-util.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "hostname-util.h" #include "copy.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "ratelimit.h" -#include "machine-pool.h" -#include "qcow2-util.h" -#include "import-compress.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" #include "import-common.h" +#include "import-compress.h" #include "import-tar.h" +#include "io-util.h" +#include "machine-pool.h" +#include "mkdir.h" +#include "path-util.h" #include "process-util.h" +#include "qcow2-util.h" +#include "ratelimit.h" +#include "rm-rf.h" +#include "string-util.h" +#include "util.h" struct TarImport { sd_event *event; @@ -234,7 +241,9 @@ static int tar_import_fork_tar(TarImport *i) { if (mkdir(i->temp_path, 0755) < 0) return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path); } else if (r < 0) - return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path); + return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path); + else + (void) import_assign_pool_quota_and_warn(i->temp_path); i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (i->tar_fd < 0) diff --git a/src/import/import.c b/src/import/import.c index 1c92312585..018b94d4c4 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -23,13 +23,17 @@ #include "sd-event.h" +#include "alloc-util.h" #include "event-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "hostname-util.h" #include "import-raw.h" #include "import-tar.h" #include "import-util.h" #include "machine-image.h" #include "signal-util.h" +#include "string-util.h" #include "verbs.h" static bool arg_force = false; diff --git a/src/import/importd.c b/src/import/importd.c index a29e9d4bd5..4228681cea 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -22,20 +22,28 @@ #include <sys/prctl.h> #include "sd-bus.h" -#include "util.h" -#include "strv.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-common-errors.h" -#include "socket-util.h" -#include "mkdir.h" +#include "bus-util.h" #include "def.h" -#include "missing.h" +#include "fd-util.h" +#include "hostname-util.h" +#include "import-util.h" #include "machine-pool.h" +#include "missing.h" +#include "mkdir.h" +#include "parse-util.h" #include "path-util.h" -#include "import-util.h" #include "process-util.h" #include "signal-util.h" -#include "hostname-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "strv.h" +#include "syslog-util.h" +#include "user-util.h" +#include "util.h" +#include "web-util.h" typedef struct Transfer Transfer; typedef struct Manager Manager; diff --git a/src/import/pull-common.c b/src/import/pull-common.c index 1ddb48e03f..d6567ba7ee 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -21,17 +21,25 @@ #include <sys/prctl.h> -#include "util.h" -#include "strv.h" -#include "copy.h" -#include "rm-rf.h" +#include "alloc-util.h" #include "btrfs-util.h" -#include "capability.h" -#include "pull-job.h" -#include "pull-common.h" +#include "capability-util.h" +#include "copy.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" +#include "io-util.h" +#include "path-util.h" #include "process-util.h" +#include "pull-common.h" +#include "pull-job.h" +#include "rm-rf.h" #include "signal-util.h" #include "siphash24.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" +#include "web-util.h" #define FILENAME_ESCAPE "/.#\"\'" #define HASH_URL_THRESHOLD_LENGTH (_POSIX_PATH_MAX - 16) @@ -138,7 +146,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char * if (force_local) (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - r = btrfs_subvol_snapshot(final, p, 0); + r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA); if (r == -ENOTTY) { r = copy_tree(final, p, false); if (r < 0) @@ -366,9 +374,10 @@ int pull_verify(PullJob *main_job, log_info("SHA256 checksum of %s is valid.", main_job->url); - assert(!settings_job || settings_job->state == PULL_JOB_DONE); + assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED)); if (settings_job && + settings_job->state == PULL_JOB_DONE && settings_job->error == 0 && !settings_job->etag_exists) { diff --git a/src/import/pull-dkr.c b/src/import/pull-dkr.c index 0dab184af1..831470ff13 100644 --- a/src/import/pull-dkr.c +++ b/src/import/pull-dkr.c @@ -23,22 +23,29 @@ #include <sys/prctl.h> #include "sd-daemon.h" -#include "json.h" -#include "strv.h" + +#include "alloc-util.h" +#include "aufs-util.h" #include "btrfs-util.h" -#include "utf8.h" +#include "curl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" +#include "import-common.h" +#include "import-util.h" +#include "json.h" #include "mkdir.h" -#include "rm-rf.h" #include "path-util.h" -#include "import-util.h" -#include "curl-util.h" -#include "aufs-util.h" -#include "pull-job.h" +#include "process-util.h" #include "pull-common.h" -#include "import-common.h" #include "pull-dkr.h" -#include "process-util.h" -#include "hostname-util.h" +#include "pull-job.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "web-util.h" typedef enum DkrProgress { DKR_SEARCHING, @@ -476,13 +483,13 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) { if (!i->final_path) { i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL); if (!i->final_path) - return log_oom(); + return -ENOMEM; } if (version == DKR_PULL_V2) { - r = path_get_parent(i->image_root, &p); - if (r < 0) - return r; + p = dirname_malloc(i->image_root); + if (!p) + return -ENOMEM; } r = pull_make_local_copy(i->final_path, p ?: i->image_root, i->local, i->force_local); @@ -490,10 +497,16 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) { return r; if (version == DKR_PULL_V2) { - char **k = NULL; + char **k; + STRV_FOREACH(k, i->ancestry) { - _cleanup_free_ char *d = strjoin(i->image_root, "/.dkr-", *k, NULL); - r = btrfs_subvol_remove(d, false); + _cleanup_free_ char *d; + + d = strjoin(i->image_root, "/.dkr-", *k, NULL); + if (!d) + return -ENOMEM; + + r = btrfs_subvol_remove(d, BTRFS_REMOVE_QUOTA); if (r < 0) return r; } @@ -531,12 +544,14 @@ static int dkr_pull_job_on_open_disk(PullJob *j) { const char *base_path; base_path = strjoina(i->image_root, "/.dkr-", base); - r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY); + r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_QUOTA); } else r = btrfs_subvol_make(i->temp_path); if (r < 0) return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path); + (void) import_assign_pool_quota_and_warn(i->temp_path); + j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (j->disk_fd < 0) return j->disk_fd; diff --git a/src/import/pull-job.c b/src/import/pull-job.c index 42939f2104..824fa246ec 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -21,9 +21,16 @@ #include <sys/xattr.h> -#include "strv.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "hexdecoct.h" +#include "io-util.h" #include "machine-pool.h" +#include "parse-util.h" #include "pull-job.h" +#include "string-util.h" +#include "strv.h" +#include "xattr-util.h" PullJob* pull_job_unref(PullJob *j) { if (!j) diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 0e77197e34..03bfb51756 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -19,28 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/xattr.h> -#include <linux/fs.h> #include <curl/curl.h> +#include <linux/fs.h> +#include <sys/xattr.h> #include "sd-daemon.h" -#include "utf8.h" -#include "strv.h" -#include "copy.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "util.h" +#include "chattr-util.h" +#include "copy.h" +#include "curl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" +#include "import-common.h" +#include "import-util.h" #include "macro.h" #include "mkdir.h" -#include "rm-rf.h" #include "path-util.h" -#include "hostname-util.h" -#include "import-util.h" -#include "import-common.h" -#include "curl-util.h" -#include "qcow2-util.h" -#include "pull-job.h" #include "pull-common.h" +#include "pull-job.h" #include "pull-raw.h" +#include "qcow2-util.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "util.h" +#include "web-util.h" typedef enum RawProgress { RAW_DOWNLOADING, @@ -236,7 +244,7 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) { r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", t); + log_warning_errno(r, "Failed to set file attributes on %s: %m", t); log_info("Unpacking QCOW2 file."); @@ -312,7 +320,7 @@ static int raw_pull_make_local_copy(RawPull *i) { * writes. */ r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", tp); + log_warning_errno(r, "Failed to set file attributes on %s: %m", tp); r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, true); if (r < 0) { @@ -327,8 +335,9 @@ static int raw_pull_make_local_copy(RawPull *i) { r = rename(tp, p); if (r < 0) { + r = log_error_errno(errno, "Failed to move writable image into place: %m"); unlink(tp); - return log_error_errno(errno, "Failed to move writable image into place: %m"); + return r; } log_info("Created new local image '%s'.", i->local); @@ -349,9 +358,9 @@ static int raw_pull_make_local_copy(RawPull *i) { if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); else if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings); - - log_info("Create new settings file '%s.nspawn'", i->local); + log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); + else + log_info("Created new settings file '%s.nspawn'", i->local); } return 0; @@ -503,7 +512,7 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) { r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path); + log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path); return 0; } diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 563765d83d..e7fcd293f1 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -23,23 +23,30 @@ #include <curl/curl.h> #include "sd-daemon.h" -#include "utf8.h" -#include "strv.h" -#include "copy.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "util.h" +#include "copy.h" +#include "curl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" +#include "import-common.h" +#include "import-util.h" #include "macro.h" #include "mkdir.h" -#include "rm-rf.h" #include "path-util.h" #include "process-util.h" -#include "hostname-util.h" -#include "import-util.h" -#include "import-common.h" -#include "curl-util.h" -#include "pull-job.h" #include "pull-common.h" +#include "pull-job.h" #include "pull-tar.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "util.h" +#include "web-util.h" typedef enum TarProgress { TAR_DOWNLOADING, @@ -247,9 +254,9 @@ static int tar_pull_make_local_copy(TarPull *i) { if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); else if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings); - - log_info("Create new settings file '%s.nspawn'", i->local); + log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); + else + log_info("Created new settings file '%s.nspawn'", i->local); } return 0; @@ -409,7 +416,9 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) { if (mkdir(i->temp_path, 0755) < 0) return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path); } else if (r < 0) - return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path); + return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path); + else + (void) import_assign_pool_quota_and_warn(i->temp_path); j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (j->disk_fd < 0) diff --git a/src/import/pull.c b/src/import/pull.c index 29e9424b52..39f5b2d8e4 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -23,15 +23,19 @@ #include "sd-event.h" +#include "alloc-util.h" #include "event-util.h" #include "hostname-util.h" #include "import-util.h" #include "machine-image.h" +#include "parse-util.h" #include "pull-dkr.h" #include "pull-raw.h" #include "pull-tar.h" #include "signal-util.h" +#include "string-util.h" #include "verbs.h" +#include "web-util.h" static bool arg_force = false; static const char *arg_image_root = "/var/lib/machines"; diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c index fd3cf1b0e3..47dabaa86e 100644 --- a/src/import/qcow2-util.c +++ b/src/import/qcow2-util.c @@ -21,10 +21,11 @@ #include <zlib.h> -#include "util.h" -#include "sparse-endian.h" -#include "qcow2-util.h" +#include "alloc-util.h" #include "btrfs-util.h" +#include "qcow2-util.h" +#include "sparse-endian.h" +#include "util.h" #define QCOW2_MAGIC 0x514649fb diff --git a/src/import/test-qcow2.c b/src/import/test-qcow2.c index 9a6c3e8b35..4b60079619 100644 --- a/src/import/test-qcow2.c +++ b/src/import/test-qcow2.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "fd-util.h" #include "log.h" -#include "util.h" - #include "qcow2-util.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int sfd = -1, dfd = -1; diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index 2d5f7501e7..d4f8673187 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -25,18 +25,20 @@ #include <sys/epoll.h> #include <ctype.h> -#include "sd-daemon.h" #include "sd-bus.h" +#include "sd-daemon.h" -#include "util.h" -#include "log.h" -#include "list.h" -#include "initreq.h" -#include "special.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" +#include "bus-util.h" #include "def.h" +#include "fd-util.h" #include "formats-util.h" +#include "initreq.h" +#include "list.h" +#include "log.h" +#include "special.h" +#include "util.h" #define SERVER_FD_MAX 16 #define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) @@ -210,8 +212,7 @@ static int fifo_process(Fifo *f) { if (errno == EAGAIN) return 0; - log_warning_errno(errno, "Failed to read from fifo: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read from fifo: %m"); } f->bytes_read += l; diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index b839e5979b..6b93a758f6 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -19,26 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <string.h> -#include <unistd.h> #include <fcntl.h> #include <getopt.h> -#include <microhttpd.h> #ifdef HAVE_GNUTLS #include <gnutls/gnutls.h> #endif +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> -#include "sd-journal.h" -#include "sd-daemon.h" #include "sd-bus.h" +#include "sd-daemon.h" +#include "sd-journal.h" +#include "alloc-util.h" #include "bus-util.h" +#include "fd-util.h" #include "fileio.h" #include "hostname-util.h" #include "log.h" #include "logs-show.h" #include "microhttpd-util.h" +#include "parse-util.h" #include "sigbus.h" #include "util.h" diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c index 2e0f78701a..3ff40228a0 100644 --- a/src/journal-remote/journal-remote-parse.c +++ b/src/journal-remote/journal-remote-parse.c @@ -19,8 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "fd-util.h" #include "journal-remote-parse.h" #include "journald-native.h" +#include "parse-util.h" +#include "string-util.h" #define LINE_CHUNK 8*1024u diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index 40f4ff8e58..d8250378b0 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "journal-remote.h" int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) { diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index c920ef7626..b2f5fbf6b4 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -35,16 +35,25 @@ #include "sd-daemon.h" +#include "alloc-util.h" #include "conf-parser.h" +#include "def.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" #include "journal-file.h" +#include "journal-remote-write.h" +#include "journal-remote.h" #include "journald-native.h" #include "macro.h" +#include "parse-util.h" #include "signal-util.h" #include "socket-util.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" -#include "journal-remote-write.h" -#include "journal-remote.h" #define REMOTE_JOURNAL_PATH "/var/log/journal/remote" @@ -137,7 +146,7 @@ static int spawn_curl(const char* url) { r = spawn_child("curl", argv); if (r < 0) - log_error_errno(errno, "Failed to spawn curl: %m"); + log_error_errno(r, "Failed to spawn curl: %m"); return r; } @@ -156,7 +165,7 @@ static int spawn_getter(const char *getter, const char *url) { r = spawn_child(words[0], words); if (r < 0) - log_error_errno(errno, "Failed to spawn getter %s: %m", getter); + log_error_errno(r, "Failed to spawn getter %s: %m", getter); return r; } @@ -640,11 +649,12 @@ static int setup_microhttpd_server(RemoteServer *s, { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free}, { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger}, { MHD_OPTION_LISTEN_SOCKET, fd}, + { MHD_OPTION_CONNECTION_MEMORY_LIMIT, DATA_SIZE_MAX}, { MHD_OPTION_END}, { MHD_OPTION_END}, { MHD_OPTION_END}, { MHD_OPTION_END}}; - int opts_pos = 3; + int opts_pos = 4; int flags = MHD_USE_DEBUG | MHD_USE_DUAL_STACK | @@ -1178,7 +1188,7 @@ static int parse_config(void) { {}}; return config_parse_many(PKGSYSCONFDIR "/journal-remote.conf", - CONF_DIRS_NULSTR("systemd/journal-remote.conf"), + CONF_PATHS_NULSTR("systemd/journal-remote.conf.d"), "Remote\0", config_item_table_lookup, items, false, NULL); } @@ -1407,18 +1417,21 @@ static int parse_argv(int argc, char *argv[]) { case ARG_GNUTLS_LOG: { #ifdef HAVE_GNUTLS - const char *word, *state; - size_t size; + const char* p = optarg; + for (;;) { + _cleanup_free_ char *word = NULL; - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { - char *cat; + r = extract_first_word(&p, &word, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse --gnutls-log= argument: %m"); - cat = strndup(word, size); - if (!cat) - return log_oom(); + if (r == 0) + break; - if (strv_consume(&arg_gnutls_log, cat) < 0) + if (strv_push(&arg_gnutls_log, word) < 0) return log_oom(); + + word = NULL; } break; #else diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index 6b3ad924a7..3ee6d32bf7 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -1,11 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Zbigniew JÄ™drzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + #include <stdbool.h> #include <curl/curl.h> -#include "util.h" +#include "alloc-util.h" +#include "journal-upload.h" #include "log.h" #include "utf8.h" -#include "journal-upload.h" +#include "util.h" /** * Write up to size bytes to buf. Return negative on error, and number of diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 92ce56805a..6302266ccb 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -19,23 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <curl/curl.h> #include <fcntl.h> #include <getopt.h> #include <stdio.h> #include <sys/stat.h> -#include <curl/curl.h> #include "sd-daemon.h" +#include "alloc-util.h" #include "conf-parser.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "glob-util.h" +#include "journal-upload.h" #include "log.h" #include "mkdir.h" +#include "parse-util.h" #include "sigbus.h" #include "signal-util.h" +#include "string-util.h" #include "util.h" -#include "journal-upload.h" #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem" #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-upload.pem" @@ -536,7 +542,7 @@ static int parse_config(void) { {}}; return config_parse_many(PKGSYSCONFDIR "/journal-upload.conf", - CONF_DIRS_NULSTR("systemd/journal-upload.conf"), + CONF_PATHS_NULSTR("systemd/journal-upload.conf.d"), "Upload\0", config_item_table_lookup, items, false, NULL); } diff --git a/src/journal-remote/log-generator.py b/src/journal-remote/log-generator.py index 9a8fb07c7f..fd6964e758 100755 --- a/src/journal-remote/log-generator.py +++ b/src/journal-remote/log-generator.py @@ -6,6 +6,8 @@ import argparse PARSER = argparse.ArgumentParser() PARSER.add_argument('n', type=int) PARSER.add_argument('--dots', action='store_true') +PARSER.add_argument('--data-size', type=int, default=4000) +PARSER.add_argument('--data-type', choices={'random', 'simple'}) OPTIONS = PARSER.parse_args() template = """\ @@ -38,10 +40,16 @@ facility = 6 src = open('/dev/urandom', 'rb') bytes = 0 +counter = 0 for i in range(OPTIONS.n): message = repr(src.read(2000)) - data = repr(src.read(4000)) + if OPTIONS.data_type == 'random': + data = repr(src.read(OPTIONS.data_size)) + else: + # keep the pattern non-repeating so we get a different blob every time + data = '{:0{}}'.format(counter, OPTIONS.data_size) + counter += 1 entry = template.format(m=m, realtime_ts=realtime_ts, diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index 8a11fba044..b2c398a845 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -24,17 +24,19 @@ #include <stdio.h> #include <string.h> -#include "microhttpd-util.h" -#include "log.h" -#include "macro.h" -#include "util.h" -#include "strv.h" - #ifdef HAVE_GNUTLS #include <gnutls/gnutls.h> #include <gnutls/x509.h> #endif +#include "alloc-util.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" +#include "microhttpd-util.h" + void microhttpd_logger(void *arg, const char *fmt, va_list ap) { char *f; diff --git a/src/journal/cat.c b/src/journal/cat.c index f9b279d7de..7fd4198df8 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -28,6 +28,10 @@ #include "sd-journal.h" +#include "fd-util.h" +#include "parse-util.h" +#include "string-util.h" +#include "syslog-util.h" #include "util.h" static char *arg_identifier = NULL; diff --git a/src/journal/catalog.c b/src/journal/catalog.c index 4c43500ef5..fcaa54aa0c 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -19,25 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> #include <fcntl.h> +#include <locale.h> #include <stdio.h> -#include <unistd.h> -#include <errno.h> #include <string.h> #include <sys/mman.h> -#include <locale.h> +#include <unistd.h> -#include "util.h" -#include "log.h" -#include "sparse-endian.h" #include "sd-id128.h" -#include "hashmap.h" -#include "strv.h" -#include "strbuf.h" + +#include "alloc-util.h" +#include "catalog.h" #include "conf-files.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "log.h" #include "mkdir.h" -#include "catalog.h" +#include "path-util.h" #include "siphash24.h" +#include "sparse-endian.h" +#include "strbuf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" const char * const catalog_file_dirs[] = { "/usr/local/lib/systemd/catalog/", @@ -202,7 +208,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { r = catalog_file_lang(path, &deflang); if (r < 0) - log_error_errno(errno, "Failed to determine language for file %s: %m", path); + log_error_errno(r, "Failed to determine language for file %s: %m", path); if (r == 1) log_debug("File %s has language %s.", path, deflang); @@ -215,8 +221,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { if (feof(f)) break; - log_error_errno(errno, "Failed to read file %s: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file %s: %m", path); } n++; @@ -313,8 +318,8 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { return 0; } -static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb, - CatalogItem *items, size_t n) { +static int64_t write_catalog(const char *database, struct strbuf *sb, + CatalogItem *items, size_t n) { CatalogHeader header; _cleanup_fclose_ FILE *w = NULL; int r; @@ -338,7 +343,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb, memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature)); header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8)); header.catalog_item_size = htole64(sizeof(CatalogItem)); - header.n_items = htole64(hashmap_size(h)); + header.n_items = htole64(n); r = -EIO; @@ -373,7 +378,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb, goto error; } - return ftell(w); + return ftello(w); error: (void) unlink(p); @@ -389,7 +394,8 @@ int catalog_update(const char* database, const char* root, const char* const* di CatalogItem *i; Iterator j; unsigned n; - long r; + int r; + int64_t sz; h = hashmap_new(&catalog_hash_ops); sb = strbuf_new(); @@ -439,18 +445,19 @@ int catalog_update(const char* database, const char* root, const char* const* di assert(n == hashmap_size(h)); qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func); - r = write_catalog(database, h, sb, items, n); - if (r < 0) - log_error_errno(r, "Failed to write %s: %m", database); - else - log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.", - database, n, sb->len, r); + sz = write_catalog(database, sb, items, n); + if (sz < 0) + r = log_error_errno(sz, "Failed to write %s: %m", database); + else { + r = 0; + log_debug("%s: wrote %u items, with %zu bytes of strings, %"PRIi64" total size.", + database, n, sb->len, sz); + } finish: - if (sb) - strbuf_cleanup(sb); + strbuf_cleanup(sb); - return r < 0 ? r : 0; + return r; } static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) { diff --git a/src/journal/compress.c b/src/journal/compress.c index c66043e503..e1ca0a8818 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -21,21 +21,33 @@ #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <unistd.h> #ifdef HAVE_XZ -# include <lzma.h> +#include <lzma.h> #endif #ifdef HAVE_LZ4 -# include <lz4.h> +#include <lz4.h> +#include <lz4frame.h> #endif +#include "alloc-util.h" #include "compress.h" +#include "fd-util.h" +#include "io-util.h" +#include "journal-def.h" #include "macro.h" -#include "util.h" #include "sparse-endian.h" -#include "journal-def.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" + +#ifdef HAVE_LZ4 +DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionContext); +DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext); +#endif #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t)) @@ -50,10 +62,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ #ifdef HAVE_XZ static const lzma_options_lzma opt = { 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT, - LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4}; - static const lzma_filter filters[2] = { - {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt}, - {LZMA_VLI_UNKNOWN, NULL} + LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4 + }; + static const lzma_filter filters[] = { + { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt }, + { LZMA_VLI_UNKNOWN, NULL } }; lzma_ret ret; size_t out_pos = 0; @@ -416,81 +429,96 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { #endif } -#define LZ4_BUFSIZE (512*1024) +#define LZ4_BUFSIZE (512*1024u) int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { #ifdef HAVE_LZ4 + LZ4F_errorCode_t c; + _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL; + _cleanup_free_ char *buf = NULL; + char *src = NULL; + size_t size, n, total_in = 0, total_out = 0, offset = 0, frame_size; + struct stat st; + int r; + static const LZ4F_compressOptions_t options = { + .stableSrc = 1, + }; + static const LZ4F_preferences_t preferences = { + .frameInfo.blockSizeID = 5, + }; - _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL; - char *buf; - LZ4_stream_t lz4_data = {}; - le32_t header; - size_t total_in = 0, total_out = sizeof(header); - ssize_t n; + c = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); + if (LZ4F_isError(c)) + return -ENOMEM; - assert(fdf >= 0); - assert(fdt >= 0); + if (fstat(fdf, &st) < 0) + return log_debug_errno(errno, "fstat() failed: %m"); - buf1 = malloc(LZ4_BUFSIZE); - buf2 = malloc(LZ4_BUFSIZE); - out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE)); - if (!buf1 || !buf2 || !out) - return log_oom(); + frame_size = LZ4F_compressBound(LZ4_BUFSIZE, &preferences); + size = frame_size + 64*1024; /* add some space for header and trailer */ + buf = malloc(size); + if (!buf) + return -ENOMEM; - buf = buf1; - for (;;) { - size_t m; - int r; + n = offset = LZ4F_compressBegin(ctx, buf, size, &preferences); + if (LZ4F_isError(n)) + return -EINVAL; - m = LZ4_BUFSIZE; - if (max_bytes != (uint64_t) -1 && (uint64_t) m > (max_bytes - total_in)) - m = (size_t) (max_bytes - total_in); + src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdf, 0); + if (src == MAP_FAILED) + return -errno; - n = read(fdf, buf, m); - if (n < 0) - return -errno; - if (n == 0) - break; + log_debug("Buffer size is %zu bytes, header size %zu bytes.", size, n); - total_in += n; + while (total_in < (size_t) st.st_size) { + ssize_t k; - r = LZ4_compress_continue(&lz4_data, buf, out, n); - if (r == 0) { - log_error("LZ4 compression failed."); - return -EBADMSG; + k = MIN(LZ4_BUFSIZE, st.st_size - total_in); + n = LZ4F_compressUpdate(ctx, buf + offset, size - offset, + src + total_in, k, &options); + if (LZ4F_isError(n)) { + r = -ENOTRECOVERABLE; + goto cleanup; } - header = htole32(r); - errno = 0; - - n = write(fdt, &header, sizeof(header)); - if (n < 0) - return -errno; - if (n != sizeof(header)) - return errno ? -errno : -EIO; + total_in += k; + offset += n; + total_out += n; - n = loop_write(fdt, out, r, false); - if (n < 0) - return n; + if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { + log_debug("Compressed stream longer than %zd bytes", max_bytes); + return -EFBIG; + } - total_out += sizeof(header) + r; + if (size - offset < frame_size + 4) { + k = loop_write(fdt, buf, offset, false); + if (k < 0) { + r = k; + goto cleanup; + } + offset = 0; + } + } - buf = buf == buf1 ? buf2 : buf1; + n = LZ4F_compressEnd(ctx, buf + offset, size - offset, &options); + if (LZ4F_isError(n)) { + r = -ENOTRECOVERABLE; + goto cleanup; } - header = htole32(0); - n = write(fdt, &header, sizeof(header)); - if (n < 0) - return -errno; - if (n != sizeof(header)) - return errno ? -errno : -EIO; + offset += n; + total_out += n; + r = loop_write(fdt, buf, offset, false); + if (r < 0) + goto cleanup; log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)", total_in, total_out, (double) total_out / total_in * 100); - - return 0; + cleanup: + munmap(src, st.st_size); + return r; #else return -EPROTONOSUPPORT; #endif @@ -510,7 +538,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { ret = lzma_stream_decoder(&s, UINT64_MAX, 0); if (ret != LZMA_OK) { - log_error("Failed to initialize XZ decoder: code %u", ret); + log_debug("Failed to initialize XZ decoder: code %u", ret); return -ENOMEM; } @@ -536,7 +564,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { ret = lzma_code(&s, action); if (ret != LZMA_OK && ret != LZMA_STREAM_END) { - log_error("Decompression failed: code %u", ret); + log_debug("Decompression failed: code %u", ret); return -EBADMSG; } @@ -566,14 +594,14 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { } } #else - log_error("Cannot decompress file. Compiled without XZ support."); + log_debug("Cannot decompress file. Compiled without XZ support."); return -EPROTONOSUPPORT; #endif } -int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { - #ifdef HAVE_LZ4 +static int decompress_stream_lz4_v1(int fdf, int fdt, uint64_t max_bytes) { + _cleanup_free_ char *buf = NULL, *out = NULL; size_t buf_size = 0; LZ4_streamDecode_t lz4_data = {}; @@ -585,7 +613,7 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { out = malloc(4*LZ4_BUFSIZE); if (!out) - return log_oom(); + return -ENOMEM; for (;;) { ssize_t m; @@ -606,22 +634,24 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { * not accept buffers compressed by newer binaries then. */ if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) { - log_error("Compressed stream block too big: %zd bytes", m); - return -EBADMSG; + log_debug("Compressed stream block too big: %zd bytes", m); + return -ENOBUFS; } total_in += sizeof(header) + m; if (!GREEDY_REALLOC(buf, buf_size, m)) - return log_oom(); + return -ENOMEM; r = loop_read_exact(fdf, buf, m, false); if (r < 0) return r; r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE); - if (r <= 0) - log_error("LZ4 decompression failed."); + if (r <= 0) { + log_debug("LZ4 decompression failed (legacy format)."); + return -EBADMSG; + } total_out += r; @@ -635,13 +665,80 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { return r; } - log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)", + log_debug("LZ4 decompression finished (legacy format, %zu -> %zu bytes, %.1f%%)", total_in, total_out, (double) total_out / total_in * 100); return 0; +} + +static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) { + size_t c; + _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL; + _cleanup_free_ char *buf = NULL; + char *src; + struct stat st; + int r = 0; + size_t total_in = 0, total_out = 0; + + c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); + if (LZ4F_isError(c)) + return -ENOMEM; + + if (fstat(in, &st) < 0) + return log_debug_errno(errno, "fstat() failed: %m"); + + buf = malloc(LZ4_BUFSIZE); + if (!buf) + return -ENOMEM; + + src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in, 0); + if (src == MAP_FAILED) + return -errno; + + while (total_in < (size_t) st.st_size) { + size_t produced = LZ4_BUFSIZE; + size_t used = st.st_size - total_in; + + c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL); + if (LZ4F_isError(c)) { + r = -EBADMSG; + goto cleanup; + } + + total_in += used; + total_out += produced; + + if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { + log_debug("Decompressed stream longer than %zd bytes", max_bytes); + r = -EFBIG; + goto cleanup; + } + + r = loop_write(out, buf, produced, false); + if (r < 0) + goto cleanup; + } + + log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)", + total_in, total_out, + (double) total_out / total_in * 100); + cleanup: + munmap(src, st.st_size); + return r; +} +#endif + +int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { +#ifdef HAVE_LZ4 + int r; + + r = decompress_stream_lz4_v2(fdf, fdt, max_bytes); + if (r == -EBADMSG) + r = decompress_stream_lz4_v1(fdf, fdt, max_bytes); + return r; #else - log_error("Cannot decompress file. Compiled without LZ4 support."); + log_debug("Cannot decompress file. Compiled without LZ4 support."); return -EPROTONOSUPPORT; #endif } diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c index efe418615a..39bc2e4270 100644 --- a/src/journal/coredump-vacuum.c +++ b/src/journal/coredump-vacuum.c @@ -21,12 +21,16 @@ #include <sys/statvfs.h> -#include "util.h" -#include "time-util.h" +#include "alloc-util.h" +#include "coredump-vacuum.h" +#include "dirent-util.h" +#include "fd-util.h" #include "hashmap.h" #include "macro.h" - -#include "coredump-vacuum.h" +#include "string-util.h" +#include "time-util.h" +#include "user-util.h" +#include "util.h" #define DEFAULT_MAX_USE_LOWER (uint64_t) (1ULL*1024ULL*1024ULL) /* 1 MiB */ #define DEFAULT_MAX_USE_UPPER (uint64_t) (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ diff --git a/src/journal/coredump.c b/src/journal/coredump.c index e1e66b9826..f750ddfcbd 100644 --- a/src/journal/coredump.c +++ b/src/journal/coredump.c @@ -20,10 +20,10 @@ ***/ #include <errno.h> -#include <unistd.h> #include <stdio.h> #include <sys/prctl.h> #include <sys/xattr.h> +#include <unistd.h> #ifdef HAVE_ELFUTILS # include <dwarf.h> @@ -32,23 +32,34 @@ #include "sd-journal.h" #include "sd-login.h" -#include "log.h" -#include "util.h" -#include "fileio.h" -#include "strv.h" -#include "macro.h" -#include "mkdir.h" -#include "special.h" + +#include "acl-util.h" +#include "alloc-util.h" +#include "capability-util.h" #include "cgroup-util.h" +#include "compress.h" #include "conf-parser.h" #include "copy.h" -#include "stacktrace.h" -#include "compress.h" -#include "acl-util.h" -#include "capability.h" -#include "journald-native.h" #include "coredump-vacuum.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "journald-native.h" +#include "log.h" +#include "macro.h" +#include "mkdir.h" +#include "parse-util.h" #include "process-util.h" +#include "special.h" +#include "stacktrace.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" /* The maximum size up to which we process coredumps */ #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU)) @@ -115,8 +126,8 @@ static int parse_config(void) { {} }; - return config_parse_many("/etc/systemd/coredump.conf", - CONF_DIRS_NULSTR("systemd/coredump.conf"), + return config_parse_many(PKGSYSCONFDIR "/coredump.conf", + CONF_PATHS_NULSTR("systemd/coredump.conf.d"), "Coredump\0", config_item_table_lookup, items, false, NULL); @@ -128,6 +139,7 @@ static int fix_acl(int fd, uid_t uid) { _cleanup_(acl_freep) acl_t acl = NULL; acl_entry_t entry; acl_permset_t permset; + int r; assert(fd >= 0); @@ -149,11 +161,12 @@ static int fix_acl(int fd, uid_t uid) { } if (acl_get_permset(entry, &permset) < 0 || - acl_add_perm(permset, ACL_READ) < 0 || - calc_acl_mask_if_needed(&acl) < 0) { - log_warning_errno(errno, "Failed to patch ACL: %m"); - return -errno; - } + acl_add_perm(permset, ACL_READ) < 0) + return log_warning_errno(errno, "Failed to patch ACL: %m"); + + r = calc_acl_mask_if_needed(&acl); + if (r < 0) + return log_warning_errno(r, "Failed to patch ACL: %m"); if (acl_set_fd(fd, acl) < 0) return log_error_errno(errno, "Failed to apply ACL: %m"); diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c index dde56008c1..1df28d774a 100644 --- a/src/journal/coredumpctl.c +++ b/src/journal/coredumpctl.c @@ -28,17 +28,23 @@ #include "sd-journal.h" +#include "alloc-util.h" #include "compress.h" +#include "fd-util.h" +#include "fileio.h" #include "journal-internal.h" #include "log.h" #include "macro.h" #include "pager.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "set.h" #include "sigbus.h" #include "signal-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "user-util.h" #include "util.h" static enum { @@ -84,37 +90,35 @@ static Set *new_matches(void) { } static int add_match(Set *set, const char *match) { - int r = -ENOMEM; - unsigned pid; - const char* prefix; - char *pattern = NULL; _cleanup_free_ char *p = NULL; + char *pattern = NULL; + const char* prefix; + pid_t pid; + int r; if (strchr(match, '=')) prefix = ""; else if (strchr(match, '/')) { - p = path_make_absolute_cwd(match); - if (!p) + r = path_make_absolute_cwd(match, &p); + if (r < 0) goto fail; - match = p; prefix = "COREDUMP_EXE="; - } - else if (safe_atou(match, &pid) == 0) + } else if (parse_pid(match, &pid) >= 0) prefix = "COREDUMP_PID="; else prefix = "COREDUMP_COMM="; pattern = strjoin(prefix, match, NULL); - if (!pattern) + if (!pattern) { + r = -ENOMEM; goto fail; + } log_debug("Adding pattern: %s", pattern); r = set_consume(set, pattern); - if (r < 0) { - log_error_errno(r, "Failed to add pattern: %m"); + if (r < 0) goto fail; - } return 0; fail: @@ -613,7 +617,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) { fdt = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC); if (fdt < 0) - return log_error_errno(errno, "Failed to create temporary file: %m"); + return log_error_errno(fdt, "Failed to create temporary file: %m"); log_debug("Created temporary file %s", temp); fd = fdt; @@ -772,7 +776,7 @@ static int run_gdb(sd_journal *j) { r = wait_for_terminate(pid, &st); if (r < 0) { - log_error_errno(errno, "Failed to wait for gdb: %m"); + log_error_errno(r, "Failed to wait for gdb: %m"); goto finish; } diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h index 150d034828..5959b1fed2 100644 --- a/src/journal/fsprg.h +++ b/src/journal/fsprg.h @@ -29,6 +29,7 @@ #include <inttypes.h> #include "macro.h" +#include "util.h" #ifdef __cplusplus extern "C" { diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index cdc80e2d26..0c4ac5cdc3 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -22,10 +22,12 @@ #include <fcntl.h> #include <sys/mman.h> +#include "fd-util.h" +#include "fsprg.h" +#include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" -#include "journal-authenticate.h" -#include "fsprg.h" +#include "hexdecoct.h" static uint64_t journal_file_tag_seqnum(JournalFile *f) { uint64_t r; diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h index 39c9dd0dbf..c003ac05dd 100644 --- a/src/journal/journal-def.h +++ b/src/journal/journal-def.h @@ -21,11 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sparse-endian.h" - -#include "systemd/sd-id128.h" +#include "sd-id128.h" #include "macro.h" +#include "sparse-endian.h" /* * If you change this file you probably should also change its documentation: diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 1071c6d6d7..f9ff9545dd 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -19,22 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/mman.h> #include <errno.h> -#include <sys/uio.h> -#include <unistd.h> -#include <sys/statvfs.h> #include <fcntl.h> -#include <stddef.h> #include <linux/fs.h> +#include <stddef.h> +#include <sys/mman.h> +#include <sys/statvfs.h> +#include <sys/uio.h> +#include <unistd.h> +#include "alloc-util.h" #include "btrfs-util.h" +#include "chattr-util.h" +#include "compress.h" +#include "fd-util.h" +#include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" -#include "journal-authenticate.h" #include "lookup3.h" -#include "compress.h" +#include "parse-util.h" #include "random-util.h" +#include "string-util.h" +#include "xattr-util.h" #define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem)) #define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem)) @@ -42,7 +48,7 @@ #define COMPRESSION_SIZE_THRESHOLD (512ULL) /* This is the minimum journal file size */ -#define JOURNAL_FILE_SIZE_MIN (4ULL*1024ULL*1024ULL) /* 4 MiB */ +#define JOURNAL_FILE_SIZE_MIN (512ULL*1024ULL) /* 512 KiB */ /* These are the lower and upper bounds if we deduce the max_use value * from the file system size */ @@ -1057,7 +1063,7 @@ static int journal_file_append_data( r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p); if (r < 0) return r; - else if (r > 0) { + if (r > 0) { if (ret) *ret = o; @@ -1076,23 +1082,24 @@ static int journal_file_append_data( o->data.hash = htole64(hash); #if defined(HAVE_XZ) || defined(HAVE_LZ4) - if (f->compress_xz && - size >= COMPRESSION_SIZE_THRESHOLD) { + if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { size_t rsize = 0; compression = compress_blob(data, size, o->data.payload, &rsize); - if (compression) { + if (compression >= 0) { o->object.size = htole64(offsetof(Object, data.payload) + rsize); o->object.flags |= compression; log_debug("Compressed data object %"PRIu64" -> %zu using %s", size, rsize, object_compressed_to_string(compression)); - } + } else + /* Compression didn't work, we don't really care why, let's continue without compression */ + compression = 0; } #endif - if (!compression && size > 0) + if (compression == 0 && size > 0) memcpy(o->data.payload, data, size); r = journal_file_link_data(f, o, p, hash); @@ -2698,7 +2705,7 @@ int journal_file_open( } if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) { - r = -EIO; + r = -ENODATA; goto fail; } diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index f2c07356c8..898d12d992 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -235,3 +235,8 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); int journal_file_map_data_hash_table(JournalFile *f); int journal_file_map_field_hash_table(JournalFile *f); + +static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) { + assert(f); + return f->compress_xz || f->compress_lz4; +} diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h index b51ecdb600..06847402e0 100644 --- a/src/journal/journal-internal.h +++ b/src/journal/journal-internal.h @@ -25,14 +25,14 @@ #include <inttypes.h> #include <stdbool.h> -#include "systemd/sd-id128.h" +#include "sd-id128.h" +#include "sd-journal.h" +#include "hashmap.h" #include "journal-def.h" +#include "journal-file.h" #include "list.h" -#include "hashmap.h" #include "set.h" -#include "journal-file.h" -#include "sd-journal.h" typedef struct Match Match; typedef struct Location Location; @@ -121,7 +121,7 @@ struct sd_journal { Hashmap *directories_by_path; Hashmap *directories_by_wd; - Set *errors; + Hashmap *errors; }; char *journal_make_match_string(sd_journal *j); diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h index 3ff6a3ad4a..7d14e8754b 100644 --- a/src/journal/journal-qrcode.h +++ b/src/journal/journal-qrcode.h @@ -21,8 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <stdio.h> -#include "systemd/sd-id128.h" +#include "sd-id128.h" int print_qr_code(FILE *f, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine); diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index dc1b2105dd..fa5dee73c3 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -19,20 +19,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <sys/un.h> #include <errno.h> -#include <stddef.h> -#include <unistd.h> #include <fcntl.h> #include <printf.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> #define SD_JOURNAL_SUPPRESS_LOCATION #include "sd-journal.h" -#include "util.h" -#include "socket-util.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "io-util.h" #include "memfd-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "util.h" #define SNDBUF_SIZE (8*1024*1024) diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c index a394066cb4..4b5fc76eb1 100644 --- a/src/journal/journal-vacuum.c +++ b/src/journal/journal-vacuum.c @@ -23,11 +23,18 @@ #include <sys/stat.h> #include <unistd.h> +#include "sd-id128.h" + +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "journal-def.h" #include "journal-file.h" #include "journal-vacuum.h" -#include "sd-id128.h" +#include "parse-util.h" +#include "string-util.h" #include "util.h" +#include "xattr-util.h" struct vacuum_info { uint64_t usage; @@ -217,13 +224,11 @@ int journal_directory_vacuum( de->d_name[q-8-16-1-16-1] = 0; if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) { - free(p); n_active_files++; continue; } if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) { - free(p); n_active_files++; continue; } @@ -253,7 +258,6 @@ int journal_directory_vacuum( } if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { - free(p); n_active_files ++; continue; } diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 32d59c716f..3676cb8788 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -24,15 +24,18 @@ #include <fcntl.h> #include <stddef.h> -#include "util.h" -#include "macro.h" +#include "alloc-util.h" +#include "compress.h" +#include "fd-util.h" +#include "fileio.h" +#include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" -#include "journal-authenticate.h" #include "journal-verify.h" #include "lookup3.h" -#include "compress.h" +#include "macro.h" #include "terminal-util.h" +#include "util.h" static void draw_progress(uint64_t p, usec_t *last_usec) { unsigned n, i, j, k; @@ -839,19 +842,19 @@ int journal_file_verify( data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (data_fd < 0) { - r = log_error_errno(errno, "Failed to create data file: %m"); + r = log_error_errno(data_fd, "Failed to create data file: %m"); goto fail; } entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_fd < 0) { - r = log_error_errno(errno, "Failed to create entry file: %m"); + r = log_error_errno(entry_fd, "Failed to create entry file: %m"); goto fail; } entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_array_fd < 0) { - r = log_error_errno(errno, + r = log_error_errno(entry_array_fd, "Failed to create entry array file: %m"); goto fail; } @@ -897,7 +900,7 @@ int journal_file_verify( r = journal_file_object_verify(f, p, o); if (r < 0) { - error(p, "Envalid object contents: %s", strerror(-r)); + error(p, "Invalid object contents: %s", strerror(-r)); goto fail; } diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index d9851db36c..75a48c761c 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -39,27 +39,38 @@ #include "sd-journal.h" #include "acl-util.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "catalog.h" +#include "chattr-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "fsprg.h" +#include "glob-util.h" #include "hostname-util.h" +#include "io-util.h" #include "journal-def.h" #include "journal-internal.h" #include "journal-qrcode.h" #include "journal-vacuum.h" #include "journal-verify.h" +#include "locale-util.h" #include "log.h" #include "logs-show.h" #include "mkdir.h" #include "pager.h" +#include "parse-util.h" #include "path-util.h" +#include "rlimit-util.h" #include "set.h" #include "sigbus.h" #include "strv.h" +#include "syslog-util.h" #include "terminal-util.h" #include "unit-name.h" +#include "user-util.h" #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) @@ -104,7 +115,7 @@ static const char *arg_field = NULL; static bool arg_catalog = false; static bool arg_reverse = false; static int arg_journal_type = 0; -static const char *arg_root = NULL; +static char *arg_root = NULL; static const char *arg_machine = NULL; static uint64_t arg_vacuum_size = 0; static uint64_t arg_vacuum_n_files = 0; @@ -122,6 +133,7 @@ static enum { ACTION_UPDATE_CATALOG, ACTION_LIST_BOOTS, ACTION_FLUSH, + ACTION_SYNC, ACTION_ROTATE, ACTION_VACUUM, } arg_action = ACTION_SHOW; @@ -190,12 +202,12 @@ static void help(void) { printf("%s [OPTIONS...] [MATCHES...]\n\n" "Query the journal.\n\n" - "Flags:\n" + "Options:\n" " --system Show the system journal\n" " --user Show the user journal for the current user\n" " -M --machine=CONTAINER Operate on local container\n" - " --since=DATE Show entries not older than the specified date\n" - " --until=DATE Show entries not newer than the specified date\n" + " -S --since=DATE Show entries not older than the specified date\n" + " -U --until=DATE Show entries not newer than the specified date\n" " -c --cursor=CURSOR Show entries starting at the specified cursor\n" " --after-cursor=CURSOR Show entries after the specified cursor\n" " --show-cursor Print the cursor after all the entries\n" @@ -218,12 +230,12 @@ static void help(void) { " -x --catalog Add message explanations where available\n" " --no-full Ellipsize fields\n" " -a --all Show all fields, including long and unprintable\n" - " -q --quiet Do not show privilege warning\n" + " -q --quiet Do not show info messages and privilege warning\n" " --no-pager Do not pipe output into a pager\n" " -m --merge Show entries from all available journals\n" " -D --directory=PATH Show journal files from directory\n" " --file=PATH Show journal file\n" - " --root=ROOT Operate on catalog files underneath the root ROOT\n" + " --root=ROOT Operate on catalog files below a root directory\n" #ifdef HAVE_GCRYPT " --interval=TIME Time interval for changing the FSS sealing key\n" " --verify-key=KEY Specify FSS verification key\n" @@ -233,20 +245,21 @@ static void help(void) { " -h --help Show this help text\n" " --version Show package version\n" " -F --field=FIELD List all values that a specified field takes\n" - " --new-id128 Generate a new 128-bit ID\n" " --disk-usage Show total disk usage of all journal files\n" " --vacuum-size=BYTES Reduce disk usage below specified size\n" " --vacuum-files=INT Leave only the specified number of journal files\n" " --vacuum-time=TIME Remove journal files older than specified time\n" + " --verify Verify journal file consistency\n" + " --sync Synchronize unwritten journal messages to disk\n" " --flush Flush all journal data from /run into /var\n" " --rotate Request immediate rotation of the journal files\n" " --header Show journal header information\n" " --list-catalog Show all message IDs in the catalog\n" " --dump-catalog Show entries in the message catalog\n" " --update-catalog Update the message catalog database\n" + " --new-id128 Generate a new 128-bit ID\n" #ifdef HAVE_GCRYPT " --setup-keys Generate a new FSS key pair\n" - " --verify Verify journal file consistency\n" #endif , program_invocation_short_name); } @@ -270,8 +283,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERIFY, ARG_VERIFY_KEY, ARG_DISK_USAGE, - ARG_SINCE, - ARG_UNTIL, ARG_AFTER_CURSOR, ARG_SHOW_CURSOR, ARG_USER_UNIT, @@ -280,6 +291,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_UPDATE_CATALOG, ARG_FORCE, ARG_UTC, + ARG_SYNC, ARG_FLUSH, ARG_ROTATE, ARG_VACUUM_SIZE, @@ -323,8 +335,8 @@ static int parse_argv(int argc, char *argv[]) { { "cursor", required_argument, NULL, 'c' }, { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, - { "since", required_argument, NULL, ARG_SINCE }, - { "until", required_argument, NULL, ARG_UNTIL }, + { "since", required_argument, NULL, 'S' }, + { "until", required_argument, NULL, 'U' }, { "unit", required_argument, NULL, 'u' }, { "user-unit", required_argument, NULL, ARG_USER_UNIT }, { "field", required_argument, NULL, 'F' }, @@ -336,6 +348,7 @@ static int parse_argv(int argc, char *argv[]) { { "machine", required_argument, NULL, 'M' }, { "utc", no_argument, NULL, ARG_UTC }, { "flush", no_argument, NULL, ARG_FLUSH }, + { "sync", no_argument, NULL, ARG_SYNC }, { "rotate", no_argument, NULL, ARG_ROTATE }, { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, @@ -348,7 +361,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0) switch (c) { @@ -507,7 +520,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - arg_root = optarg; + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case 'c': @@ -646,7 +661,7 @@ static int parse_argv(int argc, char *argv[]) { break; } - case ARG_SINCE: + case 'S': r = parse_timestamp(optarg, &arg_since); if (r < 0) { log_error("Failed to parse timestamp: %s", optarg); @@ -655,7 +670,7 @@ static int parse_argv(int argc, char *argv[]) { arg_since_set = true; break; - case ARG_UNTIL: + case 'U': r = parse_timestamp(optarg, &arg_until); if (r < 0) { log_error("Failed to parse timestamp: %s", optarg); @@ -718,6 +733,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_ROTATE; break; + case ARG_SYNC: + arg_action = ACTION_SYNC; + break; + case '?': return -EINVAL; @@ -748,7 +767,7 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if (arg_action != ACTION_SHOW && optind < argc) { + if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) { log_error("Extraneous arguments starting with '%s'", argv[optind]); return -EINVAL; } @@ -1472,7 +1491,7 @@ static int setup_keys(void) { safe_close(fd); fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC); if (fd < 0) { - r = log_error_errno(errno, "Failed to open %s: %m", k); + r = log_error_errno(fd, "Failed to open %s: %m", k); goto finish; } @@ -1480,7 +1499,7 @@ static int setup_keys(void) { * writing and in-place updating */ r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes: %m"); + log_warning_errno(r, "Failed to set file attributes: %m"); zero(h); memcpy(h.signature, "KSHHRHLP", 8); @@ -1697,36 +1716,50 @@ static int access_check_var_log_journal(sd_journal *j) { static int access_check(sd_journal *j) { Iterator it; void *code; + char *path; int r = 0; assert(j); - if (set_isempty(j->errors)) { + if (hashmap_isempty(j->errors)) { if (ordered_hashmap_isempty(j->files)) log_notice("No journal files were found."); return 0; } - if (set_contains(j->errors, INT_TO_PTR(-EACCES))) { + if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) { (void) access_check_var_log_journal(j); if (ordered_hashmap_isempty(j->files)) r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions."); } - SET_FOREACH(code, j->errors, it) { + HASHMAP_FOREACH_KEY(path, code, j->errors, it) { int err; - err = -PTR_TO_INT(code); - assert(err > 0); + err = abs(PTR_TO_INT(code)); - if (err == EACCES) + switch (err) { + case EACCES: continue; - log_warning_errno(err, "Error was encountered while opening journal files: %m"); - if (r == 0) - r = -err; + case ENODATA: + log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path); + break; + + case EPROTONOSUPPORT: + log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path); + break; + + case EBADMSG: + log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path); + break; + + default: + log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path); + break; + } } return r; @@ -1738,6 +1771,11 @@ static int flush_to_var(void) { _cleanup_close_ int watch_fd = -1; int r; + if (arg_machine) { + log_error("--flush is not supported in conjunction with --machine=."); + return -EOPNOTSUPP; + } + /* Quick exit */ if (access("/run/systemd/journal/flushed", F_OK) >= 0) return 0; @@ -1757,10 +1795,8 @@ static int flush_to_var(void) { &error, NULL, "ssi", "systemd-journald.service", "main", SIGUSR1); - if (r < 0) { - log_error("Failed to kill journal service: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); mkdir_p("/run/systemd/journal", 0755); @@ -1791,30 +1827,97 @@ static int flush_to_var(void) { return 0; } -static int rotate(void) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +static int send_signal_and_wait(int sig, const char *watch_path) { _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_close_ int watch_fd = -1; + usec_t start; int r; - r = bus_connect_system_systemd(&bus); - if (r < 0) - return log_error_errno(r, "Failed to get D-Bus connection: %m"); + if (arg_machine) { + log_error("--sync and --rotate are not supported in conjunction with --machine=."); + return -EOPNOTSUPP; + } - r = sd_bus_call_method( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "KillUnit", - &error, - NULL, - "ssi", "systemd-journald.service", "main", SIGUSR2); - if (r < 0) - return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); + start = now(CLOCK_MONOTONIC); + + /* This call sends the specified signal to journald, and waits + * for acknowledgment by watching the mtime of the specified + * flag file. This is used to trigger syncing or rotation and + * then wait for the operation to complete. */ + + for (;;) { + usec_t tstamp; + + /* See if a sync happened by now. */ + r = read_timestamp_file(watch_path, &tstamp); + if (r < 0 && r != -ENOENT) + return log_error_errno(errno, "Failed to read %s: %m", watch_path); + if (r >= 0 && tstamp >= start) + return 0; + + /* Let's ask for a sync, but only once. */ + if (!bus) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + + r = bus_connect_system_systemd(&bus); + if (r < 0) + return log_error_errno(r, "Failed to get D-Bus connection: %m"); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + &error, + NULL, + "ssi", "systemd-journald.service", "main", sig); + if (r < 0) + return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); + + continue; + } + + /* Let's install the inotify watch, if we didn't do that yet. */ + if (watch_fd < 0) { + + mkdir_p("/run/systemd/journal", 0755); + + watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); + if (watch_fd < 0) + return log_error_errno(errno, "Failed to create inotify watch: %m"); + + r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR); + if (r < 0) + return log_error_errno(errno, "Failed to watch journal directory: %m"); + + /* Recheck the flag file immediately, so that we don't miss any event since the last check. */ + continue; + } + + /* OK, all preparatory steps done, let's wait until + * inotify reports an event. */ + + r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY); + if (r < 0) + return log_error_errno(r, "Failed to wait for event: %m"); + + r = flush_fd(watch_fd); + if (r < 0) + return log_error_errno(r, "Failed to flush inotify events: %m"); + } return 0; } +static int rotate(void) { + return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated"); +} + +static int sync_journal(void) { + return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced"); +} + int main(int argc, char *argv[]) { int r; _cleanup_journal_close_ sd_journal *j = NULL; @@ -1840,30 +1943,19 @@ int main(int argc, char *argv[]) { * be split up into many files. */ setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); - if (arg_action == ACTION_NEW_ID128) { - r = generate_new_id128(); - goto finish; - } - - if (arg_action == ACTION_FLUSH) { - r = flush_to_var(); - goto finish; - } + switch (arg_action) { - if (arg_action == ACTION_ROTATE) { - r = rotate(); + case ACTION_NEW_ID128: + r = generate_new_id128(); goto finish; - } - if (arg_action == ACTION_SETUP_KEYS) { + case ACTION_SETUP_KEYS: r = setup_keys(); goto finish; - } - - if (arg_action == ACTION_UPDATE_CATALOG || - arg_action == ACTION_LIST_CATALOG || - arg_action == ACTION_DUMP_CATALOG) { + case ACTION_LIST_CATALOG: + case ACTION_DUMP_CATALOG: + case ACTION_UPDATE_CATALOG: { _cleanup_free_ char *database; database = path_join(arg_root, CATALOG_DATABASE, NULL); @@ -1879,9 +1971,10 @@ int main(int argc, char *argv[]) { } else { bool oneline = arg_action == ACTION_LIST_CATALOG; + pager_open_if_enabled(); + if (optind < argc) - r = catalog_list_items(stdout, database, - oneline, argv + optind); + r = catalog_list_items(stdout, database, oneline, argv + optind); else r = catalog_list(stdout, database, oneline); if (r < 0) @@ -1891,6 +1984,31 @@ int main(int argc, char *argv[]) { goto finish; } + case ACTION_FLUSH: + r = flush_to_var(); + goto finish; + + case ACTION_SYNC: + r = sync_journal(); + goto finish; + + case ACTION_ROTATE: + r = rotate(); + goto finish; + + case ACTION_SHOW: + case ACTION_PRINT_HEADER: + case ACTION_VERIFY: + case ACTION_DISK_USAGE: + case ACTION_LIST_BOOTS: + case ACTION_VACUUM: + /* These ones require access to the journal files, continue below. */ + break; + + default: + assert_not_reached("Unknown action"); + } + if (arg_directory) r = sd_journal_open_directory(&j, arg_directory, arg_journal_type); else if (arg_file) @@ -1900,8 +2018,7 @@ int main(int argc, char *argv[]) { else r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type); if (r < 0) { - log_error_errno(r, "Failed to open %s: %m", - arg_directory ? arg_directory : arg_file ? "files" : "journal"); + log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal"); goto finish; } @@ -1909,18 +2026,28 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - if (arg_action == ACTION_VERIFY) { - r = verify(j); - goto finish; - } + switch (arg_action) { - if (arg_action == ACTION_PRINT_HEADER) { + case ACTION_NEW_ID128: + case ACTION_SETUP_KEYS: + case ACTION_LIST_CATALOG: + case ACTION_DUMP_CATALOG: + case ACTION_UPDATE_CATALOG: + case ACTION_FLUSH: + case ACTION_SYNC: + case ACTION_ROTATE: + assert_not_reached("Unexpected action."); + + case ACTION_PRINT_HEADER: journal_print_header(j); r = 0; goto finish; - } - if (arg_action == ACTION_DISK_USAGE) { + case ACTION_VERIFY: + r = verify(j); + goto finish; + + case ACTION_DISK_USAGE: { uint64_t bytes = 0; char sbytes[FORMAT_BYTES_MAX]; @@ -1933,7 +2060,11 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_action == ACTION_VACUUM) { + case ACTION_LIST_BOOTS: + r = list_boots(j); + goto finish; + + case ACTION_VACUUM: { Directory *d; Iterator i; @@ -1953,9 +2084,11 @@ int main(int argc, char *argv[]) { goto finish; } - if (arg_action == ACTION_LIST_BOOTS) { - r = list_boots(j); - goto finish; + case ACTION_SHOW: + break; + + default: + assert_not_reached("Unknown action"); } /* add_boot() must be called first! @@ -2248,5 +2381,7 @@ finish: strv_free(arg_system_units); strv_free(arg_user_units); + free(arg_root); + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index fe8ae194c9..3c13fe0d67 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -19,9 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "missing.h" -#include "journald-audit.h" +#include "alloc-util.h" #include "audit-type.h" +#include "fd-util.h" +#include "hexdecoct.h" +#include "io-util.h" +#include "journald-audit.h" +#include "missing.h" +#include "string-util.h" typedef struct MapField { const char *audit_field; diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c index 307bdc3949..89f3d4b42f 100644 --- a/src/journal/journald-console.c +++ b/src/journal/journald-console.c @@ -23,11 +23,16 @@ #include <fcntl.h> #include <sys/socket.h> +#include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" -#include "journald-server.h" -#include "journald-console.h" #include "formats-util.h" +#include "io-util.h" +#include "journald-console.h" +#include "journald-server.h" +#include "parse-util.h" #include "process-util.h" +#include "stdio-util.h" #include "terminal-util.h" static bool prefix_timestamp(void) { @@ -101,7 +106,7 @@ void server_forward_console( fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) { - log_debug_errno(errno, "Failed to open %s for logging: %m", tty); + log_debug_errno(fd, "Failed to open %s for logging: %m", tty); return; } diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index 51fe3aa50a..e048e04716 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -19,20 +19,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <sys/epoll.h> #include <fcntl.h> +#include <sys/epoll.h> #include <sys/mman.h> #include <sys/socket.h> +#include <unistd.h> -#include "systemd/sd-messages.h" -#include <libudev.h> +#include "libudev.h" +#include "sd-messages.h" -#include "journald-server.h" +#include "escape.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" #include "journald-kmsg.h" +#include "journald-server.h" #include "journald-syslog.h" -#include "formats-util.h" +#include "parse-util.h" #include "process-util.h" +#include "stdio-util.h" +#include "string-util.h" void server_forward_kmsg( Server *s, @@ -341,8 +347,7 @@ static int server_read_dev_kmsg(Server *s) { if (errno == EAGAIN || errno == EINTR || errno == EPIPE) return 0; - log_error_errno(errno, "Failed to read from kernel: %m"); - return -errno; + return log_error_errno(errno, "Failed to read from kernel: %m"); } dev_kmsg_record(s, buffer, l); @@ -436,6 +441,7 @@ fail: int server_open_kernel_seqnum(Server *s) { _cleanup_close_ int fd; uint64_t *p; + int r; assert(s); @@ -449,8 +455,9 @@ int server_open_kernel_seqnum(Server *s) { return 0; } - if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) { - log_error_errno(errno, "Failed to allocate sequential number file, ignoring: %m"); + r = posix_fallocate(fd, 0, sizeof(uint64_t)); + if (r != 0) { + log_error_errno(r, "Failed to allocate sequential number file, ignoring: %m"); return 0; } diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 3e8a7a05f6..69a685c06f 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -19,21 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <stddef.h> #include <sys/epoll.h> #include <sys/mman.h> +#include <sys/statvfs.h> +#include <unistd.h> -#include "socket-util.h" -#include "path-util.h" -#include "selinux-util.h" -#include "journald-server.h" -#include "journald-native.h" -#include "journald-kmsg.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "io-util.h" #include "journald-console.h" +#include "journald-kmsg.h" +#include "journald-native.h" +#include "journald-server.h" #include "journald-syslog.h" #include "journald-wall.h" #include "memfd-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "string-util.h" bool valid_user_field(const char *p, size_t l, bool allow_protected) { const char *a; @@ -338,7 +345,7 @@ void server_process_native_file( r = readlink_malloc(sl, &k); if (r < 0) { - log_error_errno(errno, "readlink(%s) failed: %m", sl); + log_error_errno(r, "readlink(%s) failed: %m", sl); return; } @@ -393,8 +400,37 @@ void server_process_native_file( assert_se(munmap(p, ps) >= 0); } else { _cleanup_free_ void *p = NULL; + struct statvfs vfs; ssize_t n; + if (fstatvfs(fd, &vfs) < 0) { + log_error_errno(errno, "Failed to stat file system of passed file, ignoring: %m"); + return; + } + + /* Refuse operating on file systems that have + * mandatory locking enabled, see: + * + * https://github.com/systemd/systemd/issues/1822 + */ + if (vfs.f_flag & ST_MANDLOCK) { + log_error("Received file descriptor from file system with mandatory locking enable, refusing."); + return; + } + + /* Make the fd non-blocking. On regular files this has + * the effect of bypassing mandatory locking. Of + * course, this should normally not be necessary given + * the check above, but let's better be safe than + * sorry, after all NFS is pretty confusing regarding + * file system flags, and we better don't trust it, + * and so is SMB. */ + r = fd_nonblock(fd, true); + if (r < 0) { + log_error_errno(r, "Failed to make fd non-blocking, ignoring: %m"); + return; + } + /* The file is not sealed, we can't map the file here, since * clients might then truncate it and trigger a SIGBUS for * us. So let's stupidly read it */ @@ -407,7 +443,7 @@ void server_process_native_file( n = pread(fd, p, st.st_size, 0); if (n < 0) - log_error_errno(n, "Failed to read file, ignoring: %m"); + log_error_errno(errno, "Failed to read file, ignoring: %m"); else if (n > 0) server_process_native_message(s, p, n, ucred, tv, label, label_len); } diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c index 8afd493b50..434ddc8ac9 100644 --- a/src/journal/journald-rate-limit.c +++ b/src/journal/journald-rate-limit.c @@ -19,14 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> +#include <string.h> -#include "journald-rate-limit.h" -#include "list.h" -#include "util.h" +#include "alloc-util.h" #include "hashmap.h" +#include "list.h" #include "random-util.h" +#include "string-util.h" +#include "util.h" +#include "journald-rate-limit.h" #define POOLS_MAX 5 #define BUCKETS_MAX 127 diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index fb172b7f5d..be913d26ef 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -19,7 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <linux/sockios.h> #ifdef HAVE_SELINUX #include <selinux/selinux.h> #endif @@ -27,6 +26,7 @@ #include <sys/mman.h> #include <sys/signalfd.h> #include <sys/statvfs.h> +#include <linux/sockios.h> #include "libudev.h" #include "sd-daemon.h" @@ -34,18 +34,19 @@ #include "sd-messages.h" #include "acl-util.h" +#include "alloc-util.h" +#include "audit-util.h" #include "cgroup-util.h" #include "conf-parser.h" +#include "dirent-util.h" +#include "extract-word.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "fs-util.h" #include "hashmap.h" #include "hostname-util.h" -#include "missing.h" -#include "mkdir.h" -#include "process-util.h" -#include "rm-rf.h" -#include "selinux-util.h" -#include "signal-util.h" -#include "socket-util.h" +#include "io-util.h" #include "journal-authenticate.h" #include "journal-file.h" #include "journal-internal.h" @@ -57,6 +58,17 @@ #include "journald-server.h" #include "journald-stream.h" #include "journald-syslog.h" +#include "missing.h" +#include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "rm-rf.h" +#include "selinux-util.h" +#include "signal-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "string-util.h" #define USER_JOURNALS_MAX 1024 @@ -67,6 +79,8 @@ #define RECHECK_SPACE_USEC (30*USEC_PER_SEC) +#define NOTIFY_SNDBUF_SIZE (8*1024*1024) + static int determine_space_for( Server *s, JournalMetrics *metrics, @@ -227,12 +241,17 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { /* We do not recalculate the mask unconditionally here, * so that the fchmod() mask above stays intact. */ if (acl_get_permset(entry, &permset) < 0 || - acl_add_perm(permset, ACL_READ) < 0 || - calc_acl_mask_if_needed(&acl) < 0) { + acl_add_perm(permset, ACL_READ) < 0) { log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); return; } + r = calc_acl_mask_if_needed(&acl); + if (r < 0) { + log_warning_errno(r, "Failed to patch ACL on %s, ignoring: %m", f->path); + return; + } + if (acl_set_fd(f->fd, acl) < 0) log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path); @@ -930,7 +949,7 @@ finish: static int system_journal_open(Server *s, bool flush_requested) { const char *fn; - int r; + int r = 0; if (!s->system_journal && (s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) && @@ -1222,29 +1241,38 @@ int server_process_datagram(sd_event_source *es, int fd, uint32_t revents, void static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { Server *s = userdata; + int r; assert(s); - log_info("Received request to flush runtime journal from PID %"PRIu32, si->ssi_pid); + log_info("Received request to flush runtime journal from PID " PID_FMT, si->ssi_pid); server_flush_to_var(s); server_sync(s); server_vacuum(s, false, false); - touch("/run/systemd/journal/flushed"); + r = touch("/run/systemd/journal/flushed"); + if (r < 0) + log_warning_errno(r, "Failed to touch /run/systemd/journal/flushed, ignoring: %m"); return 0; } static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { Server *s = userdata; + int r; assert(s); - log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid); + log_info("Received request to rotate journal from PID " PID_FMT, si->ssi_pid); server_rotate(s); server_vacuum(s, true, true); + /* Let clients know when the most recent rotation happened. */ + r = write_timestamp_file_atomic("/run/systemd/journal/rotated", now(CLOCK_MONOTONIC)); + if (r < 0) + log_warning_errno(r, "Failed to write /run/systemd/journal/rotated, ignoring: %m"); + return 0; } @@ -1259,12 +1287,30 @@ static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo * return 0; } +static int dispatch_sigrtmin1(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) { + Server *s = userdata; + int r; + + assert(s); + + log_debug("Received request to sync from PID " PID_FMT, si->ssi_pid); + + server_sync(s); + + /* Let clients know when the most recent sync happened. */ + r = write_timestamp_file_atomic("/run/systemd/journal/synced", now(CLOCK_MONOTONIC)); + if (r < 0) + log_warning_errno(r, "Failed to write /run/systemd/journal/synced, ignoring: %m"); + + return 0; +} + static int setup_signals(Server *s) { int r; assert(s); - assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, -1) >= 0); + assert(sigprocmask_many(SIG_SETMASK, NULL, SIGINT, SIGTERM, SIGUSR1, SIGUSR2, SIGRTMIN+1, -1) >= 0); r = sd_event_add_signal(s->event, &s->sigusr1_event_source, SIGUSR1, dispatch_sigusr1, s); if (r < 0) @@ -1278,17 +1324,41 @@ static int setup_signals(Server *s) { if (r < 0) return r; + /* Let's process SIGTERM late, so that we flush all queued + * messages to disk before we exit */ + r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20); + if (r < 0) + return r; + + /* When journald is invoked on the terminal (when debugging), + * it's useful if C-c is handled equivalent to SIGTERM. */ r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s); if (r < 0) return r; + r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20); + if (r < 0) + return r; + + /* SIGRTMIN+1 causes an immediate sync. We process this very + * late, so that everything else queued at this point is + * really written to disk. Clients can watch + * /run/systemd/journal/synced with inotify until its mtime + * changes to see when a sync happened. */ + r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s); + if (r < 0) + return r; + + r = sd_event_source_set_priority(s->sigrtmin1_event_source, SD_EVENT_PRIORITY_NORMAL+15); + if (r < 0) + return r; + return 0; } static int server_parse_proc_cmdline(Server *s) { _cleanup_free_ char *line = NULL; - const char *w, *state; - size_t l; + const char *p; int r; r = proc_cmdline(&line); @@ -1297,12 +1367,16 @@ static int server_parse_proc_cmdline(Server *s) { return 0; } - FOREACH_WORD_QUOTED(w, l, line, state) { + p = line; + for(;;) { _cleanup_free_ char *word; - word = strndup(w, l); - if (!word) - return -ENOMEM; + r = extract_first_word(&p, &word, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse journald syntax \"%s\": %m", line); + + if (r == 0) + break; if (startswith(word, "systemd.journald.forward_to_syslog=")) { r = parse_boolean(word + 35); @@ -1339,8 +1413,8 @@ static int server_parse_proc_cmdline(Server *s) { static int server_parse_config_file(Server *s) { assert(s); - return config_parse_many("/etc/systemd/journald.conf", - CONF_DIRS_NULSTR("systemd/journald.conf"), + return config_parse_many(PKGSYSCONFDIR "/journald.conf", + CONF_PATHS_NULSTR("systemd/journald.conf.d"), "Journal\0", config_item_perf_lookup, journald_gperf_lookup, false, s); @@ -1443,17 +1517,184 @@ static int server_open_hostname(Server *s) { return 0; } +static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Server *s = userdata; + int r; + + assert(s); + assert(s->notify_event_source == es); + assert(s->notify_fd == fd); + + /* The $NOTIFY_SOCKET is writable again, now send exactly one + * message on it. Either it's the wtachdog event, the initial + * READY=1 event or an stdout stream event. If there's nothing + * to write anymore, turn our event source off. The next time + * there's something to send it will be turned on again. */ + + if (!s->sent_notify_ready) { + static const char p[] = + "READY=1\n" + "STATUS=Processing requests..."; + ssize_t l; + + l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); + if (l < 0) { + if (errno == EAGAIN) + return 0; + + return log_error_errno(errno, "Failed to send READY=1 notification message: %m"); + } + + s->sent_notify_ready = true; + log_debug("Sent READY=1 notification."); + + } else if (s->send_watchdog) { + + static const char p[] = + "WATCHDOG=1"; + + ssize_t l; + + l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); + if (l < 0) { + if (errno == EAGAIN) + return 0; + + return log_error_errno(errno, "Failed to send WATCHDOG=1 notification message: %m"); + } + + s->send_watchdog = false; + log_debug("Sent WATCHDOG=1 notification."); + + } else if (s->stdout_streams_notify_queue) + /* Dispatch one stream notification event */ + stdout_stream_send_notify(s->stdout_streams_notify_queue); + + /* Leave us enabled if there's still more to to do. */ + if (s->send_watchdog || s->stdout_streams_notify_queue) + return 0; + + /* There was nothing to do anymore, let's turn ourselves off. */ + r = sd_event_source_set_enabled(es, SD_EVENT_OFF); + if (r < 0) + return log_error_errno(r, "Failed to turn off notify event source: %m"); + + return 0; +} + +static int dispatch_watchdog(sd_event_source *es, uint64_t usec, void *userdata) { + Server *s = userdata; + int r; + + assert(s); + + s->send_watchdog = true; + + r = sd_event_source_set_enabled(s->notify_event_source, SD_EVENT_ON); + if (r < 0) + log_warning_errno(r, "Failed to turn on notify event source: %m"); + + r = sd_event_source_set_time(s->watchdog_event_source, usec + s->watchdog_usec / 2); + if (r < 0) + return log_error_errno(r, "Failed to restart watchdog event source: %m"); + + r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON); + if (r < 0) + return log_error_errno(r, "Failed to enable watchdog event source: %m"); + + return 0; +} + +static int server_connect_notify(Server *s) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + }; + const char *e; + int r; + + assert(s); + assert(s->notify_fd < 0); + assert(!s->notify_event_source); + + /* + So here's the problem: we'd like to send notification + messages to PID 1, but we cannot do that via sd_notify(), + since that's synchronous, and we might end up blocking on + it. Specifically: given that PID 1 might block on + dbus-daemon during IPC, and dbus-daemon is logging to us, + and might hence block on us, we might end up in a deadlock + if we block on sending PID 1 notification messages -- by + generating a full blocking circle. To avoid this, let's + create a non-blocking socket, and connect it to the + notification socket, and then wait for POLLOUT before we + send anything. This should efficiently avoid any deadlocks, + as we'll never block on PID 1, hence PID 1 can safely block + on dbus-daemon which can safely block on us again. + + Don't think that this issue is real? It is, see: + https://github.com/systemd/systemd/issues/1505 + */ + + e = getenv("NOTIFY_SOCKET"); + if (!e) + return 0; + + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { + log_error("NOTIFY_SOCKET set to an invalid value: %s", e); + return -EINVAL; + } + + if (strlen(e) > sizeof(sa.un.sun_path)) { + log_error("NOTIFY_SOCKET path too long: %s", e); + return -EINVAL; + } + + s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (s->notify_fd < 0) + return log_error_errno(errno, "Failed to create notify socket: %m"); + + (void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE); + + strncpy(sa.un.sun_path, e, sizeof(sa.un.sun_path)); + if (sa.un.sun_path[0] == '@') + sa.un.sun_path[0] = 0; + + r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e)); + if (r < 0) + return log_error_errno(errno, "Failed to connect to notify socket: %m"); + + r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s); + if (r < 0) + return log_error_errno(r, "Failed to watch notification socket: %m"); + + if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) { + s->send_watchdog = true; + + r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec/4, dispatch_watchdog, s); + if (r < 0) + return log_error_errno(r, "Failed to add watchdog time event: %m"); + } + + /* This should fire pretty soon, which we'll use to send the + * READY=1 event. */ + + return 0; +} + int server_init(Server *s) { _cleanup_fdset_free_ FDSet *fds = NULL; int n, r, fd; + bool no_sockets; assert(s); zero(*s); - s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1; + s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1; s->compress = true; s->seal = true; + s->watchdog_usec = USEC_INFINITY; + s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC; s->sync_scheduled = false; @@ -1496,8 +1737,6 @@ int server_init(Server *s) { if (r < 0) return log_error_errno(r, "Failed to create event loop: %m"); - sd_event_set_watchdog(s->event, true); - n = sd_listen_fds(true); if (n < 0) return log_error_errno(n, "Failed to read listening file descriptors from environment: %m"); @@ -1555,30 +1794,44 @@ int server_init(Server *s) { } } - r = server_open_stdout_socket(s, fds); - if (r < 0) - return r; + /* Try to restore streams, but don't bother if this fails */ + (void) server_restore_streams(s, fds); if (fdset_size(fds) > 0) { log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds)); fds = fdset_free(fds); } + no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0; + + /* always open stdout, syslog, native, and kmsg sockets */ + + /* systemd-journald.socket: /run/systemd/journal/stdout */ + r = server_open_stdout_socket(s); + if (r < 0) + return r; + + /* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */ r = server_open_syslog_socket(s); if (r < 0) return r; + /* systemd-journald.socket: /run/systemd/journal/socket */ r = server_open_native_socket(s); if (r < 0) return r; + /* /dev/ksmg */ r = server_open_dev_kmsg(s); if (r < 0) return r; - r = server_open_audit(s); - if (r < 0) - return r; + /* Unless we got *some* sockets and not audit, open audit socket */ + if (s->audit_fd >= 0 || no_sockets) { + r = server_open_audit(s); + if (r < 0) + return r; + } r = server_open_kernel_seqnum(s); if (r < 0) @@ -1608,6 +1861,8 @@ int server_init(Server *s) { server_cache_boot_id(s); server_cache_machine_id(s); + (void) server_connect_notify(s); + return system_journal_open(s, false); } @@ -1655,7 +1910,10 @@ void server_done(Server *s) { sd_event_source_unref(s->sigusr2_event_source); sd_event_source_unref(s->sigterm_event_source); sd_event_source_unref(s->sigint_event_source); + sd_event_source_unref(s->sigrtmin1_event_source); sd_event_source_unref(s->hostname_event_source); + sd_event_source_unref(s->notify_event_source); + sd_event_source_unref(s->watchdog_event_source); sd_event_unref(s->event); safe_close(s->syslog_fd); @@ -1664,6 +1922,7 @@ void server_done(Server *s) { safe_close(s->dev_kmsg_fd); safe_close(s->audit_fd); safe_close(s->hostname_fd); + safe_close(s->notify_fd); if (s->rate_limit) journal_rate_limit_free(s->rate_limit); diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 535c0ab9ab..dcc21bb7c3 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -25,10 +25,13 @@ #include <sys/types.h> #include "sd-event.h" -#include "journal-file.h" + +typedef struct Server Server; + #include "hashmap.h" -#include "audit.h" +#include "journal-file.h" #include "journald-rate-limit.h" +#include "journald-stream.h" #include "list.h" typedef enum Storage { @@ -48,15 +51,14 @@ typedef enum SplitMode { _SPLIT_INVALID = -1 } SplitMode; -typedef struct StdoutStream StdoutStream; - -typedef struct Server { +struct Server { int syslog_fd; int native_fd; int stdout_fd; int dev_kmsg_fd; int audit_fd; int hostname_fd; + int notify_fd; sd_event *event; @@ -70,7 +72,10 @@ typedef struct Server { sd_event_source *sigusr2_event_source; sd_event_source *sigterm_event_source; sd_event_source *sigint_event_source; + sd_event_source *sigrtmin1_event_source; sd_event_source *hostname_event_source; + sd_event_source *notify_event_source; + sd_event_source *watchdog_event_source; JournalFile *runtime_journal; JournalFile *system_journal; @@ -111,6 +116,7 @@ typedef struct Server { usec_t oldest_file_usec; LIST_HEAD(StdoutStream, stdout_streams); + LIST_HEAD(StdoutStream, stdout_streams_notify_queue); unsigned n_stdout_streams; char *tty_path; @@ -126,13 +132,14 @@ typedef struct Server { MMapCache *mmap; - bool dev_kmsg_readable; + struct udev *udev; uint64_t *kernel_seqnum; + bool dev_kmsg_readable:1; - struct udev *udev; - - bool sync_scheduled; + bool send_watchdog:1; + bool sent_notify_ready:1; + bool sync_scheduled:1; char machine_id_field[sizeof("_MACHINE_ID=") + 32]; char boot_id_field[sizeof("_BOOT_ID=") + 32]; @@ -140,7 +147,9 @@ typedef struct Server { /* Cached cgroup root, so that we don't have to query that all the time */ char *cgroup_root; -} Server; + + usec_t watchdog_usec; +}; #define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID=")) diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 69e2d41863..fb800782fb 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -19,25 +19,35 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <stddef.h> +#include <unistd.h> #ifdef HAVE_SELINUX #include <selinux/selinux.h> #endif -#include "sd-event.h" #include "sd-daemon.h" -#include "socket-util.h" -#include "selinux-util.h" -#include "mkdir.h" +#include "sd-event.h" + +#include "alloc-util.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" +#include "journald-console.h" +#include "journald-kmsg.h" #include "journald-server.h" #include "journald-stream.h" #include "journald-syslog.h" -#include "journald-kmsg.h" -#include "journald-console.h" #include "journald-wall.h" +#include "mkdir.h" +#include "parse-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "syslog-util.h" #define STDOUT_STREAMS_MAX 4096 @@ -69,6 +79,7 @@ struct StdoutStream { bool forward_to_console:1; bool fdstore:1; + bool in_notify_queue:1; char buffer[LINE_MAX+1]; size_t length; @@ -78,6 +89,7 @@ struct StdoutStream { char *state_file; LIST_FIELDS(StdoutStream, stdout_stream); + LIST_FIELDS(StdoutStream, stdout_stream_notify_queue); }; void stdout_stream_free(StdoutStream *s) { @@ -88,6 +100,9 @@ void stdout_stream_free(StdoutStream *s) { assert(s->server->n_stdout_streams > 0); s->server->n_stdout_streams --; LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); + + if (s->in_notify_queue) + LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); } if (s->event_source) { @@ -111,7 +126,7 @@ static void stdout_stream_destroy(StdoutStream *s) { return; if (s->state_file) - unlink(s->state_file); + (void) unlink(s->state_file); stdout_stream_free(s); } @@ -190,11 +205,15 @@ static int stdout_stream_save(StdoutStream *s) { goto fail; } - /* Store the connection fd in PID 1, so that we get it passed - * in again on next start */ - if (!s->fdstore) { - sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1); - s->fdstore = true; + if (!s->fdstore && !s->in_notify_queue) { + LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); + s->in_notify_queue = true; + + if (s->server->notify_event_source) { + r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON); + if (r < 0) + log_warning_errno(r, "Failed to enable notify event source: %m"); + } } return 0; @@ -519,8 +538,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent if (errno == EAGAIN) return 0; - log_error_errno(errno, "Failed to accept stdout connection: %m"); - return -errno; + return log_error_errno(errno, "Failed to accept stdout connection: %m"); } if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) { @@ -627,7 +645,7 @@ static int stdout_stream_restore(Server *s, const char *fname, int fd) { return 0; } -static int server_restore_streams(Server *s, FDSet *fds) { +int server_restore_streams(Server *s, FDSet *fds) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r; @@ -681,7 +699,7 @@ fail: return log_error_errno(errno, "Failed to read streams directory: %m"); } -int server_open_stdout_socket(Server *s, FDSet *fds) { +int server_open_stdout_socket(Server *s) { int r; assert(s); @@ -717,8 +735,52 @@ int server_open_stdout_socket(Server *s, FDSet *fds) { if (r < 0) return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m"); - /* Try to restore streams, but don't bother if this fails */ - (void) server_restore_streams(s, fds); - return 0; } + +void stdout_stream_send_notify(StdoutStream *s) { + struct iovec iovec = { + .iov_base = (char*) "FDSTORE=1", + .iov_len = strlen("FDSTORE=1"), + }; + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + }; + struct cmsghdr *cmsg; + ssize_t l; + + assert(s); + assert(!s->fdstore); + assert(s->in_notify_queue); + assert(s->server); + assert(s->server->notify_fd >= 0); + + /* Store the connection fd in PID 1, so that we get it passed + * in again on next start */ + + msghdr.msg_controllen = CMSG_SPACE(sizeof(int)); + msghdr.msg_control = alloca0(msghdr.msg_controllen); + + cmsg = CMSG_FIRSTHDR(&msghdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + + memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int)); + + l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL); + if (l < 0) { + if (errno == EAGAIN) + return; + + log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m"); + } else { + log_debug("Successfully sent stream file descriptor to service manager."); + s->fdstore = 1; + } + + LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); + s->in_notify_queue = false; + +} diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h index 94bf955d78..e3497f0ded 100644 --- a/src/journal/journald-stream.h +++ b/src/journal/journald-stream.h @@ -21,9 +21,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +typedef struct StdoutStream StdoutStream; + #include "fdset.h" #include "journald-server.h" -int server_open_stdout_socket(Server *s, FDSet *fds); +int server_open_stdout_socket(Server *s); +int server_restore_streams(Server *s, FDSet *fds); void stdout_stream_free(StdoutStream *s); +void stdout_stream_send_notify(StdoutStream *s); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index ffba451955..f3ac1a7ae0 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -19,20 +19,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <stddef.h> #include <sys/epoll.h> +#include <unistd.h> -#include "systemd/sd-messages.h" -#include "socket-util.h" -#include "selinux-util.h" +#include "sd-messages.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" +#include "journald-console.h" +#include "journald-kmsg.h" #include "journald-server.h" #include "journald-syslog.h" -#include "journald-kmsg.h" -#include "journald-console.h" #include "journald-wall.h" -#include "formats-util.h" #include "process-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "syslog-util.h" /* Warn once every 30s if we missed syslog message */ #define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC) diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c index 7863766ae7..69540f1141 100644 --- a/src/journal/journald-wall.c +++ b/src/journal/journald-wall.c @@ -19,11 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "utmp-wtmp.h" -#include "journald-server.h" -#include "journald-wall.h" +#include "alloc-util.h" #include "formats-util.h" +#include "journald-server.h" #include "process-util.h" +#include "string-util.h" +#include "utmp-wtmp.h" +#include "journald-wall.h" void server_forward_wall( Server *s, diff --git a/src/journal/journald.c b/src/journal/journald.c index 83236ceba9..b137e3c7be 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -61,10 +61,6 @@ int main(int argc, char *argv[]) { log_debug("systemd-journald running as pid "PID_FMT, getpid()); server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started"); - sd_notify(false, - "READY=1\n" - "STATUS=Processing requests..."); - for (;;) { usec_t t = USEC_INFINITY, n; @@ -117,10 +113,6 @@ int main(int argc, char *argv[]) { server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped"); finish: - sd_notify(false, - "STOPPING=1\n" - "STATUS=Shutting down..."); - server_done(&server); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 22f75540b8..3cb1dfa986 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -23,6 +23,7 @@ #include <stdlib.h> #include <sys/mman.h> +#include "alloc-util.h" #include "hashmap.h" #include "list.h" #include "log.h" diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 13fa9b52fc..5cde7f17f7 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -21,29 +21,38 @@ #include <errno.h> #include <fcntl.h> +#include <linux/magic.h> +#include <poll.h> #include <stddef.h> -#include <unistd.h> #include <sys/inotify.h> -#include <poll.h> #include <sys/vfs.h> -#include <linux/magic.h> +#include <unistd.h> #include "sd-journal.h" + +#include "alloc-util.h" +#include "catalog.h" +#include "compress.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "fs-util.h" +#include "hashmap.h" +#include "hostname-util.h" +#include "io-util.h" #include "journal-def.h" #include "journal-file.h" -#include "hashmap.h" +#include "journal-internal.h" #include "list.h" -#include "strv.h" -#include "path-util.h" #include "lookup3.h" -#include "compress.h" -#include "journal-internal.h" #include "missing.h" -#include "catalog.h" +#include "path-util.h" #include "replace-var.h" -#include "fileio.h" -#include "formats-util.h" -#include "hostname-util.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" #define JOURNAL_FILES_MAX 7168 @@ -64,19 +73,46 @@ static bool journal_pid_changed(sd_journal *j) { return j->original_pid != getpid(); } -/* We return an error here only if we didn't manage to - memorize the real error. */ -static int set_put_error(sd_journal *j, int r) { +static int journal_put_error(sd_journal *j, int r, const char *path) { + char *copy; int k; + /* Memorize an error we encountered, and store which + * file/directory it was generated from. Note that we store + * only *one* path per error code, as the error code is the + * key into the hashmap, and the path is the value. This means + * we keep track only of all error kinds, but not of all error + * locations. This has the benefit that the hashmap cannot + * grow beyond bounds. + * + * We return an error here only if we didn't manage to + * memorize the real error. */ + if (r >= 0) return r; - k = set_ensure_allocated(&j->errors, NULL); + k = hashmap_ensure_allocated(&j->errors, NULL); if (k < 0) return k; - return set_put(j->errors, INT_TO_PTR(r)); + if (path) { + copy = strdup(path); + if (!copy) + return -ENOMEM; + } else + copy = NULL; + + k = hashmap_put(j->errors, INT_TO_PTR(r), copy); + if (k < 0) { + free(copy); + + if (k == -EEXIST) + return 0; + + return k; + } + + return 0; } static void detach_location(sd_journal *j) { @@ -1016,8 +1052,6 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { int r; - const char *word, *state; - size_t l; Object *o; assert_return(j, -EINVAL); @@ -1031,20 +1065,23 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { if (r < 0) return r; - FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) { + for(;;) { _cleanup_free_ char *item = NULL; - sd_id128_t id; unsigned long long ll; + sd_id128_t id; int k = 0; - if (l < 2 || word[1] != '=') - return -EINVAL; + r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; - item = strndup(word, l); - if (!item) - return -ENOMEM; + if (r == 0) + break; - switch (word[0]) { + if (strlen(item) < 2 || item[1] != '=') + return -EINVAL; + + switch (item[0]) { case 's': k = sd_id128_from_string(item+2, &id); @@ -1173,6 +1210,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) { } static bool file_type_wanted(int flags, const char *filename) { + assert(filename); + if (!endswith(filename, ".journal") && !endswith(filename, ".journal~")) return false; @@ -1197,7 +1236,7 @@ static bool file_type_wanted(int flags, const char *filename) { static int add_any_file(sd_journal *j, const char *path) { JournalFile *f = NULL; - int r; + int r, k; assert(j); assert(path); @@ -1206,20 +1245,23 @@ static int add_any_file(sd_journal *j, const char *path) { return 0; if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { - log_warning("Too many open journal files, not adding %s.", path); - return set_put_error(j, -ETOOMANYREFS); + log_debug("Too many open journal files, not adding %s.", path); + r = -ETOOMANYREFS; + goto fail; } r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Failed to open journal file %s: %m", path); + goto fail; + } /* journal_file_dump(f); */ r = ordered_hashmap_put(j->files, f->path, f); if (r < 0) { journal_file_close(f); - return r; + goto fail; } log_debug("File %s added.", f->path); @@ -1229,11 +1271,17 @@ static int add_any_file(sd_journal *j, const char *path) { j->current_invalidate_counter ++; return 0; + +fail: + k = journal_put_error(j, r, path); + if (k < 0) + return k; + + return r; } static int add_file(sd_journal *j, const char *prefix, const char *filename) { - _cleanup_free_ char *path = NULL; - int r; + const char *path; assert(j); assert(prefix); @@ -1243,34 +1291,24 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { !file_type_wanted(j->flags, filename)) return 0; - path = strjoin(prefix, "/", filename, NULL); - if (!path) - return -ENOMEM; - - r = add_any_file(j, path); - if (r == -ENOENT) - return 0; - return r; + path = strjoina(prefix, "/", filename); + return add_any_file(j, path); } -static int remove_file(sd_journal *j, const char *prefix, const char *filename) { - _cleanup_free_ char *path; +static void remove_file(sd_journal *j, const char *prefix, const char *filename) { + const char *path; JournalFile *f; assert(j); assert(prefix); assert(filename); - path = strjoin(prefix, "/", filename, NULL); - if (!path) - return -ENOMEM; - + path = strjoina(prefix, "/", filename); f = ordered_hashmap_get(j->files, path); if (!f) - return 0; + return; remove_file_real(j, f); - return 0; } static void remove_file_real(sd_journal *j, JournalFile *f) { @@ -1299,12 +1337,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { j->current_invalidate_counter ++; } +static int dirname_is_machine_id(const char *fn) { + sd_id128_t id, machine; + int r; + + r = sd_id128_get_machine(&machine); + if (r < 0) + return r; + + r = sd_id128_from_string(fn, &id); + if (r < 0) + return r; + + return sd_id128_equal(id, machine); +} + static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { _cleanup_free_ char *path = NULL; - int r; _cleanup_closedir_ DIR *d = NULL; - sd_id128_t id, mid; + struct dirent *de = NULL; Directory *m; + int r, k; assert(j); assert(prefix); @@ -1313,35 +1366,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) log_debug("Considering %s/%s.", prefix, dirname); if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && - (sd_id128_from_string(dirname, &id) < 0 || - sd_id128_get_machine(&mid) < 0 || - !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run")))) + !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run"))) return 0; path = strjoin(prefix, "/", dirname, NULL); - if (!path) - return -ENOMEM; + if (!path) { + r = -ENOMEM; + goto fail; + } d = opendir(path); if (!d) { - log_debug_errno(errno, "Failed to open %s: %m", path); - if (errno == ENOENT) - return 0; - return -errno; + r = log_debug_errno(errno, "Failed to open directory %s: %m", path); + goto fail; } m = hashmap_get(j->directories_by_path, path); if (!m) { m = new0(Directory, 1); - if (!m) - return -ENOMEM; + if (!m) { + r = -ENOMEM; + goto fail; + } m->is_root = false; m->path = path; if (hashmap_put(j->directories_by_path, m->path, m) < 0) { free(m); - return -ENOMEM; + r = -ENOMEM; + goto fail; } path = NULL; /* avoid freeing in cleanup */ @@ -1363,41 +1417,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) inotify_rm_watch(j->inotify_fd, m->wd); } - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) { - r = -errno; - log_debug_errno(errno, "Failed to read directory %s: %m", m->path); - return r; - } - if (!de) - break; + FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { if (dirent_is_file_with_suffix(de, ".journal") || - dirent_is_file_with_suffix(de, ".journal~")) { - r = add_file(j, m->path, de->d_name); - if (r < 0) { - log_debug_errno(r, "Failed to add file %s/%s: %m", - m->path, de->d_name); - r = set_put_error(j, r); - if (r < 0) - return r; - } - } + dirent_is_file_with_suffix(de, ".journal~")) + (void) add_file(j, m->path, de->d_name); } check_network(j, dirfd(d)); return 0; + +fail: + k = journal_put_error(j, r, path ?: dirname); + if (k < 0) + return k; + + return r; } -static int add_root_directory(sd_journal *j, const char *p) { +static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; Directory *m; - int r; + int r, k; assert(j); assert(p); @@ -1410,26 +1453,35 @@ static int add_root_directory(sd_journal *j, const char *p) { p = strjoina(j->prefix, p); d = opendir(p); - if (!d) - return -errno; + if (!d) { + if (errno == ENOENT && missing_ok) + return 0; + + r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); + goto fail; + } m = hashmap_get(j->directories_by_path, p); if (!m) { m = new0(Directory, 1); - if (!m) - return -ENOMEM; + if (!m) { + r = -ENOMEM; + goto fail; + } m->is_root = true; m->path = strdup(p); if (!m->path) { free(m); - return -ENOMEM; + r = -ENOMEM; + goto fail; } if (hashmap_put(j->directories_by_path, m->path, m) < 0) { free(m->path); free(m); - return -ENOMEM; + r = -ENOMEM; + goto fail; } j->current_invalidate_counter ++; @@ -1452,42 +1504,27 @@ static int add_root_directory(sd_journal *j, const char *p) { if (j->no_new_files) return 0; - for (;;) { - struct dirent *de; + FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { sd_id128_t id; - errno = 0; - de = readdir(d); - if (!de && errno != 0) { - r = -errno; - log_debug_errno(errno, "Failed to read directory %s: %m", m->path); - return r; - } - if (!de) - break; - if (dirent_is_file_with_suffix(de, ".journal") || - dirent_is_file_with_suffix(de, ".journal~")) { - r = add_file(j, m->path, de->d_name); - if (r < 0) { - log_debug_errno(r, "Failed to add file %s/%s: %m", - m->path, de->d_name); - r = set_put_error(j, r); - if (r < 0) - return r; - } - } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) && - sd_id128_from_string(de->d_name, &id) >= 0) { - - r = add_directory(j, m->path, de->d_name); - if (r < 0) - log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name); - } + dirent_is_file_with_suffix(de, ".journal~")) + (void) add_file(j, m->path, de->d_name); + else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) && + sd_id128_from_string(de->d_name, &id) >= 0) + (void) add_directory(j, m->path, de->d_name); } check_network(j, dirfd(d)); return 0; + +fail: + k = journal_put_error(j, r, p); + if (k < 0) + return k; + + return r; } static void remove_directory(sd_journal *j, Directory *d) { @@ -1512,8 +1549,8 @@ static void remove_directory(sd_journal *j, Directory *d) { } static int add_search_paths(sd_journal *j) { - int r; - const char search_paths[] = + + static const char search_paths[] = "/run/log/journal\0" "/var/log/journal\0"; const char *p; @@ -1523,14 +1560,8 @@ static int add_search_paths(sd_journal *j) { /* We ignore most errors here, since the idea is to only open * what's actually accessible, and ignore the rest. */ - NULSTR_FOREACH(p, search_paths) { - r = add_root_directory(j, p); - if (r < 0 && r != -ENOENT) { - r = set_put_error(j, r); - if (r < 0) - return r; - } - } + NULSTR_FOREACH(p, search_paths) + (void) add_root_directory(j, p, true); return 0; } @@ -1554,17 +1585,14 @@ static int add_current_paths(sd_journal *j) { if (!dir) return -ENOMEM; - r = add_root_directory(j, dir); - if (r < 0) { - set_put_error(j, r); + r = add_root_directory(j, dir, true); + if (r < 0) return r; - } } return 0; } - static int allocate_inotify(sd_journal *j) { assert(j); @@ -1692,11 +1720,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f if (!j) return -ENOMEM; - r = add_root_directory(j, path); - if (r < 0) { - set_put_error(j, r); + r = add_root_directory(j, path, false); + if (r < 0) goto fail; - } *ret = j; return 0; @@ -1721,10 +1747,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla STRV_FOREACH(path, paths) { r = add_any_file(j, *path); - if (r < 0) { - log_error_errno(r, "Failed to open %s: %m", *path); + if (r < 0) goto fail; - } } j->no_new_files = true; @@ -1741,6 +1765,7 @@ fail: _public_ void sd_journal_close(sd_journal *j) { Directory *d; JournalFile *f; + char *p; if (!j) return; @@ -1768,10 +1793,13 @@ _public_ void sd_journal_close(sd_journal *j) { mmap_cache_unref(j->mmap); } + while ((p = hashmap_steal_first(j->errors))) + free(p); + hashmap_free(j->errors); + free(j->path); free(j->prefix); free(j->unique_field); - set_free(j->errors); free(j); } @@ -2064,7 +2092,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) { if (j->no_new_files) r = add_current_paths(j); else if (j->path) - r = add_root_directory(j, j->path); + r = add_root_directory(j, j->path, true); else r = add_search_paths(j); if (r < 0) @@ -2111,7 +2139,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { static void process_inotify_event(sd_journal *j, struct inotify_event *e) { Directory *d; - int r; assert(j); assert(e); @@ -2127,20 +2154,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { /* Event for a journal file */ - if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { - r = add_file(j, d->path, e->name); - if (r < 0) { - log_debug_errno(r, "Failed to add file %s/%s: %m", - d->path, e->name); - set_put_error(j, r); - } - - } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) { - - r = remove_file(j, d->path, e->name); - if (r < 0) - log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name); - } + if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) + (void) add_file(j, d->path, e->name); + else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) + remove_file(j, d->path, e->name); } else if (!d->is_root && e->len == 0) { @@ -2153,11 +2170,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { /* Event for root directory */ - if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { - r = add_directory(j, d->path, e->name); - if (r < 0) - log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name); - } + if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) + (void) add_directory(j, d->path, e->name); } return; @@ -2166,7 +2180,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { if (e->mask & IN_IGNORED) return; - log_warning("Unknown inotify event."); + log_debug("Unknown inotify event."); } static int determine_change(sd_journal *j) { diff --git a/src/journal/stacktrace.c b/src/journal/stacktrace.c index 98a54ff269..4305462f80 100644 --- a/src/journal/stacktrace.c +++ b/src/journal/stacktrace.c @@ -22,10 +22,13 @@ #include <dwarf.h> #include <elfutils/libdwfl.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" #include "macro.h" #include "stacktrace.h" -#include "formats-util.h" +#include "string-util.h" +#include "util.h" #define FRAMES_MAX 64 #define THREADS_MAX 64 diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c index dbfdea609d..aea8fd15e6 100644 --- a/src/journal/test-catalog.c +++ b/src/journal/test-catalog.c @@ -25,11 +25,16 @@ #include <errno.h> #include <fcntl.h> -#include "util.h" -#include "log.h" -#include "macro.h" #include "sd-messages.h" + +#include "alloc-util.h" #include "catalog.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" +#include "util.h" static const char *catalog_dirs[] = { CATALOG_DIR, diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c index c8e5b76c6c..93ea9c6318 100644 --- a/src/journal/test-compress-benchmark.c +++ b/src/journal/test-compress-benchmark.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + /*** This file is part of systemd @@ -17,30 +19,73 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "compress.h" -#include "util.h" #include "macro.h" +#include "parse-util.h" +#include "random-util.h" +#include "string-util.h" +#include "util.h" typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, size_t *dst_size); typedef int (decompress_t)(const void *src, uint64_t src_size, void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max); +static usec_t arg_duration = 2 * USEC_PER_SEC; +static size_t arg_start; + #define MAX_SIZE (1024*1024LU) +#define PRIME 1048571 /* A prime close enough to one megabyte that mod 4 == 3 */ + +static size_t _permute(size_t x) { + size_t residue; + + if (x >= PRIME) + return x; + + residue = x*x % PRIME; + if (x <= PRIME / 2) + return residue; + else + return PRIME - residue; +} + +static size_t permute(size_t x) { + return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345); +} -static char* make_buf(size_t count) { +static char* make_buf(size_t count, const char *type) { char *buf; size_t i; buf = malloc(count); assert_se(buf); - for (i = 0; i < count; i++) - buf[i] = 'a' + i % ('z' - 'a' + 1); + if (streq(type, "zeros")) + memzero(buf, count); + else if (streq(type, "simple")) + for (i = 0; i < count; i++) + buf[i] = 'a' + i % ('z' - 'a' + 1); + else if (streq(type, "random")) { + size_t step = count / 10; + + random_bytes(buf, step); + memzero(buf + 1*step, step); + random_bytes(buf + 2*step, step); + memzero(buf + 3*step, step); + random_bytes(buf + 4*step, step); + memzero(buf + 5*step, step); + random_bytes(buf + 6*step, step); + memzero(buf + 7*step, step); + random_bytes(buf + 8*step, step); + memzero(buf + 9*step, step); + } else + assert_not_reached("here"); return buf; } -static void test_compress_decompress(const char* label, +static void test_compress_decompress(const char* label, const char* type, compress_t compress, decompress_t decompress) { usec_t n, n2 = 0; float dt; @@ -50,64 +95,85 @@ static void test_compress_decompress(const char* label, size_t buf2_allocated = 0; size_t skipped = 0, compressed = 0, total = 0; - text = make_buf(MAX_SIZE); + text = make_buf(MAX_SIZE, type); buf = calloc(MAX_SIZE + 1, 1); assert_se(text && buf); n = now(CLOCK_MONOTONIC); - for (size_t i = 1; i <= MAX_SIZE; i += (i < 2048 ? 1 : 217)) { - size_t j = 0, k = 0; + for (size_t i = 0; i <= MAX_SIZE; i++) { + size_t j = 0, k = 0, size; int r; - r = compress(text, i, buf, &j); + size = permute(i); + + log_debug("%s %zu %zu", type, i, size); + + memzero(buf, MIN(size + 1000, MAX_SIZE)); + + r = compress(text, size, buf, &j); /* assume compression must be successful except for small inputs */ - assert_se(r == 0 || (i < 2048 && r == -ENOBUFS)); + assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random")); + /* check for overwrites */ - assert_se(buf[i] == 0); + assert_se(buf[size] == 0); if (r != 0) { - skipped += i; + skipped += size; continue; } assert_se(j > 0); - if (j >= i) - log_error("%s \"compressed\" %zu -> %zu", label, i, j); + if (j >= size) + log_error("%s \"compressed\" %zu -> %zu", label, size, j); r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0); assert_se(r == 0); assert_se(buf2_allocated >= k); - assert_se(k == i); + assert_se(k == size); - assert_se(memcmp(text, buf2, i) == 0); + assert_se(memcmp(text, buf2, size) == 0); - total += i; + total += size; compressed += j; n2 = now(CLOCK_MONOTONIC); - if (n2 - n > 60 * USEC_PER_SEC) + if (n2 - n > arg_duration) break; } dt = (n2-n) / 1e6; - log_info("%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), " + log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), " "mean compresion %.2f%%, skipped %zu bytes", - label, total, dt, + label, type, total, dt, total / 1024. / 1024 / dt, 100 - compressed * 100. / total, skipped); } int main(int argc, char *argv[]) { + const char *i; - log_set_max_level(LOG_DEBUG); + log_set_max_level(LOG_INFO); + if (argc >= 2) { + unsigned x; + + assert_se(safe_atou(argv[1], &x) >= 0); + arg_duration = x * USEC_PER_SEC; + } + if (argc == 3) + (void) safe_atolu(argv[2], &arg_start); + else + arg_start = getpid(); + + NULSTR_FOREACH(i, "zeros\0simple\0random\0") { #ifdef HAVE_XZ - test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz); + test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz); #endif #ifdef HAVE_LZ4 - test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4); + test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4); #endif + } return 0; } diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c index f17c00e60d..b9d90a8988 100644 --- a/src/journal/test-compress.c +++ b/src/journal/test-compress.c @@ -17,10 +17,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "compress.h" -#include "util.h" +#include "fd-util.h" +#include "fileio.h" #include "macro.h" #include "random-util.h" +#include "util.h" #ifdef HAVE_XZ # define XZ_OK 0 @@ -144,8 +147,8 @@ static void test_compress_stream(int compression, const char *srcfile) { _cleanup_close_ int src = -1, dst = -1, dst2 = -1; - char pattern[] = "/tmp/systemd-test.xz.XXXXXX", - pattern2[] = "/tmp/systemd-test.xz.XXXXXX"; + char pattern[] = "/tmp/systemd-test.compressed.XXXXXX", + pattern2[] = "/tmp/systemd-test.compressed.XXXXXX"; int r; _cleanup_free_ char *cmd = NULL, *cmd2; struct stat st = {}; @@ -185,7 +188,7 @@ static void test_compress_stream(int compression, assert_se(lseek(dst, 1, SEEK_SET) == 1); r = decompress(dst, dst2, st.st_size); - assert_se(r == -EBADMSG); + assert_se(r == -EBADMSG || r == 0); assert_se(lseek(dst, 0, SEEK_SET) == 0); assert_se(lseek(dst2, 0, SEEK_SET) == 0); @@ -236,8 +239,7 @@ int main(int argc, char *argv[]) { compress_blob_lz4, decompress_startswith_lz4, data, sizeof(data), true); - /* Produced stream is not compatible with lz4 binary, skip lz4cat check. */ - test_compress_stream(OBJECT_COMPRESSED_LZ4, NULL, + test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat", compress_stream_lz4, decompress_stream_lz4, argv[0]); #else log_info("/* LZ4 test skipped */"); diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c index cde2025ae9..040c7d58fb 100644 --- a/src/journal/test-journal-enum.c +++ b/src/journal/test-journal-enum.c @@ -21,8 +21,9 @@ #include <stdio.h> -#include "log.h" #include "sd-journal.h" + +#include "log.h" #include "macro.h" #include "journal-internal.h" diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c index 2d4f531e9b..03d1522e23 100644 --- a/src/journal/test-journal-flush.c +++ b/src/journal/test-journal-flush.c @@ -22,9 +22,12 @@ #include <fcntl.h> #include "sd-journal.h" -#include "macro.h" + +#include "alloc-util.h" #include "journal-file.h" #include "journal-internal.h" +#include "macro.h" +#include "string-util.h" int main(int argc, char *argv[]) { _cleanup_free_ char *fn = NULL; diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c index e6599f366d..142da85041 100644 --- a/src/journal/test-journal-init.c +++ b/src/journal/test-journal-init.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "systemd/sd-journal.h" +#include "sd-journal.h" #include "log.h" -#include "util.h" +#include "parse-util.h" #include "rm-rf.h" +#include "util.h" int main(int argc, char *argv[]) { sd_journal *j; diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 8069339c1f..4ad89fe4b6 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -24,11 +24,14 @@ #include <fcntl.h> #include "sd-journal.h" + +#include "alloc-util.h" #include "journal-file.h" #include "journal-vacuum.h" -#include "util.h" #include "log.h" +#include "parse-util.h" #include "rm-rf.h" +#include "util.h" /* This program tests skipping around in a multi-file journal. */ diff --git a/src/journal/test-journal-match.c b/src/journal/test-journal-match.c index a3187053c9..abefedb992 100644 --- a/src/journal/test-journal-match.c +++ b/src/journal/test-journal-match.c @@ -21,11 +21,13 @@ #include <stdio.h> -#include "systemd/sd-journal.h" +#include "sd-journal.h" +#include "alloc-util.h" #include "journal-internal.h" -#include "util.h" #include "log.h" +#include "string-util.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_journal_close_ sd_journal*j; diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c index 81ca47ed8d..694376670d 100644 --- a/src/journal/test-journal-send.c +++ b/src/journal/test-journal-send.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "systemd/sd-journal.h" #include <stdlib.h> #include <unistd.h> +#include "sd-journal.h" + #include "log.h" int main(int argc, char *argv[]) { diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index b5ecf2f375..0cbef4b8c5 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -19,16 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <fcntl.h> +#include <unistd.h> #include "sd-journal.h" -#include "util.h" + +#include "alloc-util.h" +#include "journal-file.h" +#include "journal-internal.h" #include "log.h" #include "macro.h" +#include "parse-util.h" #include "rm-rf.h" -#include "journal-file.h" -#include "journal-internal.h" +#include "util.h" #define N_ENTRIES 200 diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c index c99ca0654b..1784187fe9 100644 --- a/src/journal/test-journal-syslog.c +++ b/src/journal/test-journal-syslog.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "journald-syslog.h" #include "macro.h" +#include "string-util.h" static void test_syslog_parse_identifier(const char* str, const char *ident, const char*pid, int ret) { diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index d89123dc64..887a83efe1 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -23,12 +23,13 @@ #include <unistd.h> #include <fcntl.h> -#include "util.h" -#include "log.h" -#include "rm-rf.h" +#include "fd-util.h" #include "journal-file.h" #include "journal-verify.h" +#include "log.h" +#include "rm-rf.h" #include "terminal-util.h" +#include "util.h" #define N_ENTRIES 6000 #define RANDOM_RANGE 77 diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c index 3258b22702..fdd48e531c 100644 --- a/src/journal/test-mmap-cache.c +++ b/src/journal/test-mmap-cache.c @@ -19,14 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fcntl.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> -#include <fcntl.h> +#include "fd-util.h" +#include "fileio.h" #include "macro.h" -#include "util.h" #include "mmap-cache.h" +#include "util.h" int main(int argc, char *argv[]) { int x, y, z, r; diff --git a/src/libsystemd-network/arp-util.c b/src/libsystemd-network/arp-util.c index 2f5b9b3731..4660c7ea09 100644 --- a/src/libsystemd-network/arp-util.c +++ b/src/libsystemd-network/arp-util.c @@ -21,8 +21,9 @@ #include <linux/filter.h> #include <arpa/inet.h> -#include "util.h" #include "arp-util.h" +#include "fd-util.h" +#include "util.h" int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) { struct sock_filter filter[] = { diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 7d9cad2a70..51ee7bcce4 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -19,18 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "sd-id128.h" #include "libudev.h" -#include "udev-util.h" - -#include "virt.h" -#include "sparse-endian.h" -#include "siphash24.h" +#include "sd-id128.h" -#include "dhcp6-protocol.h" #include "dhcp-identifier.h" +#include "dhcp6-protocol.h" #include "network-internal.h" +#include "siphash24.h" +#include "sparse-endian.h" +#include "udev-util.h" +#include "virt.h" #define SYSTEMD_PEN 43793 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) @@ -58,7 +56,6 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { return 0; } - int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { /* name is a pointer to memory in the udev_device struct, so must have the same scope */ diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 95117915f4..2291736f8b 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -21,11 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-id128.h" #include "macro.h" #include "sparse-endian.h" #include "unaligned.h" -#include "sd-id128.h" /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index df6f882af5..a5daaa543a 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -22,15 +22,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdint.h> #include <linux/if_packet.h> -#include <net/if_arp.h> #include <net/ethernet.h> - -#include "socket-util.h" +#include <net/if_arp.h> +#include <stdint.h> #include "sd-dhcp-client.h" + #include "dhcp-protocol.h" +#include "socket-util.h" int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index 7f10838de1..fac25e0fa2 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -18,18 +18,18 @@ ***/ #include <errno.h> -#include <sys/socket.h> -#include <string.h> -#include <linux/if_packet.h> -#include <linux/if_infiniband.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <stdio.h> +#include <string.h> +#include <sys/socket.h> #include <linux/filter.h> - -#include "socket-util.h" +#include <linux/if_infiniband.h> +#include <linux/if_packet.h> #include "dhcp-internal.h" +#include "fd-util.h" +#include "socket-util.h" static int _bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 83e8192f58..ecc220f2f6 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -24,10 +24,11 @@ #include <net/ethernet.h> #include <netinet/in.h> -#include "sparse-endian.h" #include "sd-event.h" + #include "list.h" #include "macro.h" +#include "sparse-endian.h" typedef struct DHCP6Address DHCP6Address; @@ -58,9 +59,6 @@ typedef struct DHCP6IA DHCP6IA; #define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) -int dhcp_network_icmp6_bind_router_solicitation(int index); -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr); - int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia); diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index 187975364b..318ee9c4b4 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -18,116 +18,19 @@ ***/ #include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <string.h> -#include <linux/if_packet.h> +#include <netinet/in.h> +#include <netinet/ip6.h> #include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include <netinet/in.h> - -#include "socket-util.h" +#include <linux/if_packet.h> #include "dhcp6-internal.h" #include "dhcp6-protocol.h" - -#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } } - -#define IN6ADDR_ALL_NODES_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } - -int dhcp_network_icmp6_bind_router_solicitation(int index) { - struct icmp6_filter filter = { }; - struct ipv6_mreq mreq = { - .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, - .ipv6mr_interface = index, - }; - _cleanup_close_ int s = -1; - int r, zero = 0, hops = 255; - - s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_ICMPV6); - if (s < 0) - return -errno; - - ICMP6_FILTER_SETBLOCKALL(&filter); - ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); - r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, - sizeof(filter)); - if (r < 0) - return -errno; - - /* RFC 3315, section 6.7, bullet point 2 may indicate that an - IPV6_PKTINFO socket option also applies for ICMPv6 multicast. - Empirical experiments indicates otherwise and therefore an - IPV6_MULTICAST_IF socket option is used here instead */ - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, - sizeof(index)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, - sizeof(zero)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, - sizeof(hops)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)); - if (r < 0) - return -errno; - - r = s; - s = -1; - return r; -} - -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { - struct sockaddr_in6 dst = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, - }; - struct { - struct nd_router_solicit rs; - struct nd_opt_hdr rs_opt; - struct ether_addr rs_opt_mac; - } _packed_ rs = { - .rs.nd_rs_type = ND_ROUTER_SOLICIT, - }; - struct iovec iov[1] = { - { &rs, }, - }; - struct msghdr msg = { - .msg_name = &dst, - .msg_namelen = sizeof(dst), - .msg_iov = iov, - .msg_iovlen = 1, - }; - int r; - - if (ether_addr) { - memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN); - rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; - rs.rs_opt.nd_opt_len = 1; - iov[0].iov_len = sizeof(rs); - } else - iov[0].iov_len = sizeof(rs.rs); - - r = sendmsg(s, &msg, 0); - if (r < 0) - return -errno; - - return 0; -} +#include "fd-util.h" +#include "socket-util.h" int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { struct in6_pktinfo pktinfo = { diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index f41bebced0..0f46df6a1b 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -23,14 +23,14 @@ #include <errno.h> #include <string.h> -#include "sparse-endian.h" -#include "unaligned.h" -#include "util.h" -#include "strv.h" - +#include "alloc-util.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" #include "dns-domain.h" +#include "sparse-endian.h" +#include "strv.h" +#include "unaligned.h" +#include "util.h" #define DHCP6_OPTION_IA_NA_LEN 12 #define DHCP6_OPTION_IA_TA_LEN 4 @@ -344,7 +344,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * int r; assert_return(optlen > 1, -ENODATA); - assert_return(optval[optlen] == '\0', -EINVAL); + assert_return(optval[optlen - 1] == '\0', -EINVAL); while (pos < optlen) { _cleanup_free_ char *ret = NULL; diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c new file mode 100644 index 0000000000..91308bf6c3 --- /dev/null +++ b/src/libsystemd-network/icmp6-util.c @@ -0,0 +1,129 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <errno.h> +#include <netinet/icmp6.h> +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#include <linux/if_packet.h> + +#include "fd-util.h" +#include "icmp6-util.h" +#include "socket-util.h" + +#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ + { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } } + +#define IN6ADDR_ALL_NODES_MULTICAST_INIT \ + { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } + +int icmp6_bind_router_solicitation(int index) { + struct icmp6_filter filter = { }; + struct ipv6_mreq mreq = { + .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, + .ipv6mr_interface = index, + }; + _cleanup_close_ int s = -1; + int r, zero = 0, hops = 255; + + s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, + IPPROTO_ICMPV6); + if (s < 0) + return -errno; + + ICMP6_FILTER_SETBLOCKALL(&filter); + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); + r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, + sizeof(filter)); + if (r < 0) + return -errno; + + /* RFC 3315, section 6.7, bullet point 2 may indicate that an + IPV6_PKTINFO socket option also applies for ICMPv6 multicast. + Empirical experiments indicates otherwise and therefore an + IPV6_MULTICAST_IF socket option is used here instead */ + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, + sizeof(index)); + if (r < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, + sizeof(zero)); + if (r < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, + sizeof(hops)); + if (r < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)); + if (r < 0) + return -errno; + + r = s; + s = -1; + return r; +} + +int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { + struct sockaddr_in6 dst = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, + }; + struct { + struct nd_router_solicit rs; + struct nd_opt_hdr rs_opt; + struct ether_addr rs_opt_mac; + } _packed_ rs = { + .rs.nd_rs_type = ND_ROUTER_SOLICIT, + }; + struct iovec iov[1] = { + { &rs, }, + }; + struct msghdr msg = { + .msg_name = &dst, + .msg_namelen = sizeof(dst), + .msg_iov = iov, + .msg_iovlen = 1, + }; + int r; + + if (ether_addr) { + memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN); + rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; + rs.rs_opt.nd_opt_len = 1; + iov[0].iov_len = sizeof(rs); + } else + iov[0].iov_len = sizeof(rs.rs); + + r = sendmsg(s, &msg, 0); + if (r < 0) + return -errno; + + return 0; +} diff --git a/src/libsystemd-network/icmp6-util.h b/src/libsystemd-network/icmp6-util.h new file mode 100644 index 0000000000..4eb17e152e --- /dev/null +++ b/src/libsystemd-network/icmp6-util.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <net/ethernet.h> + +int icmp6_bind_router_solicitation(int index); +int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr); diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c index 4012cd483b..583be2f55d 100644 --- a/src/libsystemd-network/lldp-internal.c +++ b/src/libsystemd-network/lldp-internal.c @@ -20,9 +20,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "lldp-internal.h" #include "sd-lldp.h" +#include "alloc-util.h" +#include "lldp-internal.h" + /* We store maximum 1K chassis entries */ #define LLDP_MIB_MAX_CHASSIS 1024 diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 284cc6720e..5d19fa0fea 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -22,11 +22,12 @@ #pragma once -#include "log.h" +#include "sd-event.h" + #include "list.h" #include "lldp-tlv.h" +#include "log.h" #include "prioq.h" -#include "sd-event.h" typedef struct lldp_neighbour_port lldp_neighbour_port; typedef struct lldp_chassis lldp_chassis; diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 12a6599ff1..f483cd9c8e 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -23,10 +23,11 @@ #include <linux/filter.h> #include <linux/if_ether.h> -#include "socket-util.h" -#include "lldp-tlv.h" -#include "lldp-network.h" +#include "fd-util.h" #include "lldp-internal.h" +#include "lldp-network.h" +#include "lldp-tlv.h" +#include "socket-util.h" int lldp_network_bind_raw_socket(int ifindex) { typedef struct LLDPFrame { diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c index 7486b4c38f..97b6b485d2 100644 --- a/src/libsystemd-network/lldp-port.c +++ b/src/libsystemd-network/lldp-port.c @@ -20,6 +20,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "async.h" #include "lldp-port.h" #include "lldp-network.h" diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index 66af22e37d..7890160497 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -23,8 +23,9 @@ #include <net/ethernet.h> #include <arpa/inet.h> -#include "macro.h" +#include "alloc-util.h" #include "lldp-tlv.h" +#include "macro.h" int tlv_section_new(tlv_section **ret) { tlv_section *s; @@ -277,7 +278,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { p = m->pdu; - /* extract ethernet header */ + /* extract Ethernet header */ memcpy(&m->mac, p, ETH_ALEN); p += sizeof(struct ether_header); @@ -386,12 +387,11 @@ static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t r = lldp_tlv_packet_enter_container(tlv, type); if (r < 0) - goto out; + return r; r = tlv_packet_read_u16(tlv, value); r2 = lldp_tlv_packet_exit_container(tlv); - out: return r < 0 ? r : r2; } @@ -428,18 +428,18 @@ int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID); if (r < 0) - goto out2; + return r; r = tlv_packet_read_u8(tlv, &subtype); if (r < 0) - goto out1; + goto out; switch (subtype) { case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: r = tlv_packet_read_bytes(tlv, data, length); if (r < 0) - goto out1; + goto out; break; default: @@ -449,10 +449,9 @@ int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, *type = subtype; - out1: + out: r2 = lldp_tlv_packet_exit_container(tlv); - out2: return r < 0 ? r : r2; } @@ -468,11 +467,11 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv, r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID); if (r < 0) - goto out2; + return r; r = tlv_packet_read_u8(tlv, &subtype); if (r < 0) - goto out1; + goto out; switch (subtype) { case LLDP_PORT_SUBTYPE_PORT_COMPONENT: @@ -482,7 +481,7 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv, r = tlv_packet_read_string(tlv, &s, length); if (r < 0) - goto out1; + goto out; *data = (uint8_t *) s; @@ -491,7 +490,7 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv, r = tlv_packet_read_bytes(tlv, data, length); if (r < 0) - goto out1; + goto out; break; default: @@ -501,10 +500,9 @@ int sd_lldp_packet_read_port_id(tlv_packet *tlv, *type = subtype; - out1: + out: r2 = lldp_tlv_packet_exit_container(tlv); - out2: return r < 0 ? r : r2; } @@ -541,12 +539,11 @@ int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) { r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID); if (r < 0) - goto out; + return r; r = tlv_packet_read_u16(tlv, id); r2 = lldp_tlv_packet_exit_container(tlv); - out: return r < 0 ? r : r2; } @@ -557,7 +554,7 @@ int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flag r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID); if (r < 0) - goto out; + return r; r = tlv_packet_read_u8(tlv, flags); if (r >= 0) @@ -565,7 +562,6 @@ int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flag r2 = lldp_tlv_packet_exit_container(tlv); - out: return r < 0 ? r : r2; } @@ -577,7 +573,7 @@ int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **nam r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME); if (r < 0) - goto out; + return r; r = tlv_packet_read_u16(tlv, vlan_id); if (r >= 0) @@ -590,7 +586,6 @@ int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **nam r2 = lldp_tlv_packet_exit_container(tlv); - out: return r < 0 ? r : r2; } @@ -601,12 +596,11 @@ int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) { r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID); if (r < 0) - goto out; + return r; r = tlv_packet_read_u16(tlv, id); r2 = lldp_tlv_packet_exit_container(tlv); - out: return r < 0 ? r : r2; } @@ -617,7 +611,7 @@ int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, u r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION); if (r < 0) - goto out; + return r; r = tlv_packet_read_u8(tlv, status); if (r >= 0) @@ -625,7 +619,6 @@ int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, u r2 = lldp_tlv_packet_exit_container(tlv); - out: return r < 0 ? r : r2; } diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 2a62af2fd4..52d76e443e 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -19,20 +19,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/ether.h> -#include <linux/if.h> #include <arpa/inet.h> +#include <linux/if.h> +#include <netinet/ether.h> -#include "strv.h" -#include "siphash24.h" +#include "sd-ndisc.h" + +#include "alloc-util.h" +#include "condition.h" +#include "conf-parser.h" #include "dhcp-lease-internal.h" #include "log.h" +#include "network-internal.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "siphash24.h" +#include "string-util.h" +#include "strv.h" #include "utf8.h" #include "util.h" -#include "conf-parser.h" -#include "condition.h" -#include "network-internal.h" -#include "sd-icmp6-nd.h" const char *net_get_name(struct udev_device *device) { const char *name, *field; @@ -390,8 +395,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, assert(size); for (i = 0; i < size; i++) - fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]), + fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s", + SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]), (i < (size - 1)) ? " ": ""); } diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 141b836a0d..137537253a 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -17,24 +17,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> -#include <string.h> -#include <stdio.h> #include <net/ethernet.h> #include <net/if_arp.h> -#include <linux/if_infiniband.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> +#include <linux/if_infiniband.h> -#include "util.h" -#include "random-util.h" -#include "async.h" +#include "sd-dhcp-client.h" -#include "dhcp-protocol.h" +#include "alloc-util.h" +#include "async.h" +#include "dhcp-identifier.h" #include "dhcp-internal.h" #include "dhcp-lease-internal.h" -#include "dhcp-identifier.h" -#include "sd-dhcp-client.h" +#include "dhcp-protocol.h" +#include "random-util.h" +#include "string-util.h" +#include "util.h" #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) @@ -1265,8 +1267,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - lifetime_timeout - time_now, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); /* don't arm earlier timeouts if this has already expired */ if (lifetime_timeout <= time_now) @@ -1292,8 +1293,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - t2_timeout - time_now, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); /* don't arm earlier timeout if this has already expired */ if (t2_timeout <= time_now) @@ -1318,8 +1318,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - t1_timeout - time_now, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); return 0; } @@ -1518,7 +1517,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd, expected_hlen = ETH_ALEN; expected_chaddr = (const struct ether_addr *) &client->mac_addr; } else { - /* Non-ethernet links expect zero chaddr */ + /* Non-Ethernet links expect zero chaddr */ expected_hlen = 0; expected_chaddr = &zero_mac; } diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index df3d8e6e3c..8befedc500 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -18,21 +18,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <arpa/inet.h> #include <errno.h> -#include <string.h> #include <stdio.h> -#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sd-dhcp-lease.h" +#include "alloc-util.h" +#include "dhcp-lease-internal.h" +#include "dhcp-protocol.h" +#include "dns-domain.h" +#include "fd-util.h" #include "fileio.h" -#include "unaligned.h" -#include "in-addr-util.h" +#include "hexdecoct.h" #include "hostname-util.h" -#include "dns-domain.h" +#include "in-addr-util.h" #include "network-internal.h" -#include "dhcp-protocol.h" -#include "dhcp-lease-internal.h" -#include "sd-dhcp-lease.h" +#include "parse-util.h" +#include "string-util.h" +#include "unaligned.h" int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); @@ -945,19 +951,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (address) { r = inet_pton(AF_INET, address, &lease->address); if (r <= 0) - log_debug_errno(errno, "Failed to parse address %s, ignoring: %m", address); + log_debug("Failed to parse address %s, ignoring.", address); } if (router) { r = inet_pton(AF_INET, router, &lease->router); if (r <= 0) - log_debug_errno(errno, "Failed to parse router %s, ignoring: %m", router); + log_debug("Failed to parse router %s, ignoring.", router); } if (netmask) { r = inet_pton(AF_INET, netmask, &lease->subnet_mask); if (r <= 0) - log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", netmask); + log_debug("Failed to parse netmask %s, ignoring.", netmask); else lease->have_subnet_mask = true; } @@ -965,19 +971,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (server_address) { r = inet_pton(AF_INET, server_address, &lease->server_address); if (r <= 0) - log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", server_address); + log_debug("Failed to parse server address %s, ignoring.", server_address); } if (next_server) { r = inet_pton(AF_INET, next_server, &lease->next_server); if (r <= 0) - log_debug_errno(errno, "Failed to parse next server %s, ignoring: %m", next_server); + log_debug("Failed to parse next server %s, ignoring.", next_server); } if (broadcast) { r = inet_pton(AF_INET, broadcast, &lease->broadcast); if (r <= 0) - log_debug_errno(errno, "Failed to parse broadcast address %s, ignoring: %m", broadcast); + log_debug("Failed to parse broadcast address %s, ignoring.", broadcast); else lease->have_broadcast = true; } diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index d27bb561ca..8d0d9955c3 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -22,12 +22,15 @@ #include <sys/ioctl.h> -#include "in-addr-util.h" -#include "siphash24.h" - #include "sd-dhcp-server.h" -#include "dhcp-server-internal.h" + +#include "alloc-util.h" #include "dhcp-internal.h" +#include "dhcp-server-internal.h" +#include "fd-util.h" +#include "in-addr-util.h" +#include "siphash24.h" +#include "string-util.h" #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) @@ -93,7 +96,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres return 0; } -bool sd_dhcp_server_is_running(sd_dhcp_server *server) { +int sd_dhcp_server_is_running(sd_dhcp_server *server) { assert_return(server, false); return !!server->receive_message; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index acb31a16c2..a443bb3a7a 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -24,17 +24,18 @@ #include <sys/ioctl.h> #include <linux/if_infiniband.h> -#include "udev.h" -#include "udev-util.h" -#include "util.h" -#include "random-util.h" - -#include "network-internal.h" #include "sd-dhcp6-client.h" -#include "dhcp6-protocol.h" + +#include "alloc-util.h" +#include "dhcp-identifier.h" #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" -#include "dhcp-identifier.h" +#include "dhcp6-protocol.h" +#include "fd-util.h" +#include "network-internal.h" +#include "random-util.h" +#include "string-table.h" +#include "util.h" #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN @@ -208,9 +209,8 @@ int sd_dhcp6_client_set_duid( return 0; } -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) { +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) { assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); client->information_request = enabled; @@ -218,7 +218,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enable return 0; } -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, bool *enabled) { +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) { assert_return(client, -EINVAL); assert_return(enabled, -EINVAL); @@ -259,12 +259,12 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { assert_return(client, -EINVAL); - assert_return(ret, -EINVAL); if (!client->lease) return -ENOMSG; - *ret = client->lease; + if (ret) + *ret = client->lease; return 0; } @@ -595,8 +595,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, } log_dhcp6_client(client, "Next retransmission in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - client->retransmit_time, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC)); r = sd_event_add_time(client->event, &client->timeout_resend, clock_boottime_or_monotonic(), @@ -1048,9 +1047,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC); log_dhcp6_client(client, "T1 expires in %s", - format_timespan(time_string, - FORMAT_TIMESPAN_MAX, - timeout, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); r = sd_event_add_time(client->event, &client->lease->ia.timeout_t1, @@ -1072,9 +1069,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); log_dhcp6_client(client, "T2 expires in %s", - format_timespan(time_string, - FORMAT_TIMESPAN_MAX, - timeout, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); r = sd_event_add_time(client->event, &client->lease->ia.timeout_t2, @@ -1120,11 +1115,19 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { } int sd_dhcp6_client_stop(sd_dhcp6_client *client) { + assert_return(client, -EINVAL); + client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP); return 0; } +int sd_dhcp6_client_is_running(sd_dhcp6_client *client) { + assert_return(client, -EINVAL); + + return client->state != DHCP6_STATE_STOPPED; +} + int sd_dhcp6_client_start(sd_dhcp6_client *client) { int r = 0; enum DHCP6State state = DHCP6_STATE_SOLICITATION; diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index f34af6eaba..3f32ba35e7 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -22,11 +22,11 @@ #include <errno.h> -#include "strv.h" -#include "util.h" - +#include "alloc-util.h" #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" +#include "strv.h" +#include "util.h" int dhcp6_lease_clear_timers(DHCP6IA *ia) { assert_return(ia, -EINVAL); diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-icmp6-nd.c deleted file mode 100644 index bedcac8d9e..0000000000 --- a/src/libsystemd-network/sd-icmp6-nd.c +++ /dev/null @@ -1,722 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <netinet/icmp6.h> -#include <netinet/ip6.h> -#include <string.h> -#include <stdbool.h> -#include <netinet/in.h> -#include <sys/ioctl.h> - -#include "socket-util.h" -#include "async.h" - -#include "dhcp6-internal.h" -#include "sd-icmp6-nd.h" - -#define ICMP6_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC -#define ICMP6_MAX_ROUTER_SOLICITATIONS 3 - -enum icmp6_nd_state { - ICMP6_NEIGHBOR_DISCOVERY_IDLE = 0, - ICMP6_ROUTER_SOLICITATION_SENT = 10, - ICMP6_ROUTER_ADVERTISMENT_LISTEN = 11, -}; - -#define IP6_MIN_MTU (unsigned)1280 -#define ICMP6_ND_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr)) -#define ICMP6_OPT_LEN_UNITS 8 - -typedef struct ICMP6Prefix ICMP6Prefix; - -struct ICMP6Prefix { - unsigned n_ref; - - LIST_FIELDS(ICMP6Prefix, prefixes); - - uint8_t len; - sd_event_source *timeout_valid; - struct in6_addr addr; -}; - -struct sd_icmp6_nd { - unsigned n_ref; - - enum icmp6_nd_state state; - sd_event *event; - int event_priority; - int index; - struct ether_addr mac_addr; - uint32_t mtu; - ICMP6Prefix *expired_prefix; - LIST_HEAD(ICMP6Prefix, prefixes); - int fd; - sd_event_source *recv; - sd_event_source *timeout; - int nd_sent; - sd_icmp6_nd_callback_t callback; - void *userdata; -}; - -#define log_icmp6_nd(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__) - -static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) { - - if (!prefix) - return NULL; - - assert(prefix->n_ref > 0); - prefix->n_ref--; - - if (prefix->n_ref > 0) - return NULL; - - prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid); - free(prefix); - return NULL; -} - -static int icmp6_prefix_new(ICMP6Prefix **ret) { - _cleanup_free_ ICMP6Prefix *prefix = NULL; - - assert(ret); - - prefix = new0(ICMP6Prefix, 1); - if (!prefix) - return -ENOMEM; - - prefix->n_ref = 1; - LIST_INIT(prefixes, prefix); - - *ret = prefix; - prefix = NULL; - - return 0; -} - -static void icmp6_nd_notify(sd_icmp6_nd *nd, int event) { - if (nd->callback) - nd->callback(nd, event, nd->userdata); -} - -int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback, - void *userdata) { - assert(nd); - - nd->callback = callback; - nd->userdata = userdata; - - return 0; -} - -int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) { - assert(nd); - assert(interface_index >= -1); - - nd->index = interface_index; - - return 0; -} - -int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) { - assert(nd); - - if (mac_addr) - memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr)); - else - zero(nd->mac_addr); - - return 0; - -} - -int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) { - int r; - - assert_return(nd, -EINVAL); - assert_return(!nd->event, -EBUSY); - - if (event) - nd->event = sd_event_ref(event); - else { - r = sd_event_default(&nd->event); - if (r < 0) - return 0; - } - - nd->event_priority = priority; - - return 0; -} - -int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) { - assert_return(nd, -EINVAL); - - nd->event = sd_event_unref(nd->event); - - return 0; -} - -sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd) { - assert(nd); - - return nd->event; -} - -sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) { - - if (!nd) - return NULL; - - assert(nd->n_ref > 0); - nd->n_ref++; - - return nd; -} - -static int icmp6_nd_init(sd_icmp6_nd *nd) { - assert(nd); - - nd->recv = sd_event_source_unref(nd->recv); - nd->fd = asynchronous_close(nd->fd); - nd->timeout = sd_event_source_unref(nd->timeout); - - return 0; -} - -sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) { - ICMP6Prefix *prefix, *p; - - if (!nd) - return NULL; - - assert(nd->n_ref > 0); - nd->n_ref--; - - if (nd->n_ref > 0) - return NULL; - - icmp6_nd_init(nd); - sd_icmp6_nd_detach_event(nd); - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { - LIST_REMOVE(prefixes, nd->prefixes, prefix); - - prefix = icmp6_prefix_unref(prefix); - } - - free(nd); - - return NULL; -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_icmp6_nd*, sd_icmp6_nd_unref); -#define _cleanup_sd_icmp6_nd_free_ _cleanup_(sd_icmp6_nd_unrefp) - -int sd_icmp6_nd_new(sd_icmp6_nd **ret) { - _cleanup_sd_icmp6_nd_free_ sd_icmp6_nd *nd = NULL; - - assert(ret); - - nd = new0(sd_icmp6_nd, 1); - if (!nd) - return -ENOMEM; - - nd->n_ref = 1; - - nd->index = -1; - nd->fd = -1; - - LIST_HEAD_INIT(nd->prefixes); - - *ret = nd; - nd = NULL; - - return 0; -} - -int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) { - assert_return(nd, -EINVAL); - assert_return(mtu, -EINVAL); - - if (nd->mtu == 0) - return -ENOMSG; - - *mtu = nd->mtu; - - return 0; -} - -static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_icmp6_nd *nd = userdata; - ICMP6Prefix *prefix, *p; - - assert(nd); - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { - if (prefix->timeout_valid != s) - continue; - - log_icmp6_nd(nd, "Prefix expired "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len); - - LIST_REMOVE(prefixes, nd->prefixes, prefix); - - nd->expired_prefix = prefix; - icmp6_nd_notify(nd, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED); - nd->expired_prefix = NULL; - - prefix = icmp6_prefix_unref(prefix); - - break; - } - - return 0; -} - -static int icmp6_ra_prefix_set_timeout(sd_icmp6_nd *nd, - ICMP6Prefix *prefix, - usec_t valid) { - usec_t time_now; - int r; - - assert_return(prefix, -EINVAL); - - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - return r; - - prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid); - - r = sd_event_add_time(nd->event, &prefix->timeout_valid, - clock_boottime_or_monotonic(), time_now + valid, - USEC_PER_SEC, icmp6_ra_prefix_timeout, nd); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(prefix->timeout_valid, - nd->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(prefix->timeout_valid, - "icmp6-prefix-timeout"); - -error: - if (r < 0) - prefix->timeout_valid = - sd_event_source_unref(prefix->timeout_valid); - - return r; -} - -static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, - const struct in6_addr *addr, - uint8_t addr_prefixlen) { - uint8_t bytes, mask, len; - - assert_return(prefix, -EINVAL); - assert_return(addr, -EINVAL); - - len = MIN(prefixlen, addr_prefixlen); - - bytes = len / 8; - mask = 0xff << (8 - len % 8); - - if (memcmp(prefix, addr, bytes) != 0 || - (prefix->s6_addr[bytes] & mask) != (addr->s6_addr[bytes] & mask)) - return -EADDRNOTAVAIL; - - return 0; -} - -static int icmp6_ra_prefix_match(ICMP6Prefix *head, const struct in6_addr *addr, - uint8_t addr_len, ICMP6Prefix **result) { - ICMP6Prefix *prefix; - - LIST_FOREACH(prefixes, prefix, head) { - if (icmp6_prefix_match(&prefix->addr, prefix->len, addr, - addr_len) >= 0) { - *result = prefix; - return 0; - } - } - - return -EADDRNOTAVAIL; -} - -int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen, - struct in6_addr *addr) { - return icmp6_prefix_match(prefix, prefixlen, addr, - sizeof(addr->s6_addr) * 8); -} - -int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr, - uint8_t *prefixlen) { - int r; - ICMP6Prefix *prefix; - - assert_return(nd, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(prefixlen, -EINVAL); - - r = icmp6_ra_prefix_match(nd->prefixes, addr, - sizeof(addr->s6_addr) * 8, &prefix); - if (r < 0) - return r; - - *prefixlen = prefix->len; - - return 0; -} - -int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, uint8_t *prefixlen) { - assert_return(nd, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(prefixlen, -EINVAL); - - if (!nd->expired_prefix) - return -EADDRNOTAVAIL; - - *addr = &nd->expired_prefix->addr; - *prefixlen = nd->expired_prefix->len; - - return 0; -} - -static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len, - const struct nd_opt_prefix_info *prefix_opt) { - int r; - ICMP6Prefix *prefix; - uint32_t lifetime; - char time_string[FORMAT_TIMESPAN_MAX]; - - assert_return(nd, -EINVAL); - assert_return(prefix_opt, -EINVAL); - - if (len < prefix_opt->nd_opt_pi_len) - return -ENOMSG; - - if (!(prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)) - return 0; - - lifetime = be32toh(prefix_opt->nd_opt_pi_valid_time); - - r = icmp6_ra_prefix_match(nd->prefixes, - &prefix_opt->nd_opt_pi_prefix, - prefix_opt->nd_opt_pi_prefix_len, &prefix); - - if (r < 0 && r != -EADDRNOTAVAIL) - return r; - - /* if router advertisment prefix valid timeout is zero, the timeout - callback will be called immediately to clean up the prefix */ - - if (r == -EADDRNOTAVAIL) { - r = icmp6_prefix_new(&prefix); - if (r < 0) - return r; - - prefix->len = prefix_opt->nd_opt_pi_prefix_len; - - memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix, - sizeof(prefix->addr)); - - log_icmp6_nd(nd, "New prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - lifetime * USEC_PER_SEC, 0)); - - LIST_PREPEND(prefixes, nd->prefixes, prefix); - - } else { - if (prefix->len != prefix_opt->nd_opt_pi_prefix_len) { - uint8_t prefixlen; - - prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len); - - log_icmp6_nd(nd, "Prefix length mismatch %d/%d using %d", - prefix->len, - prefix_opt->nd_opt_pi_prefix_len, - prefixlen); - - prefix->len = prefixlen; - } - - log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - lifetime * USEC_PER_SEC, 0)); - } - - r = icmp6_ra_prefix_set_timeout(nd, prefix, lifetime * USEC_PER_SEC); - - return r; -} - -static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra, - ssize_t len) { - void *opt; - struct nd_opt_hdr *opt_hdr; - - assert_return(nd, -EINVAL); - assert_return(ra, -EINVAL); - - len -= sizeof(*ra); - if (len < ICMP6_OPT_LEN_UNITS) { - log_icmp6_nd(nd, "Router Advertisement below minimum length"); - - return -ENOMSG; - } - - opt = ra + 1; - opt_hdr = opt; - - while (len != 0 && len >= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS) { - struct nd_opt_mtu *opt_mtu; - uint32_t mtu; - struct nd_opt_prefix_info *opt_prefix; - - if (opt_hdr->nd_opt_len == 0) - return -ENOMSG; - - switch (opt_hdr->nd_opt_type) { - case ND_OPT_MTU: - opt_mtu = opt; - - mtu = be32toh(opt_mtu->nd_opt_mtu_mtu); - - if (mtu != nd->mtu) { - nd->mtu = MAX(mtu, IP6_MIN_MTU); - - log_icmp6_nd(nd, "Router Advertisement link MTU %d using %d", - mtu, nd->mtu); - } - - break; - - case ND_OPT_PREFIX_INFORMATION: - opt_prefix = opt; - - icmp6_ra_prefix_update(nd, len, opt_prefix); - - break; - } - - len -= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS; - opt = (void *)((char *)opt + - opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS); - opt_hdr = opt; - } - - if (len > 0) - log_icmp6_nd(nd, "Router Advertisement contains %zd bytes of trailing garbage", len); - - return 0; -} - -static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - sd_icmp6_nd *nd = userdata; - int r, buflen = 0; - ssize_t len; - _cleanup_free_ struct nd_router_advert *ra = NULL; - int event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE; - - assert(s); - assert(nd); - assert(nd->event); - - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0 || buflen <= 0) - buflen = ICMP6_ND_RECV_SIZE; - - ra = malloc(buflen); - if (!ra) - return -ENOMEM; - - len = read(fd, ra, buflen); - if (len < 0) { - log_icmp6_nd(nd, "Could not receive message from UDP socket: %m"); - return 0; - } - - if (ra->nd_ra_type != ND_ROUTER_ADVERT) - return 0; - - if (ra->nd_ra_code != 0) - return 0; - - nd->timeout = sd_event_source_unref(nd->timeout); - - nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN; - - if (ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER ) - event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER; - - if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) - event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED; - - log_icmp6_nd(nd, "Received Router Advertisement flags %s/%s", - ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED? "MANAGED": "none", - ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER? "OTHER": "none"); - - if (event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE) { - r = icmp6_ra_parse(nd, ra, len); - if (r < 0) { - log_icmp6_nd(nd, "Could not parse Router Advertisement: %s", - strerror(-r)); - return 0; - } - } - - icmp6_nd_notify(nd, event); - - return 0; -} - -static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { - sd_icmp6_nd *nd = userdata; - uint64_t time_now, next_timeout; - struct ether_addr unset = { }; - struct ether_addr *addr = NULL; - int r; - - assert(s); - assert(nd); - assert(nd->event); - - nd->timeout = sd_event_source_unref(nd->timeout); - - if (nd->nd_sent >= ICMP6_MAX_ROUTER_SOLICITATIONS) { - icmp6_nd_notify(nd, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT); - nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN; - } else { - if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr))) - addr = &nd->mac_addr; - - r = dhcp_network_icmp6_send_router_solicitation(nd->fd, addr); - if (r < 0) - log_icmp6_nd(nd, "Error sending Router Solicitation"); - else { - nd->state = ICMP6_ROUTER_SOLICITATION_SENT; - log_icmp6_nd(nd, "Sent Router Solicitation"); - } - - nd->nd_sent++; - - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) { - icmp6_nd_notify(nd, r); - return 0; - } - - next_timeout = time_now + ICMP6_ROUTER_SOLICITATION_INTERVAL; - - r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), - next_timeout, 0, - icmp6_router_solicitation_timeout, nd); - if (r < 0) { - icmp6_nd_notify(nd, r); - return 0; - } - - r = sd_event_source_set_priority(nd->timeout, - nd->event_priority); - if (r < 0) { - icmp6_nd_notify(nd, r); - return 0; - } - - r = sd_event_source_set_description(nd->timeout, "icmp6-timeout"); - if (r < 0) { - icmp6_nd_notify(nd, r); - return 0; - } - } - - return 0; -} - -int sd_icmp6_nd_stop(sd_icmp6_nd *nd) { - assert_return(nd, -EINVAL); - assert_return(nd->event, -EINVAL); - - log_icmp6_nd(client, "Stop ICMPv6"); - - icmp6_nd_init(nd); - - nd->state = ICMP6_NEIGHBOR_DISCOVERY_IDLE; - - return 0; -} - -int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) { - int r; - - assert(nd); - assert(nd->event); - - if (nd->state != ICMP6_NEIGHBOR_DISCOVERY_IDLE) - return -EINVAL; - - if (nd->index < 1) - return -EINVAL; - - r = dhcp_network_icmp6_bind_router_solicitation(nd->index); - if (r < 0) - return r; - - nd->fd = r; - - r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, - icmp6_router_advertisment_recv, nd); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(nd->recv, nd->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(nd->recv, "icmp6-receive-message"); - if (r < 0) - goto error; - - r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), - 0, 0, icmp6_router_solicitation_timeout, nd); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(nd->timeout, nd->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(nd->timeout, "icmp6-timeout"); -error: - if (r < 0) - icmp6_nd_init(nd); - else - log_icmp6_nd(client, "Start Router Solicitation"); - - return r; -} diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 95b96bfd52..5340fdc0c1 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -24,17 +24,19 @@ #include <stdlib.h> #include <string.h> +#include "sd-ipv4acd.h" + +#include "alloc-util.h" +#include "arp-util.h" #include "event-util.h" +#include "fd-util.h" #include "in-addr-util.h" #include "list.h" -#include "refcnt.h" #include "random-util.h" +#include "refcnt.h" #include "siphash24.h" #include "util.h" -#include "arp-util.h" -#include "sd-ipv4acd.h" - /* Constants from the RFC */ #define PROBE_WAIT 1 #define PROBE_NUM 3 @@ -468,7 +470,7 @@ int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){ return 0; } -bool sd_ipv4acd_is_running(sd_ipv4acd *ll) { +int sd_ipv4acd_is_running(sd_ipv4acd *ll) { assert_return(ll, false); return ll->state != IPV4ACD_STATE_INIT; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index dd427ddd78..0d915e20e7 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -18,13 +18,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <arpa/inet.h> #include <errno.h> -#include <string.h> #include <stdio.h> -#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sd-ipv4acd.h" +#include "sd-ipv4ll.h" +#include "alloc-util.h" #include "event-util.h" +#include "in-addr-util.h" #include "list.h" #include "random-util.h" #include "refcnt.h" @@ -32,9 +37,6 @@ #include "sparse-endian.h" #include "util.h" -#include "sd-ipv4acd.h" -#include "sd-ipv4ll.h" - #define IPV4LL_NETWORK 0xA9FE0000L #define IPV4LL_NETMASK 0xFFFF0000L @@ -226,12 +228,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) { return 0; } -bool sd_ipv4ll_is_running(sd_ipv4ll *ll) { +int sd_ipv4ll_is_running(sd_ipv4ll *ll) { assert_return(ll, false); return sd_ipv4acd_is_running(ll->acd); } +static bool ipv4ll_address_is_valid(const struct in_addr *address) { + uint32_t addr; + + assert(address); + + if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address)) + return false; + + addr = be32toh(address->s_addr); + + if ((addr & 0x0000FF00) == 0x0000 || + (addr & 0x0000FF00) == 0xFF00) + return false; + + return true; +} + +int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { + int r; + + assert_return(ll, -EINVAL); + assert_return(address, -EINVAL); + assert_return(ipv4ll_address_is_valid(address), -EINVAL); + + r = sd_ipv4acd_set_address(ll->acd, address); + if (r < 0) + return r; + + ll->address = address->s_addr; + + return 0; +} + static int ipv4ll_pick_address(sd_ipv4ll *ll) { struct in_addr in_addr; be32_t addr; @@ -247,18 +282,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) { return r; addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK); } while (addr == ll->address || - (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK || (ntohl(addr) & 0x0000FF00) == 0x0000 || (ntohl(addr) & 0x0000FF00) == 0xFF00); in_addr.s_addr = addr; - r = sd_ipv4acd_set_address(ll->acd, &in_addr); + r = sd_ipv4ll_set_address(ll, &in_addr); if (r < 0) return r; - ll->address = addr; - return 0; } diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 06949a1e83..4ebe8053fa 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -22,15 +22,19 @@ #include <arpa/inet.h> -#include "siphash24.h" -#include "hashmap.h" - -#include "lldp-tlv.h" -#include "lldp-port.h" #include "sd-lldp.h" -#include "prioq.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" #include "lldp-internal.h" +#include "lldp-port.h" +#include "lldp-tlv.h" #include "lldp-util.h" +#include "prioq.h" +#include "siphash24.h" +#include "string-util.h" typedef enum LLDPAgentRXState { LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4, diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c new file mode 100644 index 0000000000..0881973e7f --- /dev/null +++ b/src/libsystemd-network/sd-ndisc.c @@ -0,0 +1,672 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <netinet/icmp6.h> +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <stdbool.h> +#include <string.h> +#include <sys/ioctl.h> + +#include "sd-ndisc.h" + +#include "alloc-util.h" +#include "async.h" +#include "icmp6-util.h" +#include "in-addr-util.h" +#include "list.h" +#include "socket-util.h" + +#define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC +#define NDISC_MAX_ROUTER_SOLICITATIONS 3 + +enum NDiscState { + NDISC_STATE_IDLE, + NDISC_STATE_SOLICITATION_SENT, + NDISC_STATE_ADVERTISMENT_LISTEN, + _NDISC_STATE_MAX, + _NDISC_STATE_INVALID = -1, +}; + +#define IP6_MIN_MTU (unsigned)1280 +#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr)) +#define NDISC_OPT_LEN_UNITS 8 + +#define ND_RA_FLAG_PREF 0x18 +#define ND_RA_FLAG_PREF_LOW 0x03 +#define ND_RA_FLAG_PREF_MEDIUM 0x0 +#define ND_RA_FLAG_PREF_HIGH 0x1 +#define ND_RA_FLAG_PREF_INVALID 0x2 + +typedef struct NDiscPrefix NDiscPrefix; + +struct NDiscPrefix { + unsigned n_ref; + + sd_ndisc *nd; + + LIST_FIELDS(NDiscPrefix, prefixes); + + uint8_t len; + usec_t valid_until; + struct in6_addr addr; +}; + +struct sd_ndisc { + unsigned n_ref; + + enum NDiscState state; + sd_event *event; + int event_priority; + int index; + struct ether_addr mac_addr; + uint32_t mtu; + LIST_HEAD(NDiscPrefix, prefixes); + int fd; + sd_event_source *recv; + sd_event_source *timeout; + int nd_sent; + sd_ndisc_router_callback_t router_callback; + sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback; + sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback; + sd_ndisc_callback_t callback; + void *userdata; +}; + +#define log_ndisc(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__) + +static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) { + + if (!prefix) + return NULL; + + assert(prefix->n_ref > 0); + prefix->n_ref--; + + if (prefix->n_ref > 0) + return NULL; + + if (prefix->nd) + LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix); + + free(prefix); + + return NULL; +} + +static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) { + _cleanup_free_ NDiscPrefix *prefix = NULL; + + assert(ret); + + prefix = new0(NDiscPrefix, 1); + if (!prefix) + return -ENOMEM; + + prefix->n_ref = 1; + LIST_INIT(prefixes, prefix); + prefix->nd = nd; + + *ret = prefix; + prefix = NULL; + + return 0; +} + +int sd_ndisc_set_callback(sd_ndisc *nd, + sd_ndisc_router_callback_t router_callback, + sd_ndisc_prefix_onlink_callback_t prefix_onlink_callback, + sd_ndisc_prefix_autonomous_callback_t prefix_autonomous_callback, + sd_ndisc_callback_t callback, + void *userdata) { + assert(nd); + + nd->router_callback = router_callback; + nd->prefix_onlink_callback = prefix_onlink_callback; + nd->prefix_autonomous_callback = prefix_autonomous_callback; + nd->callback = callback; + nd->userdata = userdata; + + return 0; +} + +int sd_ndisc_set_index(sd_ndisc *nd, int interface_index) { + assert(nd); + assert(interface_index >= -1); + + nd->index = interface_index; + + return 0; +} + +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { + assert(nd); + + if (mac_addr) + memcpy(&nd->mac_addr, mac_addr, sizeof(nd->mac_addr)); + else + zero(nd->mac_addr); + + return 0; + +} + +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) { + int r; + + assert_return(nd, -EINVAL); + assert_return(!nd->event, -EBUSY); + + if (event) + nd->event = sd_event_ref(event); + else { + r = sd_event_default(&nd->event); + if (r < 0) + return 0; + } + + nd->event_priority = priority; + + return 0; +} + +int sd_ndisc_detach_event(sd_ndisc *nd) { + assert_return(nd, -EINVAL); + + nd->event = sd_event_unref(nd->event); + + return 0; +} + +sd_event *sd_ndisc_get_event(sd_ndisc *nd) { + assert(nd); + + return nd->event; +} + +sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { + + if (!nd) + return NULL; + + assert(nd->n_ref > 0); + nd->n_ref++; + + return nd; +} + +static int ndisc_init(sd_ndisc *nd) { + assert(nd); + + nd->recv = sd_event_source_unref(nd->recv); + nd->fd = asynchronous_close(nd->fd); + nd->timeout = sd_event_source_unref(nd->timeout); + + return 0; +} + +sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { + NDiscPrefix *prefix, *p; + + if (!nd) + return NULL; + + assert(nd->n_ref > 0); + nd->n_ref--; + + if (nd->n_ref > 0) + return NULL; + + ndisc_init(nd); + sd_ndisc_detach_event(nd); + + LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) + prefix = ndisc_prefix_unref(prefix); + + free(nd); + + return NULL; +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ndisc*, sd_ndisc_unref); +#define _cleanup_sd_ndisc_free_ _cleanup_(sd_ndisc_unrefp) + +int sd_ndisc_new(sd_ndisc **ret) { + _cleanup_sd_ndisc_free_ sd_ndisc *nd = NULL; + + assert(ret); + + nd = new0(sd_ndisc, 1); + if (!nd) + return -ENOMEM; + + nd->n_ref = 1; + + nd->index = -1; + nd->fd = -1; + + LIST_HEAD_INIT(nd->prefixes); + + *ret = nd; + nd = NULL; + + return 0; +} + +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) { + assert_return(nd, -EINVAL); + assert_return(mtu, -EINVAL); + + if (nd->mtu == 0) + return -ENOMSG; + + *mtu = nd->mtu; + + return 0; +} + +static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, + const struct in6_addr *addr, + uint8_t addr_prefixlen) { + uint8_t bytes, mask, len; + + assert_return(prefix, -EINVAL); + assert_return(addr, -EINVAL); + + len = MIN(prefixlen, addr_prefixlen); + + bytes = len / 8; + mask = 0xff << (8 - len % 8); + + if (memcmp(prefix, addr, bytes) != 0 || + (prefix->s6_addr[bytes] & mask) != (addr->s6_addr[bytes] & mask)) + return -EADDRNOTAVAIL; + + return 0; +} + +static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr, + uint8_t addr_len, NDiscPrefix **result) { + NDiscPrefix *prefix, *p; + usec_t time_now; + int r; + + assert(nd); + + r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; + + LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { + if (prefix->valid_until < time_now) { + prefix = ndisc_prefix_unref(prefix); + + continue; + } + + if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) { + *result = prefix; + return 0; + } + } + + return -EADDRNOTAVAIL; +} + +static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, + const struct nd_opt_prefix_info *prefix_opt) { + NDiscPrefix *prefix; + uint32_t lifetime_valid, lifetime_preferred; + usec_t time_now; + char time_string[FORMAT_TIMESPAN_MAX]; + int r; + + assert(nd); + assert(prefix_opt); + + if (len < prefix_opt->nd_opt_pi_len) + return -ENOMSG; + + if (!(prefix_opt->nd_opt_pi_flags_reserved & (ND_OPT_PI_FLAG_ONLINK | ND_OPT_PI_FLAG_AUTO))) + return 0; + + if (in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &prefix_opt->nd_opt_pi_prefix) > 0) + return 0; + + lifetime_valid = be32toh(prefix_opt->nd_opt_pi_valid_time); + lifetime_preferred = be32toh(prefix_opt->nd_opt_pi_preferred_time); + + if (lifetime_valid < lifetime_preferred) + return 0; + + r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix, + prefix_opt->nd_opt_pi_prefix_len, &prefix); + + if (r < 0 && r != -EADDRNOTAVAIL) + return r; + + /* if router advertisment prefix valid timeout is zero, the timeout + callback will be called immediately to clean up the prefix */ + + if (r == -EADDRNOTAVAIL) { + r = ndisc_prefix_new(nd, &prefix); + if (r < 0) + return r; + + prefix->len = prefix_opt->nd_opt_pi_prefix_len; + + memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix, + sizeof(prefix->addr)); + + log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", + SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), + prefix->len, lifetime_valid, + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); + + LIST_PREPEND(prefixes, nd->prefixes, prefix); + + } else { + if (prefix->len != prefix_opt->nd_opt_pi_prefix_len) { + uint8_t prefixlen; + + prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len); + + log_ndisc(nd, "Prefix length mismatch %d/%d using %d", + prefix->len, + prefix_opt->nd_opt_pi_prefix_len, + prefixlen); + + prefix->len = prefixlen; + } + + log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", + SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), + prefix->len, lifetime_valid, + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); + } + + r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; + + prefix->valid_until = time_now + lifetime_valid * USEC_PER_SEC; + + if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) && nd->prefix_onlink_callback) + nd->prefix_onlink_callback(nd, &prefix->addr, prefix->len, prefix->valid_until, nd->userdata); + + if ((prefix_opt->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) && nd->prefix_autonomous_callback) + nd->prefix_autonomous_callback(nd, &prefix->addr, prefix->len, lifetime_preferred, lifetime_valid, + nd->userdata); + + return 0; +} + +static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, + ssize_t len) { + void *opt; + struct nd_opt_hdr *opt_hdr; + + assert_return(nd, -EINVAL); + assert_return(ra, -EINVAL); + + len -= sizeof(*ra); + if (len < NDISC_OPT_LEN_UNITS) { + log_ndisc(nd, "Router Advertisement below minimum length"); + + return -ENOMSG; + } + + opt = ra + 1; + opt_hdr = opt; + + while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) { + struct nd_opt_mtu *opt_mtu; + uint32_t mtu; + struct nd_opt_prefix_info *opt_prefix; + + if (opt_hdr->nd_opt_len == 0) + return -ENOMSG; + + switch (opt_hdr->nd_opt_type) { + case ND_OPT_MTU: + opt_mtu = opt; + + mtu = be32toh(opt_mtu->nd_opt_mtu_mtu); + + if (mtu != nd->mtu) { + nd->mtu = MAX(mtu, IP6_MIN_MTU); + + log_ndisc(nd, "Router Advertisement link MTU %d using %d", + mtu, nd->mtu); + } + + break; + + case ND_OPT_PREFIX_INFORMATION: + opt_prefix = opt; + + ndisc_prefix_update(nd, len, opt_prefix); + + break; + } + + len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS; + opt = (void *)((char *)opt + + opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS); + opt_hdr = opt; + } + + if (len > 0) + log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len); + + return 0; +} + +static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_free_ struct nd_router_advert *ra = NULL; + sd_ndisc *nd = userdata; + int r, buflen = 0, pref, stateful; + union sockaddr_union router = {}; + socklen_t router_len = sizeof(router); + unsigned lifetime; + ssize_t len; + + assert(s); + assert(nd); + assert(nd->event); + + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0 || buflen <= 0) + buflen = ICMP6_RECV_SIZE; + + ra = malloc(buflen); + if (!ra) + return -ENOMEM; + + len = recvfrom(fd, ra, buflen, 0, &router.sa, &router_len); + if (len < 0) { + log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m"); + return 0; + } else if (router_len != sizeof(router.in6) && router_len != 0) { + log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)router_len); + return 0; + } + + if (ra->nd_ra_type != ND_ROUTER_ADVERT) + return 0; + + if (ra->nd_ra_code != 0) + return 0; + + nd->timeout = sd_event_source_unref(nd->timeout); + + nd->state = NDISC_STATE_ADVERTISMENT_LISTEN; + + stateful = ra->nd_ra_flags_reserved & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER); + pref = (ra->nd_ra_flags_reserved & ND_RA_FLAG_PREF) >> 3; + + switch (pref) { + case ND_RA_FLAG_PREF_LOW: + case ND_RA_FLAG_PREF_HIGH: + break; + default: + pref = ND_RA_FLAG_PREF_MEDIUM; + break; + } + + lifetime = be16toh(ra->nd_ra_router_lifetime); + + log_ndisc(nd, "Received Router Advertisement: flags %s preference %s lifetime %u sec", + stateful & ND_RA_FLAG_MANAGED ? "MANAGED" : stateful & ND_RA_FLAG_OTHER ? "OTHER" : "none", + pref == ND_RA_FLAG_PREF_HIGH ? "high" : pref == ND_RA_FLAG_PREF_LOW ? "low" : "medium", + lifetime); + + r = ndisc_ra_parse(nd, ra, len); + if (r < 0) { + log_ndisc(nd, "Could not parse Router Advertisement: %s", strerror(-r)); + return 0; + } + + if (nd->router_callback) + nd->router_callback(nd, stateful, router_len != 0 ? &router.in6.sin6_addr : NULL, lifetime, pref, nd->userdata); + + return 0; +} + +static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { + sd_ndisc *nd = userdata; + uint64_t time_now, next_timeout; + struct ether_addr unset = { }; + struct ether_addr *addr = NULL; + int r; + + assert(s); + assert(nd); + assert(nd->event); + + nd->timeout = sd_event_source_unref(nd->timeout); + + if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) { + if (nd->callback) + nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata); + nd->state = NDISC_STATE_ADVERTISMENT_LISTEN; + } else { + if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr))) + addr = &nd->mac_addr; + + r = icmp6_send_router_solicitation(nd->fd, addr); + if (r < 0) + log_ndisc(nd, "Error sending Router Solicitation"); + else { + nd->state = NDISC_STATE_SOLICITATION_SENT; + log_ndisc(nd, "Sent Router Solicitation"); + } + + nd->nd_sent++; + + assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0); + + next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL; + + r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), + next_timeout, 0, + ndisc_router_solicitation_timeout, nd); + if (r < 0) { + /* we cannot continue if we are unable to rearm the timer */ + sd_ndisc_stop(nd); + return 0; + } + + r = sd_event_source_set_priority(nd->timeout, nd->event_priority); + if (r < 0) + return 0; + + r = sd_event_source_set_description(nd->timeout, "ndisc-timeout"); + if (r < 0) + return 0; + } + + return 0; +} + +int sd_ndisc_stop(sd_ndisc *nd) { + assert_return(nd, -EINVAL); + assert_return(nd->event, -EINVAL); + + log_ndisc(client, "Stop NDisc"); + + ndisc_init(nd); + + nd->state = NDISC_STATE_IDLE; + + if (nd->callback) + nd->callback(nd, SD_NDISC_EVENT_STOP, nd->userdata); + + return 0; +} + +int sd_ndisc_router_discovery_start(sd_ndisc *nd) { + int r; + + assert(nd); + assert(nd->event); + + if (nd->state != NDISC_STATE_IDLE) + return -EINVAL; + + if (nd->index < 1) + return -EINVAL; + + r = icmp6_bind_router_solicitation(nd->index); + if (r < 0) + return r; + + nd->fd = r; + + r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, + ndisc_router_advertisment_recv, nd); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(nd->recv, nd->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(nd->recv, "ndisc-receive-message"); + if (r < 0) + goto error; + + r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), + 0, 0, ndisc_router_solicitation_timeout, nd); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(nd->timeout, nd->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(nd->timeout, "ndisc-timeout"); +error: + if (r < 0) + ndisc_init(nd); + else + log_ndisc(client, "Start Router Solicitation"); + + return r; +} diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c deleted file mode 100644 index cd5a204f8c..0000000000 --- a/src/libsystemd-network/sd-pppoe.c +++ /dev/null @@ -1,810 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -/* See RFC 2516 */ - -#include <sys/ioctl.h> -#include <linux/ppp_defs.h> -#include <linux/ppp-ioctl.h> -#include <net/if.h> -#include <netinet/in.h> -#include <linux/if_pppox.h> - -#include "sd-pppoe.h" - -#include "event-util.h" - -#include "util.h" -#include "random-util.h" -#include "socket-util.h" -#include "async.h" -#include "utf8.h" - -#define PPPOE_MAX_PACKET_SIZE 1484 -#define PPPOE_MAX_PADR_RESEND 16 - -/* TODO: move this to socket-util.h without getting into - * a mess with the includes */ -union sockaddr_union_pppox { - struct sockaddr sa; - struct sockaddr_pppox pppox; -}; - -typedef enum PPPoEState { - PPPOE_STATE_INITIALIZING, - PPPOE_STATE_REQUESTING, - PPPOE_STATE_RUNNING, - PPPOE_STATE_STOPPED, - _PPPOE_STATE_MAX, - _PPPOE_STATE_INVALID = -1, -} PPPoEState; - -typedef struct PPPoETags { - char *service_name; - char *ac_name; - uint8_t *host_uniq; - size_t host_uniq_len; - uint8_t *cookie; - size_t cookie_len; -} PPPoETags; - -struct sd_pppoe { - unsigned n_ref; - - PPPoEState state; - uint64_t host_uniq; - - int ifindex; - char *ifname; - - sd_event *event; - int event_priority; - int fd; - sd_event_source *io; - sd_event_source *timeout; - int padr_resend_count; - - char *service_name; - struct ether_addr peer_mac; - be16_t session_id; - - int pppoe_fd; - int channel; - - sd_pppoe_cb_t cb; - void *userdata; - - PPPoETags tags; -}; - -#define PPPOE_PACKET_LENGTH(header) \ - be16toh((header)->length) - -#define PPPOE_PACKET_TAIL(packet) \ - (struct pppoe_tag*)((uint8_t*)(packet) + sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet)) - -#define PPPOE_TAG_LENGTH(tag) \ - be16toh((tag)->tag_len) - -#define PPPOE_TAG_TYPE(tag) \ - (tag)->tag_type - -#define PPPOE_TAG_NEXT(tag) \ - (struct pppoe_tag *)((uint8_t *)(tag) + sizeof(struct pppoe_tag) + PPPOE_TAG_LENGTH(tag)) - -#define PPPOE_TAGS_FOREACH(tag, header) \ - for (tag = (header)->tag; \ - ((uint8_t *)(tag) + sizeof(struct pppoe_tag) < (uint8_t*)PPPOE_PACKET_TAIL(header)) && \ - (PPPOE_TAG_NEXT(tag) <= PPPOE_PACKET_TAIL(header)) && \ - (tag >= (header)->tag) && \ - (PPPOE_TAG_TYPE(tag) != PTT_EOL); \ - tag = PPPOE_TAG_NEXT(tag)) - -static void pppoe_tags_clear(PPPoETags *tags) { - free(tags->service_name); - free(tags->ac_name); - free(tags->host_uniq); - free(tags->cookie); - - zero(*tags); -} - -int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex) { - assert_return(ppp, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - - ppp->ifindex = ifindex; - - return 0; -} - -int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname) { - char *name; - - assert_return(ppp, -EINVAL); - assert_return(ifname, -EINVAL); - - if (strlen(ifname) > IFNAMSIZ) - return -EINVAL; - - name = strdup(ifname); - if (!name) - return -ENOMEM; - - free(ppp->ifname); - ppp->ifname = name; - - return 0; -} - -int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name) { - _cleanup_free_ char *name = NULL; - - assert_return(ppp, -EINVAL); - - if (service_name) { - name = strdup(service_name); - if (!name) - return -ENOMEM; - } - - free(ppp->service_name); - ppp->service_name = name; - name = NULL; - - return 0; -} - -int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority) { - int r; - - assert_return(ppp, -EINVAL); - assert_return(!ppp->event, -EBUSY); - - if (event) - ppp->event = sd_event_ref(event); - else { - r = sd_event_default(&ppp->event); - if (r < 0) - return r; - } - - ppp->event_priority = priority; - - return 0; -} - -int sd_pppoe_detach_event(sd_pppoe *ppp) { - assert_return(ppp, -EINVAL); - - ppp->event = sd_event_unref(ppp->event); - - return 0; -} - -sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp) { - - if (!ppp) - return NULL; - - assert(ppp->n_ref > 0); - ppp->n_ref++; - - return ppp; -} - -sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) { - - if (!ppp) - return NULL; - - assert(ppp->n_ref > 0); - ppp->n_ref--; - - if (ppp->n_ref > 0) - return NULL; - - pppoe_tags_clear(&ppp->tags); - free(ppp->ifname); - free(ppp->service_name); - sd_pppoe_stop(ppp); - sd_pppoe_detach_event(ppp); - - free(ppp); - return NULL; -} - -int sd_pppoe_new (sd_pppoe **ret) { - sd_pppoe *ppp; - - assert_return(ret, -EINVAL); - - ppp = new0(sd_pppoe, 1); - if (!ppp) - return -ENOMEM; - - ppp->n_ref = 1; - ppp->state = _PPPOE_STATE_INVALID; - ppp->ifindex = -1; - ppp->fd = -1; - ppp->pppoe_fd = -1; - ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND; - - *ret = ppp; - - return 0; -} - -int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel) { - assert_return(ppp, -EINVAL); - assert_return(channel, -EINVAL); - assert_return(ppp->pppoe_fd != -1, -EUNATCH); - assert_return(ppp->state == PPPOE_STATE_RUNNING, -EUNATCH); - - *channel = ppp->channel; - - return 0; -} - -int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata) { - assert_return(ppp, -EINVAL); - - ppp->cb = cb; - ppp->userdata = userdata; - - return 0; -} - -static void pppoe_tag_append(struct pppoe_hdr *packet, size_t packet_size, be16_t tag_type, const void *tag_data, uint16_t tag_len) { - struct pppoe_tag *tag; - - assert(packet); - assert(sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len <= packet_size); - assert(!(!tag_data ^ !tag_len)); - - tag = PPPOE_PACKET_TAIL(packet); - - tag->tag_len = htobe16(tag_len); - tag->tag_type = tag_type; - if (tag_data) - memcpy(tag->tag_data, tag_data, tag_len); - - packet->length = htobe16(PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len); -} - -static int pppoe_send(sd_pppoe *ppp, uint8_t code) { - union sockaddr_union link = { - .ll = { - .sll_family = AF_PACKET, - .sll_protocol = htons(ETH_P_PPP_DISC), - .sll_halen = ETH_ALEN, - }, - }; - _cleanup_free_ struct pppoe_hdr *packet = NULL; - int r; - - assert(ppp); - assert(ppp->fd != -1); - assert(IN_SET(code, PADI_CODE, PADR_CODE, PADT_CODE)); - - link.ll.sll_ifindex = ppp->ifindex; - if (code == PADI_CODE) - memset(&link.ll.sll_addr, 0xff, ETH_ALEN); - else - memcpy(&link.ll.sll_addr, &ppp->peer_mac, ETH_ALEN); - - packet = malloc0(PPPOE_MAX_PACKET_SIZE); - if (!packet) - return -ENOMEM; - - packet->ver = 0x1; - packet->type = 0x1; - packet->code = code; - if (code == PADT_CODE) - packet->sid = ppp->session_id; - - /* Service-Name */ - pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_SRV_NAME, - ppp->service_name, ppp->service_name ? strlen(ppp->service_name) : 0); - - /* AC-Cookie */ - if (code == PADR_CODE && ppp->tags.cookie) - pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_AC_COOKIE, - ppp->tags.cookie, ppp->tags.cookie_len); - - /* Host-Uniq */ - if (code != PADT_CODE) { - ppp->host_uniq = random_u64(); - - pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_HOST_UNIQ, - &ppp->host_uniq, sizeof(ppp->host_uniq)); - } - - r = sendto(ppp->fd, packet, sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet), - 0, &link.sa, sizeof(link.ll)); - if (r < 0) - return -errno; - - return 0; -} - -static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata); - -static int pppoe_arm_timeout(sd_pppoe *ppp) { - _cleanup_event_source_unref_ sd_event_source *timeout = NULL; - usec_t next_timeout = 0; - int r; - - assert(ppp); - - r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout); - if (r < 0) - return r; - - next_timeout += 500 * USEC_PER_MSEC; - - r = sd_event_add_time(ppp->event, &timeout, clock_boottime_or_monotonic(), next_timeout, - 10 * USEC_PER_MSEC, pppoe_timeout, ppp); - if (r < 0) - return r; - - r = sd_event_source_set_priority(timeout, ppp->event_priority); - if (r < 0) - return r; - - sd_event_source_unref(ppp->timeout); - ppp->timeout = timeout; - timeout = NULL; - - return 0; -} - -static int pppoe_send_initiation(sd_pppoe *ppp) { - int r; - - r = pppoe_send(ppp, PADI_CODE); - if (r < 0) - return r; - - log_debug("PPPoE: sent DISCOVER (Service-Name: %s)", - strna(ppp->service_name)); - - pppoe_arm_timeout(ppp); - - return r; -} - -static int pppoe_send_request(sd_pppoe *ppp) { - int r; - - r = pppoe_send(ppp, PADR_CODE); - if (r < 0) - return r; - - log_debug("PPPoE: sent REQUEST"); - - ppp->padr_resend_count --; - - pppoe_arm_timeout(ppp); - - return 0; -} - -static int pppoe_send_terminate(sd_pppoe *ppp) { - int r; - - r = pppoe_send(ppp, PADT_CODE); - if (r < 0) - return r; - - log_debug("PPPoE: sent TERMINATE"); - - return 0; -} - -static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata) { - sd_pppoe *ppp = userdata; - int r; - - assert(ppp); - - switch (ppp->state) { - case PPPOE_STATE_INITIALIZING: - r = pppoe_send_initiation(ppp); - if (r < 0) - log_warning_errno(r, "PPPoE: sending PADI failed: %m"); - - break; - case PPPOE_STATE_REQUESTING: - if (ppp->padr_resend_count <= 0) { - log_debug("PPPoE: PADR timed out, restarting PADI"); - - r = pppoe_send_initiation(ppp); - if (r < 0) - log_warning_errno(r, "PPPoE: sending PADI failed: %m"); - - ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND; - ppp->state = PPPOE_STATE_INITIALIZING; - } else { - r = pppoe_send_request(ppp); - if (r < 0) - log_warning_errno(r, "PPPoE: sending PADR failed: %m"); - } - - break; - default: - assert_not_reached("timeout in invalid state"); - } - - return 0; -} - -static int pppoe_tag_parse_binary(struct pppoe_tag *tag, uint8_t **ret, size_t *length) { - uint8_t *data; - - assert(ret); - assert(length); - - data = memdup(tag->tag_data, PPPOE_TAG_LENGTH(tag)); - if (!data) - return -ENOMEM; - - free(*ret); - *ret = data; - *length = PPPOE_TAG_LENGTH(tag); - - return 0; -} - -static int pppoe_tag_parse_string(struct pppoe_tag *tag, char **ret) { - char *string; - - assert(ret); - - string = strndup(tag->tag_data, PPPOE_TAG_LENGTH(tag)); - if (!string) - return -ENOMEM; - - free(*ret); - *ret = string; - - return 0; -} - -static int pppoe_payload_parse(PPPoETags *tags, struct pppoe_hdr *header) { - struct pppoe_tag *tag; - int r; - - assert(tags); - - pppoe_tags_clear(tags); - - PPPOE_TAGS_FOREACH(tag, header) { - switch (PPPOE_TAG_TYPE(tag)) { - case PTT_SRV_NAME: - r = pppoe_tag_parse_string(tag, &tags->service_name); - if (r < 0) - return r; - - break; - case PTT_AC_NAME: - r = pppoe_tag_parse_string(tag, &tags->ac_name); - if (r < 0) - return r; - - break; - case PTT_HOST_UNIQ: - r = pppoe_tag_parse_binary(tag, &tags->host_uniq, &tags->host_uniq_len); - if (r < 0) - return r; - - break; - case PTT_AC_COOKIE: - r = pppoe_tag_parse_binary(tag, &tags->cookie, &tags->cookie_len); - if (r < 0) - return r; - - break; - case PTT_SRV_ERR: - case PTT_SYS_ERR: - case PTT_GEN_ERR: - { - _cleanup_free_ char *error = NULL; - - /* TODO: do something more sensible with the error messages */ - r = pppoe_tag_parse_string(tag, &error); - if (r < 0) - return r; - - if (strlen(error) > 0 && utf8_is_valid(error)) - log_debug("PPPoE: error - '%s'", error); - else - log_debug("PPPoE: error"); - - break; - } - default: - log_debug("PPPoE: ignoring unknown PPPoE tag type: 0x%.2x", PPPOE_TAG_TYPE(tag)); - } - } - - return 0; -} - -static int pppoe_open_pppoe_socket(sd_pppoe *ppp) { - int s; - - assert(ppp); - assert(ppp->pppoe_fd == -1); - - s = socket(AF_PPPOX, SOCK_STREAM, 0); - if (s < 0) - return -errno; - - ppp->pppoe_fd = s; - - return 0; -} - -static int pppoe_connect_pppoe_socket(sd_pppoe *ppp) { - union sockaddr_union_pppox link = { - .pppox = { - .sa_family = AF_PPPOX, - .sa_protocol = PX_PROTO_OE, - }, - }; - int r, channel; - - assert(ppp); - assert(ppp->pppoe_fd != -1); - assert(ppp->session_id); - assert(ppp->ifname); - - link.pppox.sa_addr.pppoe.sid = ppp->session_id; - memcpy(link.pppox.sa_addr.pppoe.dev, ppp->ifname, strlen(ppp->ifname)); - memcpy(link.pppox.sa_addr.pppoe.remote, &ppp->peer_mac, ETH_ALEN); - - r = connect(ppp->pppoe_fd, &link.sa, sizeof(link.pppox)); - if (r < 0) - return r; - - r = ioctl(ppp->pppoe_fd, PPPIOCGCHAN, &channel); - if (r < 0) - return -errno; - - ppp->channel = channel; - - return 0; -} - -static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct ether_addr *mac) { - int r; - - assert(packet); - - if (packet->ver != 0x1 || packet->type != 0x1) - return 0; - - r = pppoe_payload_parse(&ppp->tags, packet); - if (r < 0) - return 0; - - switch (ppp->state) { - case PPPOE_STATE_INITIALIZING: - if (packet->code != PADO_CODE) - return 0; - - if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) || - memcmp(ppp->tags.host_uniq, &ppp->host_uniq, sizeof(ppp->host_uniq)) != 0) - return 0; - - log_debug("PPPoE: got OFFER (Peer: " - "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx; " - "Service-Name: '%s'; AC-Name: '%s')", - mac->ether_addr_octet[0], - mac->ether_addr_octet[1], - mac->ether_addr_octet[2], - mac->ether_addr_octet[3], - mac->ether_addr_octet[4], - mac->ether_addr_octet[5], - strempty(ppp->tags.service_name), - strempty(ppp->tags.ac_name)); - - memcpy(&ppp->peer_mac, mac, ETH_ALEN); - - r = pppoe_open_pppoe_socket(ppp); - if (r < 0) { - log_warning("PPPoE: could not open socket"); - return r; - } - - r = pppoe_send_request(ppp); - if (r < 0) - return 0; - - ppp->state = PPPOE_STATE_REQUESTING; - - break; - case PPPOE_STATE_REQUESTING: - if (packet->code != PADS_CODE) - return 0; - - if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) || - memcmp(ppp->tags.host_uniq, &ppp->host_uniq, - sizeof(ppp->host_uniq)) != 0) - return 0; - - if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0) - return 0; - - ppp->session_id = packet->sid; - - log_debug("PPPoE: got CONFIRMATION (Session ID: %"PRIu16")", - be16toh(ppp->session_id)); - - r = pppoe_connect_pppoe_socket(ppp); - if (r < 0) { - log_warning("PPPoE: could not connect socket"); - return r; - } - - ppp->state = PPPOE_STATE_RUNNING; - - ppp->timeout = sd_event_source_unref(ppp->timeout); - assert(ppp->cb); - ppp->cb(ppp, SD_PPPOE_EVENT_RUNNING, ppp->userdata); - - break; - case PPPOE_STATE_RUNNING: - if (packet->code != PADT_CODE) - return 0; - - if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0) - return 0; - - if (ppp->session_id != packet->sid) - return 0; - - log_debug("PPPoE: got TERMINATE"); - - ppp->state = PPPOE_STATE_STOPPED; - - assert(ppp->cb); - ppp->cb(ppp, SD_PPPOE_EVENT_STOPPED, ppp->userdata); - - break; - case PPPOE_STATE_STOPPED: - break; - default: - assert_not_reached("PPPoE: invalid state when receiving message"); - } - - return 0; -} - -static int pppoe_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - sd_pppoe *ppp = userdata; - _cleanup_free_ struct pppoe_hdr *packet = NULL; - union sockaddr_union link = {}; - socklen_t addrlen = sizeof(link); - int buflen = 0, len, r; - - assert(ppp); - assert(fd != -1); - - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return r; - - if (buflen < 0) - /* this can't be right */ - return -EIO; - - packet = malloc0(buflen); - if (!packet) - return -ENOMEM; - - len = recvfrom(fd, packet, buflen, 0, &link.sa, &addrlen); - if (len < 0) { - log_warning_errno(r, "PPPoE: could not receive message from raw socket: %m"); - return 0; - } else if ((size_t)len < sizeof(struct pppoe_hdr)) - return 0; - else if ((size_t)len != sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet)) - return 0; - - if (link.ll.sll_halen != ETH_ALEN) - /* not ethernet? */ - return 0; - - r = pppoe_handle_message(ppp, packet, (struct ether_addr*)&link.ll.sll_addr); - if (r < 0) - return r; - - return 1; -} - -int sd_pppoe_start(sd_pppoe *ppp) { - union sockaddr_union link = { - .ll = { - .sll_family = AF_PACKET, - .sll_protocol = htons(ETH_P_PPP_DISC), - }, - }; - _cleanup_close_ int s = -1; - _cleanup_event_source_unref_ sd_event_source *io = NULL; - int r; - - assert_return(ppp, -EINVAL); - assert_return(ppp->fd == -1, -EBUSY); - assert_return(!ppp->io, -EBUSY); - assert_return(ppp->ifindex > 0, -EUNATCH); - assert_return(ppp->ifname, -EUNATCH); - assert_return(ppp->event, -EUNATCH); - assert_return(ppp->cb, -EUNATCH); - - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - link.ll.sll_ifindex = ppp->ifindex; - - r = bind(s, &link.sa, sizeof(link.ll)); - if (r < 0) - return r; - - r = sd_event_add_io(ppp->event, &io, - s, EPOLLIN, pppoe_receive_message, - ppp); - if (r < 0) - return r; - - r = sd_event_source_set_priority(io, ppp->event_priority); - if (r < 0) - return r; - - ppp->fd = s; - s = -1; - ppp->io = io; - io = NULL; - - r = pppoe_send_initiation(ppp); - if (r < 0) - return r; - - ppp->state = PPPOE_STATE_INITIALIZING; - - return 0; -} - -int sd_pppoe_stop(sd_pppoe *ppp) { - assert_return(ppp, -EINVAL); - - if (ppp->state == PPPOE_STATE_RUNNING) - pppoe_send_terminate(ppp); - - ppp->io = sd_event_source_unref(ppp->io); - ppp->timeout = sd_event_source_unref(ppp->timeout); - ppp->fd = asynchronous_close(ppp->fd); - ppp->pppoe_fd = asynchronous_close(ppp->pppoe_fd); - - return 0; -} diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index c112ec8134..5b52c1cbb9 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -24,14 +24,16 @@ #include <sys/socket.h> #include <unistd.h> -#include "util.h" +#include "sd-dhcp-client.h" #include "sd-event.h" -#include "event-util.h" +#include "alloc-util.h" #include "dhcp-identifier.h" -#include "dhcp-protocol.h" #include "dhcp-internal.h" -#include "sd-dhcp-client.h" +#include "dhcp-protocol.h" +#include "event-util.h" +#include "util.h" +#include "fd-util.h" static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'}; diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index b1ef174849..2d29e28f16 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -5,11 +5,11 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "macro.h" - -#include "dhcp-protocol.h" +#include "alloc-util.h" #include "dhcp-internal.h" +#include "dhcp-protocol.h" +#include "macro.h" +#include "util.h" struct option_desc { uint8_t sname[64]; diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index c3bcb9cb4b..1a5c8c4605 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -22,11 +22,11 @@ #include <errno.h> +#include "sd-dhcp-server.h" #include "sd-event.h" -#include "event-util.h" -#include "sd-dhcp-server.h" #include "dhcp-server-internal.h" +#include "event-util.h" static void test_pool(struct in_addr *address, unsigned size, int ret) { _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 0c131a9897..17ed6d58f3 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -19,23 +19,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <net/ethernet.h> #include <stdbool.h> #include <stdio.h> -#include <sys/types.h> #include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> -#include <net/ethernet.h> -#include "socket-util.h" -#include "macro.h" +#include "sd-dhcp6-client.h" #include "sd-event.h" -#include "event-util.h" -#include "virt.h" -#include "sd-dhcp6-client.h" -#include "dhcp6-protocol.h" #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" +#include "dhcp6-protocol.h" +#include "event-util.h" +#include "fd-util.h" +#include "macro.h" +#include "socket-util.h" +#include "virt.h" static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} @@ -700,7 +701,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { static int test_client_solicit(sd_event *e) { sd_dhcp6_client *client; usec_t time_now = now(clock_boottime_or_monotonic()); - bool val = true; + int val = true; if (verbose) printf("* %s\n", __FUNCTION__); diff --git a/src/libsystemd-network/test-icmp6-rs.c b/src/libsystemd-network/test-icmp6-rs.c deleted file mode 100644 index 27b0ef4572..0000000000 --- a/src/libsystemd-network/test-icmp6-rs.c +++ /dev/null @@ -1,357 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <netinet/icmp6.h> - -#include "socket-util.h" - -#include "dhcp6-internal.h" -#include "sd-icmp6-nd.h" - -static struct ether_addr mac_addr = { - .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} -}; - -static bool verbose = false; -static sd_event_source *test_hangcheck; -static int test_fd[2]; - -typedef int (*send_ra_t)(uint8_t flags); -static send_ra_t send_ra_function; - -static int test_rs_hangcheck(sd_event_source *s, uint64_t usec, - void *userdata) { - assert_se(false); - - return 0; -} - -int dhcp_network_icmp6_bind_router_solicitation(int index) { - assert_se(index == 42); - - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0) - return -errno; - - return test_fd[0]; -} - -static int send_ra_short_prefix(uint8_t flags) { - uint8_t advertisement[] = { - 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x03, 0x04, 0x34, 0xc0, 0x00, 0x00, 0x01, 0xf4, - 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == - sizeof(advertisement)); - - return 0; -} - -static void test_short_prefix_cb(sd_icmp6_nd *nd, int event, void *userdata) { - sd_event *e = userdata; - struct { - struct in6_addr addr; - uint8_t prefixlen; - bool success; - } addrs[] = { - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 52, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, false }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 60, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }, - 52, true }, - }; - uint8_t prefixlen; - unsigned int i; - - for (i = 0; i < ELEMENTSOF(addrs); i++) { - printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x", - __FUNCTION__, - addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1], - addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3], - addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5], - addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]); - - if (addrs[i].success) { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) >= 0); - assert_se(addrs[i].prefixlen == prefixlen); - printf("/%d onlink\n", prefixlen); - } else { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) == -EADDRNOTAVAIL); - printf("/128 offlink\n"); - } - } - - sd_event_exit(e, 0); -} - -static int send_ra_prefixes(uint8_t flags) { - uint8_t advertisement[] = { - 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x3f, 0xc0, 0x00, 0x00, 0x01, 0xf4, - 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58, - 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x3c, 0x80, 0x00, 0x00, 0x03, 0x84, - 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x03, 0x84, - 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, - 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53 - }; - - assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == - sizeof(advertisement)); - - return 0; -} - -static void test_prefixes_cb(sd_icmp6_nd *nd, int event, void *userdata) { - sd_event *e = userdata; - struct { - struct in6_addr addr; - uint8_t prefixlen; - bool success; - } addrs[] = { - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 63, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, false }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 60, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }, - 63, false }, - }; - uint8_t prefixlen; - unsigned int i; - - for (i = 0; i < ELEMENTSOF(addrs); i++) { - printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x", - __FUNCTION__, - addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1], - addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3], - addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5], - addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]); - - if (addrs[i].success) { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) >= 0); - assert_se(addrs[i].prefixlen == prefixlen); - printf("/%d onlink\n", prefixlen); - } else { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) == -EADDRNOTAVAIL); - printf("/128 offlink\n"); - } - } - - send_ra_function = send_ra_short_prefix; - assert_se(sd_icmp6_nd_set_callback(nd, test_short_prefix_cb, e) >= 0); - assert_se(sd_icmp6_nd_stop(nd) >= 0); - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); -} - -static void test_prefixes(void) { - sd_event *e; - sd_icmp6_nd *nd; - - if (verbose) - printf("* %s\n", __FUNCTION__); - - send_ra_function = send_ra_prefixes; - - assert_se(sd_event_new(&e) >= 0); - - assert_se(sd_icmp6_nd_new(&nd) >= 0); - assert_se(nd); - - assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0); - - assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0); - assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0); - assert_se(sd_icmp6_nd_set_callback(nd, test_prefixes_cb, e) >= 0); - - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); - - sd_event_loop(e); - - nd = sd_icmp6_nd_unref(nd); - assert_se(!nd); - - close(test_fd[1]); - - sd_event_unref(e); -} - -static int send_ra(uint8_t flags) { - uint8_t advertisement[] = { - 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4, - 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, - 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, - }; - - advertisement[5] = flags; - - assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == - sizeof(advertisement)); - - if (verbose) - printf(" sent RA with flag 0x%02x\n", flags); - - return 0; -} - -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { - return send_ra_function(0); -} - -static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) { - sd_event *e = userdata; - static int idx = 0; - struct { - uint8_t flag; - int event; - } flag_event[] = { - { 0, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE }, - { ND_RA_FLAG_OTHER, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER }, - { ND_RA_FLAG_MANAGED, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED } - }; - uint32_t mtu; - - assert_se(nd); - - assert_se(event == flag_event[idx].event); - idx++; - - if (verbose) - printf(" got event %d\n", event); - - if (idx < 3) { - send_ra(flag_event[idx].flag); - return; - } - - assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG); - - sd_event_exit(e, 0); -} - -static void test_rs(void) { - sd_event *e; - sd_icmp6_nd *nd; - usec_t time_now = now(clock_boottime_or_monotonic()); - - if (verbose) - printf("* %s\n", __FUNCTION__); - - send_ra_function = send_ra; - - assert_se(sd_event_new(&e) >= 0); - - assert_se(sd_icmp6_nd_new(&nd) >= 0); - assert_se(nd); - - assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0); - - assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0); - assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0); - assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0); - - assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), - time_now + 2 *USEC_PER_SEC, 0, - test_rs_hangcheck, NULL) >= 0); - - assert_se(sd_icmp6_nd_stop(nd) >= 0); - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); - assert_se(sd_icmp6_nd_stop(nd) >= 0); - - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); - - sd_event_loop(e); - - test_hangcheck = sd_event_source_unref(test_hangcheck); - - nd = sd_icmp6_nd_unref(nd); - assert_se(!nd); - - close(test_fd[1]); - - sd_event_unref(e); -} - -int main(int argc, char *argv[]) { - - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); - - test_rs(); - test_prefixes(); - - return 0; -} diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c index dd2e44e7a3..913a929069 100644 --- a/src/libsystemd-network/test-ipv4ll-manual.c +++ b/src/libsystemd-network/test-ipv4ll-manual.c @@ -19,21 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> +#include <net/if.h> +#include <stdlib.h> #include <unistd.h> - #include <linux/veth.h> -#include <net/if.h> #include "sd-event.h" -#include "sd-netlink.h" #include "sd-ipv4ll.h" +#include "sd-netlink.h" -#include "util.h" +#include "alloc-util.h" #include "event-util.h" -#include "netlink-util.h" #include "in-addr-util.h" +#include "netlink-util.h" +#include "parse-util.h" +#include "string-util.h" +#include "util.h" static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) { _cleanup_free_ char *address = NULL; diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index e72204d992..6f416c51e4 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -18,20 +18,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <assert.h> #include <errno.h> #include <stdio.h> -#include <sys/types.h> +#include <stdlib.h> #include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" -#include "event-util.h" - #include "sd-ipv4ll.h" + #include "arp-util.h" +#include "event-util.h" +#include "fd-util.h" +#include "socket-util.h" +#include "util.h" static bool verbose = false; static bool extended = false; @@ -100,6 +101,7 @@ int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_ad } static void test_public_api_setters(sd_event *e) { + struct in_addr address = {}; unsigned seed = 0; sd_ipv4ll *ll; struct ether_addr mac_addr = { @@ -118,6 +120,16 @@ static void test_public_api_setters(sd_event *e) { assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL); assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + address.s_addr |= htobe32(169U << 24 | 254U << 16); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + address.s_addr |= htobe32(0x00FF); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + address.s_addr |= htobe32(0xF000); + assert_se(sd_ipv4ll_set_address(ll, &address) == 0); + address.s_addr |= htobe32(0x0F00); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + assert_se(sd_ipv4ll_set_address_seed(NULL, seed) == -EINVAL); assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0); diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index e57102a576..99545d0b8b 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -20,18 +20,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <arpa/inet.h> +#include <net/ethernet.h> #include <stdio.h> #include <string.h> -#include <net/ethernet.h> -#include <arpa/inet.h> -#include "sd-lldp.h" #include "sd-event.h" +#include "sd-lldp.h" + +#include "alloc-util.h" #include "event-util.h" -#include "macro.h" -#include "lldp.h" -#include "lldp-tlv.h" +#include "fd-util.h" #include "lldp-network.h" +#include "lldp-tlv.h" +#include "lldp.h" +#include "macro.h" +#include "string-util.h" #define TEST_LLDP_PORT "em1" #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp" @@ -50,7 +54,7 @@ static int lldp_build_tlv_packet(tlv_packet **ret) { .ether_type = htons(ETHERTYPE_LLDP), }; - /* Append ethernet header */ + /* Append Ethernet header */ memcpy(ðer.ether_dhost, lldp_dst, ETHER_ADDR_LEN); memcpy(ðer.ether_shost, &mac_addr, ETHER_ADDR_LEN); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c new file mode 100644 index 0000000000..a485be704e --- /dev/null +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -0,0 +1,170 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <netinet/icmp6.h> + +#include "sd-ndisc.h" + +#include "icmp6-util.h" +#include "socket-util.h" + +static struct ether_addr mac_addr = { + .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} +}; + +static bool verbose = false; +static sd_event_source *test_hangcheck; +static int test_fd[2]; + +typedef int (*send_ra_t)(uint8_t flags); +static send_ra_t send_ra_function; + +static int test_rs_hangcheck(sd_event_source *s, uint64_t usec, + void *userdata) { + assert_se(false); + + return 0; +} + +int icmp6_bind_router_solicitation(int index) { + assert_se(index == 42); + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0) + return -errno; + + return test_fd[0]; +} + +static int send_ra(uint8_t flags) { + uint8_t advertisement[] = { + 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4, + 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, + 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, + }; + + advertisement[5] = flags; + + assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == + sizeof(advertisement)); + + if (verbose) + printf(" sent RA with flag 0x%02x\n", flags); + + return 0; +} + +int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { + return send_ra_function(0); +} + +static void test_rs_done(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { + sd_event *e = userdata; + static unsigned idx = 0; + uint8_t flags_array[] = { + 0, + 0, + 0, + ND_RA_FLAG_OTHER, + ND_RA_FLAG_MANAGED + }; + uint32_t mtu; + + assert_se(nd); + + assert_se(flags == flags_array[idx]); + idx++; + + if (verbose) + printf(" got event 0x%02x\n", flags); + + if (idx < ELEMENTSOF(flags_array)) { + send_ra(flags_array[idx]); + return; + } + + assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG); + + sd_event_exit(e, 0); +} + +static void test_rs(void) { + sd_event *e; + sd_ndisc *nd; + usec_t time_now = now(clock_boottime_or_monotonic()); + + if (verbose) + printf("* %s\n", __FUNCTION__); + + send_ra_function = send_ra; + + assert_se(sd_event_new(&e) >= 0); + + assert_se(sd_ndisc_new(&nd) >= 0); + assert_se(nd); + + assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0); + + assert_se(sd_ndisc_set_index(nd, 42) >= 0); + assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0); + assert_se(sd_ndisc_set_callback(nd, test_rs_done, NULL, NULL, NULL, e) >= 0); + + assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), + time_now + 2 *USEC_PER_SEC, 0, + test_rs_hangcheck, NULL) >= 0); + + assert_se(sd_ndisc_stop(nd) >= 0); + assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + assert_se(sd_ndisc_stop(nd) >= 0); + + assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + + sd_event_loop(e); + + test_hangcheck = sd_event_source_unref(test_hangcheck); + + nd = sd_ndisc_unref(nd); + assert_se(!nd); + + close(test_fd[1]); + + sd_event_unref(e); +} + +int main(int argc, char *argv[]) { + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + log_open(); + + test_rs(); + + return 0; +} diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c deleted file mode 100644 index 6ea460d9ac..0000000000 --- a/src/libsystemd-network/test-pppoe.c +++ /dev/null @@ -1,177 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <errno.h> -#include <linux/veth.h> -#include <net/if.h> -#include <stdlib.h> -#include <unistd.h> -#include <sched.h> - -#include "sd-event.h" -#include "sd-netlink.h" -#include "sd-pppoe.h" - -#include "event-util.h" -#include "process-util.h" -#include "util.h" - -static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) { - static int pppoe_state = -1; - sd_event *e = userdata; - - assert_se(ppp); - assert_se(e); - - switch (event) { - case SD_PPPOE_EVENT_RUNNING: - assert_se(pppoe_state == -1); - log_info("running"); - break; - case SD_PPPOE_EVENT_STOPPED: - assert_se(pppoe_state == SD_PPPOE_EVENT_RUNNING); - log_info("stopped"); - assert_se(sd_event_exit(e, 0) >= 0); - break; - default: - assert_not_reached("invalid pppoe event"); - } - - pppoe_state = event; -} - -static int client_run(const char *client_name, sd_event *e) { - sd_pppoe *pppoe; - int client_ifindex; - - client_ifindex = (int) if_nametoindex(client_name); - assert_se(client_ifindex > 0); - - assert_se(sd_pppoe_new(&pppoe) >= 0); - assert_se(sd_pppoe_attach_event(pppoe, e, 0) >= 0); - - assert_se(sd_pppoe_set_ifname(pppoe, "pppoe-client") >= 0); - assert_se(sd_pppoe_set_ifindex(pppoe, client_ifindex) >= 0); - assert_se(sd_pppoe_set_callback(pppoe, pppoe_handler, e) >= 0); - - log_info("starting PPPoE client, it will exit when the server times out and sends PADT"); - - assert_se(sd_pppoe_start(pppoe) >= 0); - - assert_se(sd_event_loop(e) >= 0); - - assert_se(!sd_pppoe_unref(pppoe)); - - return EXIT_SUCCESS; -} - -static int test_pppoe_server(sd_event *e) { - sd_netlink *rtnl; - sd_netlink_message *m; - pid_t pid; - int r, client_ifindex, server_ifindex; - - r = unshare(CLONE_NEWNET); - if (r < 0 && errno == EPERM) - return EXIT_TEST_SKIP; - - assert_se(r >= 0); - - assert_se(sd_netlink_open(&rtnl) >= 0); - assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0); - - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0); - assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0); - assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0); - assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0); - assert_se(sd_netlink_message_open_container(m, VETH_INFO_PEER) >= 0); - assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0); - - client_ifindex = (int) if_nametoindex("pppoe-client"); - assert_se(client_ifindex > 0); - server_ifindex = (int) if_nametoindex("pppoe-server"); - assert_se(server_ifindex > 0); - - m = sd_netlink_message_unref(m); - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, client_ifindex) >= 0); - assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0); - assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0); - - m = sd_netlink_message_unref(m); - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, server_ifindex) >= 0); - assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0); - assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0); - - pid = fork(); - assert_se(pid >= 0); - if (pid == 0) { - /* let the client send some discover messages before the server is started */ - sleep(2); - - /* TODO: manage pppoe-server-options */ - execlp("pppoe-server", "pppoe-server", "-F", - "-I", "pppoe-server", - "-C", "Test-AC", - "-S", "Service-Default", - "-S", "Service-First-Auxiliary", - "-S", "Service-Second-Auxiliary", - NULL); - assert_not_reached("failed to execute pppoe-server. not installed?"); - } - - client_run("pppoe-client", e); - - assert_se(kill(pid, SIGTERM) >= 0); - assert_se(wait_for_terminate(pid, NULL) >= 0); - - assert_se(!sd_netlink_message_unref(m)); - assert_se(!sd_netlink_unref(rtnl)); - - return EXIT_SUCCESS; -} - -int main(int argc, char *argv[]) { - _cleanup_event_unref_ sd_event *e = NULL; - - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); - - assert_se(sd_event_new(&e) >= 0); - - if (argc == 1) { - log_info("running PPPoE client against local server"); - - return test_pppoe_server(e); - } else if (argc == 2) { - log_info("running PPPoE client over '%s'", argv[1]); - - return client_run(argv[1], e); - } else { - log_error("This program takes one or no arguments.\n" - "\t %s [<ifname>]", program_invocation_short_name); - return EXIT_FAILURE; - } -} diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 435ec92d6f..589a90bbff 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -22,11 +22,12 @@ #include <unistd.h> #include <fcntl.h> -#include "util.h" -#include "process-util.h" +#include "bus-container.h" #include "bus-internal.h" #include "bus-socket.h" -#include "bus-container.h" +#include "fd-util.h" +#include "process-util.h" +#include "util.h" int bus_container_connect_socket(sd_bus *b) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index aeb48bedd1..ddd3a55b6c 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -26,14 +26,19 @@ #include <stddef.h> #include <errno.h> -#include "strv.h" #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-bloom.h" +#include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-control.h" -#include "bus-bloom.h" #include "bus-util.h" -#include "capability.h" +#include "capability-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { int r; @@ -976,8 +981,12 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; pid_t pid = 0; + bool do_label; int r; - bool do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); + + assert(bus); + + do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); /* Avoid allocating anything if we have no chance of returning useful data */ if (!bus->ucred_valid && !do_label) diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index af5f7da11c..0afafc2942 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -22,8 +22,9 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-signature.h" -#include "bus-util.h" #include "bus-type.h" +#include "bus-util.h" +#include "string-util.h" _public_ int sd_bus_emit_signal( sd_bus *bus, diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 3e8cb0b7d0..2922da3763 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -19,22 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <linux/capability.h> +#include <stdlib.h> -#include "util.h" -#include "formats-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "capability.h" -#include "cgroup-util.h" -#include "fileio.h" -#include "audit.h" +#include "alloc-util.h" +#include "audit-util.h" +#include "bus-creds.h" +#include "bus-label.h" #include "bus-message.h" #include "bus-util.h" +#include "capability-util.h" +#include "cgroup-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" #include "strv.h" -#include "bus-creds.h" -#include "bus-label.h" +#include "terminal-util.h" +#include "user-util.h" +#include "util.h" enum { CAP_OFFSET_INHERITABLE = 0, diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 8833b9c677..43a7e67a6d 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -19,18 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "capability.h" -#include "strv.h" -#include "macro.h" +#include "alloc-util.h" +#include "bus-dump.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-type.h" #include "cap-list.h" +#include "capability-util.h" +#include "fileio.h" #include "formats-util.h" +#include "locale-util.h" +#include "macro.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" - -#include "bus-message.h" -#include "bus-internal.h" -#include "bus-type.h" -#include "bus-dump.h" +#include "util.h" static char *indent(unsigned level, unsigned flags) { char *p; diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c index 64a5a972ae..239d7245e6 100644 --- a/src/libsystemd/sd-bus/bus-error.c +++ b/src/libsystemd/sd-bus/bus-error.c @@ -20,16 +20,18 @@ ***/ #include <errno.h> -#include <stdlib.h> #include <stdarg.h> #include <stdbool.h> -#include <string.h> #include <stdio.h> - -#include "util.h" -#include "errno-list.h" +#include <stdlib.h> +#include <string.h> #include "sd-bus.h" + +#include "alloc-util.h" +#include "errno-list.h" +#include "string-util.h" +#include "util.h" #include "bus-error.h" BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = { @@ -565,7 +567,7 @@ _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *for const char *bus_error_message(const sd_bus_error *e, int error) { if (e) { - /* Sometimes the D-Bus server is a little bit too verbose with + /* Sometimes, the D-Bus server is a little bit too verbose with * its error messages, so let's override them here */ if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED)) return "Access denied"; diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c index fea796cd30..d9f9cd1c5e 100644 --- a/src/libsystemd/sd-bus/bus-internal.c +++ b/src/libsystemd/sd-bus/bus-internal.c @@ -19,8 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "bus-message.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-message.h" +#include "hexdecoct.h" +#include "string-util.h" bool object_path_is_valid(const char *p) { const char *q; diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index e399701beb..5fc0926f06 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -21,21 +21,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <pthread.h> - -#include "hashmap.h" -#include "prioq.h" -#include "list.h" -#include "util.h" -#include "refcnt.h" -#include "socket-util.h" +#include <sys/socket.h> #include "sd-bus.h" + #include "bus-error.h" -#include "bus-match.h" #include "bus-kernel.h" +#include "bus-match.h" +#include "hashmap.h" #include "kdbus.h" +#include "list.h" +#include "prioq.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" struct reply_callback { sd_bus_message_handler_t callback; diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c index 3149a56397..a90536bac9 100644 --- a/src/libsystemd/sd-bus/bus-introspect.c +++ b/src/libsystemd/sd-bus/bus-introspect.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "bus-introspect.h" -#include "bus-signature.h" #include "bus-internal.h" +#include "bus-introspect.h" #include "bus-protocol.h" +#include "bus-signature.h" +#include "fd-util.h" +#include "fileio.h" +#include "string-util.h" +#include "util.h" int introspect_begin(struct introspect *i, bool trusted) { assert(i); diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 577a8b44c3..6716f6daca 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -34,19 +34,23 @@ #include <libgen.h> #undef basename -#include "util.h" -#include "strv.h" -#include "memfd-util.h" -#include "capability.h" -#include "fileio.h" -#include "formats-util.h" - +#include "alloc-util.h" +#include "bus-bloom.h" #include "bus-internal.h" -#include "bus-message.h" #include "bus-kernel.h" -#include "bus-bloom.h" -#include "bus-util.h" #include "bus-label.h" +#include "bus-message.h" +#include "bus-util.h" +#include "capability-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "memfd-util.h" +#include "parse-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" #define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t)) @@ -1433,12 +1437,12 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al if (!bus || !bus->is_kernel) return -EOPNOTSUPP; - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); if (bus->n_memfd_cache <= 0) { int r; - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); r = memfd_new(bus->description); if (r < 0) @@ -1460,7 +1464,7 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al *allocated = c->allocated; fd = c->fd; - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); return fd; } @@ -1484,10 +1488,10 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si return; } - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); close_and_munmap(fd, address, mapped); return; @@ -1507,7 +1511,7 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si c->allocated = allocated; } - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); } void bus_kernel_flush_memfd(sd_bus *b) { diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 7234e7926a..55dc7caa53 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -19,10 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-internal.h" -#include "bus-message.h" #include "bus-match.h" +#include "bus-message.h" #include "bus-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hexdecoct.h" +#include "string-util.h" #include "strv.h" /* Example: diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h index 53ee0463ca..bc85af3ec0 100644 --- a/src/libsystemd/sd-bus/bus-match.h +++ b/src/libsystemd/sd-bus/bus-match.h @@ -21,10 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "hashmap.h" - #include "sd-bus.h" +#include "hashmap.h" + enum bus_match_node_type { BUS_MATCH_ROOT, BUS_MATCH_VALUE, diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 72e2b9f785..5c80095bf0 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -23,19 +23,23 @@ #include <fcntl.h> #include <sys/mman.h> -#include "util.h" -#include "utf8.h" -#include "strv.h" -#include "time-util.h" -#include "memfd-util.h" - #include "sd-bus.h" -#include "bus-message.h" + +#include "alloc-util.h" +#include "bus-gvariant.h" #include "bus-internal.h" -#include "bus-type.h" +#include "bus-message.h" #include "bus-signature.h" -#include "bus-gvariant.h" +#include "bus-type.h" #include "bus-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "memfd-util.h" +#include "string-util.h" +#include "strv.h" +#include "time-util.h" +#include "utf8.h" +#include "util.h" static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored); diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h index ff25003461..4c91dbae09 100644 --- a/src/libsystemd/sd-bus/bus-message.h +++ b/src/libsystemd/sd-bus/bus-message.h @@ -21,15 +21,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <byteswap.h> +#include <stdbool.h> #include <sys/socket.h> -#include "macro.h" #include "sd-bus.h" -#include "time-util.h" + #include "bus-creds.h" #include "bus-protocol.h" +#include "macro.h" +#include "time-util.h" struct bus_container { char enclosing; diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 728f20447a..8c472626a8 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -19,15 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" -#include "set.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-introspect.h" #include "bus-message.h" -#include "bus-type.h" #include "bus-signature.h" -#include "bus-introspect.h" -#include "bus-util.h" #include "bus-slot.h" +#include "bus-type.h" +#include "bus-util.h" +#include "set.h" +#include "string-util.h" +#include "strv.h" #include "bus-objects.h" static int node_vtable_get_userdata( diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index b149ea16da..550bad27ba 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -20,8 +20,11 @@ ***/ #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-control.h" #include "bus-objects.h" +#include "string-util.h" #include "bus-slot.h" sd_bus_slot *bus_slot_allocate( diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index d0b1e3d7dc..25873dea1e 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -20,22 +20,29 @@ ***/ #include <endian.h> +#include <poll.h> #include <stdlib.h> #include <unistd.h> -#include <poll.h> +#include "sd-bus.h" #include "sd-daemon.h" -#include "util.h" -#include "macro.h" -#include "missing.h" -#include "utf8.h" -#include "formats-util.h" -#include "signal-util.h" -#include "sd-bus.h" -#include "bus-socket.h" +#include "alloc-util.h" #include "bus-internal.h" #include "bus-message.h" +#include "bus-socket.h" +#include "fd-util.h" +#include "formats-util.h" +#include "hexdecoct.h" +#include "macro.h" +#include "missing.h" +#include "selinux-util.h" +#include "signal-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "user-util.h" +#include "utf8.h" +#include "util.h" #define SNDBUF_SIZE (8*1024*1024) @@ -602,9 +609,11 @@ static void bus_get_peercred(sd_bus *b) { b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; /* Get the SELinux context of the peer */ - r = getpeersec(b->input_fd, &b->label); - if (r < 0 && r != -EOPNOTSUPP) - log_debug_errno(r, "Failed to determine peer security context: %m"); + if (mac_selinux_use()) { + r = getpeersec(b->input_fd, &b->label); + if (r < 0 && r != -EOPNOTSUPP) + log_debug_errno(r, "Failed to determine peer security context: %m"); + } } static int bus_socket_start_auth_client(sd_bus *b) { diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index e43891be25..fd7e58fcfa 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -20,9 +20,11 @@ ***/ #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-track.h" +#include "bus-util.h" struct sd_bus_track { unsigned n_ref; diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h index 581574ab73..ad89e6c911 100644 --- a/src/libsystemd/sd-bus/bus-type.h +++ b/src/libsystemd/sd-bus/bus-type.h @@ -23,9 +23,10 @@ #include <stdbool.h> -#include "macro.h" #include "sd-bus.h" +#include "macro.h" + bool bus_type_is_valid(char c) _const_; bool bus_type_is_valid_in_signature(char c) _const_; bool bus_type_is_basic(char c) _const_; diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c index abe482fc46..71f962b00c 100644 --- a/src/libsystemd/sd-bus/busctl-introspect.c +++ b/src/libsystemd/sd-bus/busctl-introspect.c @@ -19,11 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "xml.h" -#include "sd-bus-vtable.h" +#include "sd-bus.h" +#include "alloc-util.h" #include "busctl-introspect.h" +#include "string-util.h" +#include "util.h" +#include "xml.h" #define NODE_DEPTH_MAX 16 diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 49c97af339..452ac7c407 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -23,18 +23,24 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "bus-dump.h" #include "bus-internal.h" #include "bus-signature.h" #include "bus-type.h" #include "bus-util.h" #include "busctl-introspect.h" +#include "escape.h" +#include "fd-util.h" +#include "locale-util.h" #include "log.h" #include "pager.h" +#include "parse-util.h" #include "path-util.h" #include "set.h" #include "strv.h" #include "terminal-util.h" +#include "user-util.h" #include "util.h" static bool arg_no_pager = false; diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index a23f7257fa..a8d79b01b0 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -27,28 +27,33 @@ #include <sys/mman.h> #include <pthread.h> -#include "util.h" -#include "macro.h" -#include "strv.h" -#include "missing.h" -#include "def.h" -#include "cgroup-util.h" -#include "hostname-util.h" -#include "bus-label.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-container.h" +#include "bus-control.h" #include "bus-internal.h" -#include "bus-message.h" -#include "bus-type.h" -#include "bus-socket.h" #include "bus-kernel.h" -#include "bus-control.h" +#include "bus-label.h" +#include "bus-message.h" #include "bus-objects.h" -#include "bus-util.h" -#include "bus-container.h" #include "bus-protocol.h" -#include "bus-track.h" #include "bus-slot.h" +#include "bus-socket.h" +#include "bus-track.h" +#include "bus-type.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "def.h" +#include "fd-util.h" +#include "hostname-util.h" +#include "macro.h" +#include "missing.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define log_debug_bus_message(m) \ do { \ diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c index d14110aa04..96a0929a14 100644 --- a/src/libsystemd/sd-bus/test-bus-benchmark.c +++ b/src/libsystemd/sd-bus/test-bus-benchmark.c @@ -21,14 +21,16 @@ #include <sys/wait.h> -#include "def.h" -#include "util.h" -#include "time-util.h" - #include "sd-bus.h" -#include "bus-kernel.h" + +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-kernel.h" #include "bus-util.h" +#include "def.h" +#include "fd-util.h" +#include "time-util.h" +#include "util.h" #define MAX_SIZE (2*1024*1024) diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index 20f1b532b7..767aef63ff 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -24,16 +24,18 @@ #include <unistd.h> #include <fcntl.h> -#include "log.h" -#include "util.h" -#include "macro.h" -#include "formats-util.h" - #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "bus-match.h" #include "bus-internal.h" +#include "bus-match.h" #include "bus-util.h" +#include "formats-util.h" +#include "log.h" +#include "macro.h" +#include "util.h" +#include "fd-util.h" static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m))); diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c index f586880593..51aa0a9ad0 100644 --- a/src/libsystemd/sd-bus/test-bus-cleanup.c +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -22,9 +22,10 @@ #include <stdio.h> #include "sd-bus.h" -#include "bus-util.h" + #include "bus-internal.h" #include "bus-message.h" +#include "bus-util.h" #include "refcnt.h" static void test_bus_new(void) { diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index b078bdc5f6..931c001788 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -23,14 +23,16 @@ #include <glib.h> #endif -#include "util.h" -#include "macro.h" #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-gvariant.h" -#include "bus-util.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-dump.h" +#include "bus-util.h" +#include "macro.h" +#include "util.h" static void test_bus_gvariant_is_fixed_size(void) { assert_se(bus_gvariant_is_fixed_size("") > 0); diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c index f3d1099dd2..dbdaa69fbe 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c +++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-kernel.h" #include "bus-util.h" +#include "fd-util.h" +#include "log.h" +#include "util.h" static int test_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { int *found = userdata; diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c index 6506eaab2e..0080f71d3b 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel.c +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -21,13 +21,15 @@ #include <fcntl.h> -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-kernel.h" #include "bus-util.h" -#include "bus-dump.h" +#include "fd-util.h" +#include "log.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int bus_ref = -1; diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index ff6bba5988..0747d6a37c 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -30,14 +30,17 @@ #include <dbus/dbus.h> #endif -#include "log.h" -#include "util.h" - #include "sd-bus.h" -#include "bus-message.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-dump.h" #include "bus-label.h" +#include "bus-message.h" +#include "bus-util.h" +#include "fd-util.h" +#include "log.h" +#include "hexdecoct.h" +#include "util.h" static void test_bus_path_encode_unique(void) { _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL; diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 0a35b750b3..5bc72e2355 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -22,16 +22,17 @@ #include <stdlib.h> #include <pthread.h> -#include "log.h" -#include "util.h" -#include "macro.h" -#include "strv.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" -#include "bus-dump.h" +#include "log.h" +#include "macro.h" +#include "strv.h" +#include "util.h" struct context { int fds[2]; diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c index aef768dc18..428e185769 100644 --- a/src/libsystemd/sd-bus/test-bus-proxy.c +++ b/src/libsystemd/sd-bus/test-bus-proxy.c @@ -23,13 +23,14 @@ #include <fcntl.h> #include <stdlib.h> -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-kernel.h" #include "bus-util.h" -#include "bus-dump.h" +#include "log.h" +#include "util.h" typedef struct { const char *sender; diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c index 080d8eddb7..5bf2c1ecf8 100644 --- a/src/libsystemd/sd-bus/test-bus-server.c +++ b/src/libsystemd/sd-bus/test-bus-server.c @@ -19,16 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <pthread.h> - -#include "log.h" -#include "util.h" -#include "macro.h" +#include <stdlib.h> #include "sd-bus.h" + #include "bus-internal.h" #include "bus-util.h" +#include "log.h" +#include "macro.h" +#include "util.h" struct context { int fds[2]; diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c index 17c6188ca0..92a810a7d8 100644 --- a/src/libsystemd/sd-bus/test-bus-signature.c +++ b/src/libsystemd/sd-bus/test-bus-signature.c @@ -19,7 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - +#include "string-util.h" #include "log.h" #include "bus-signature.h" #include "bus-internal.h" diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c index 2d062fc9b5..ff8df61a9e 100644 --- a/src/libsystemd/sd-bus/test-bus-zero-copy.c +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@ -21,14 +21,17 @@ #include <sys/mman.h> -#include "util.h" -#include "log.h" -#include "memfd-util.h" - #include "sd-bus.h" -#include "bus-message.h" -#include "bus-kernel.h" + +#include "alloc-util.h" #include "bus-dump.h" +#include "bus-kernel.h" +#include "bus-message.h" +#include "log.h" +#include "memfd-util.h" +#include "string-util.h" +#include "util.h" +#include "fd-util.h" #define FIRST_ARRAY 17 #define SECOND_ARRAY 33 diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 582fb53529..f1e9b7ed1b 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -33,12 +33,18 @@ #include <sys/un.h> #include <unistd.h> +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "parse-util.h" #include "path-util.h" #include "socket-util.h" #include "strv.h" #include "util.h" -#include "sd-daemon.h" +#define SNDBUF_SIZE (8*1024*1024) static void unsetenv_all(bool unset_environment) { @@ -52,8 +58,7 @@ static void unsetenv_all(bool unset_environment) { _public_ int sd_listen_fds(int unset_environment) { const char *e; - unsigned n; - int r, fd; + int n, r, fd; pid_t pid; e = getenv("LISTEN_PID"); @@ -78,17 +83,23 @@ _public_ int sd_listen_fds(int unset_environment) { goto finish; } - r = safe_atou(e, &n); + r = safe_atoi(e, &n); if (r < 0) goto finish; - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) { + assert_cc(SD_LISTEN_FDS_START < INT_MAX); + if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) { + r = -EINVAL; + goto finish; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { r = fd_cloexec(fd, true); if (r < 0) goto finish; } - r = (int) n; + r = n; finish: unsetenv_all(unset_environment); @@ -430,12 +441,19 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char goto finish; } + if (strlen(e) > sizeof(sockaddr.un.sun_path)) { + r = -EINVAL; + goto finish; + } + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); if (fd < 0) { r = -errno; goto finish; } + fd_inc_sndbuf(fd, SNDBUF_SIZE); + iovec.iov_len = strlen(state); strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); @@ -454,7 +472,7 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0); - msghdr.msg_control = alloca(msghdr.msg_controllen); + msghdr.msg_control = alloca0(msghdr.msg_controllen); cmsg = CMSG_FIRSTHDR(&msghdr); if (n_fds > 0) { @@ -573,7 +591,7 @@ _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { r = safe_atou64(s, &u); if (r < 0) goto finish; - if (u <= 0) { + if (u <= 0 || u >= USEC_INFINITY) { r = -EINVAL; goto finish; } diff --git a/src/libsystemd/sd-device/Makefile b/src/libsystemd/sd-device/Makefile new file mode 120000 index 0000000000..d0b0e8e008 --- /dev/null +++ b/src/libsystemd/sd-device/Makefile @@ -0,0 +1 @@ +../Makefile
\ No newline at end of file diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 45a4d12eb7..ae3157ee5e 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -18,15 +18,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "prioq.h" -#include "strv.h" -#include "set.h" - #include "sd-device.h" -#include "device-util.h" +#include "alloc-util.h" #include "device-enumerator-private.h" +#include "device-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "prioq.h" +#include "set.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define DEVICE_ENUMERATE_MAX_DEPTH 256 diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index b5215cb9b5..a13477e753 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -19,25 +19,31 @@ ***/ #include <ctype.h> -#include <sys/types.h> #include <net/if.h> - -#include "util.h" -#include "macro.h" -#include "refcnt.h" -#include "path-util.h" -#include "strxcpyx.h" -#include "fileio.h" -#include "hashmap.h" -#include "set.h" -#include "strv.h" -#include "mkdir.h" +#include <sys/types.h> #include "sd-device.h" -#include "device-util.h" +#include "alloc-util.h" #include "device-internal.h" #include "device-private.h" +#include "device-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hashmap.h" +#include "macro.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "refcnt.h" +#include "set.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "strxcpyx.h" +#include "user-util.h" +#include "util.h" int device_add_property(sd_device *device, const char *key, const char *value) { int r; diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h index 49a7b66a2b..d1f34efc2d 100644 --- a/src/libsystemd/sd-device/device-private.h +++ b/src/libsystemd/sd-device/device-private.h @@ -21,6 +21,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> +#include <stdbool.h> +#include <sys/types.h> + +#include "sd-device.h" + int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len); int device_new_from_strv(sd_device **ret, char **strv); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index e46546ed91..0e49262087 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -19,23 +19,28 @@ ***/ #include <ctype.h> -#include <sys/types.h> #include <net/if.h> +#include <sys/types.h> -#include "util.h" -#include "macro.h" -#include "path-util.h" -#include "strxcpyx.h" +#include "sd-device.h" + +#include "alloc-util.h" +#include "device-internal.h" +#include "device-private.h" +#include "device-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "hashmap.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" #include "set.h" +#include "stat-util.h" +#include "string-util.h" #include "strv.h" - -#include "sd-device.h" - -#include "device-util.h" -#include "device-private.h" -#include "device-internal.h" +#include "strxcpyx.h" +#include "util.h" int device_new_aux(sd_device **ret) { _cleanup_device_unref_ sd_device *device = NULL; @@ -351,13 +356,10 @@ int device_set_ifindex(sd_device *device, const char *_ifindex) { assert(device); assert(_ifindex); - r = safe_atoi(_ifindex, &ifindex); + r = parse_ifindex(_ifindex, &ifindex); if (r < 0) return r; - if (ifindex <= 0) - return -EINVAL; - r = device_add_property_internal(device, "IFINDEX", _ifindex); if (r < 0) return r; @@ -627,11 +629,9 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { struct ifreq ifr = {}; int ifindex; - r = safe_atoi(&id[1], &ifr.ifr_ifindex); + r = parse_ifindex(&id[1], &ifr.ifr_ifindex); if (r < 0) return r; - else if (ifr.ifr_ifindex <= 0) - return -EINVAL; sk = socket(PF_INET, SOCK_DGRAM, 0); if (sk < 0) diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h index e7cad9be46..ae020340a5 100644 --- a/src/libsystemd/sd-event/event-util.h +++ b/src/libsystemd/sd-event/event-util.h @@ -21,9 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "sd-event.h" +#include "util.h" + DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref); diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 1a82c4c940..ee4886700e 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -23,19 +23,22 @@ #include <sys/timerfd.h> #include <sys/wait.h> -#include "sd-id128.h" #include "sd-daemon.h" -#include "macro.h" -#include "prioq.h" +#include "sd-event.h" +#include "sd-id128.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "hashmap.h" -#include "util.h" -#include "time-util.h" +#include "list.h" +#include "macro.h" #include "missing.h" +#include "prioq.h" #include "set.h" -#include "list.h" #include "signal-util.h" - -#include "sd-event.h" +#include "string-util.h" +#include "time-util.h" +#include "util.h" #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) @@ -1123,8 +1126,8 @@ _public_ int sd_event_add_signal( callback = signal_exit_callback; r = pthread_sigmask(SIG_SETMASK, NULL, &ss); - if (r < 0) - return -errno; + if (r != 0) + return -r; if (!sigismember(&ss, sig)) return -EBUSY; diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index c092e56b7a..c1a3b49483 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -20,10 +20,12 @@ ***/ #include "sd-event.h" + +#include "fd-util.h" #include "log.h" -#include "util.h" #include "macro.h" #include "signal-util.h" +#include "util.h" static int prepare_handler(sd_event_source *s, void *userdata) { log_info("preparing %c", PTR_TO_INT(userdata)); diff --git a/src/libsystemd/sd-hwdb/hwdb-util.h b/src/libsystemd/sd-hwdb/hwdb-util.h index ee020a2942..d366c6fa41 100644 --- a/src/libsystemd/sd-hwdb/hwdb-util.h +++ b/src/libsystemd/sd-hwdb/hwdb-util.h @@ -21,10 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" - #include "sd-hwdb.h" +#include "util.h" + DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb*, sd_hwdb_unref); #define _cleanup_hwdb_unref_ _cleanup_(sd_hwdb_unrefp) diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c index f0316be659..0e034863d6 100644 --- a/src/libsystemd/sd-hwdb/sd-hwdb.c +++ b/src/libsystemd/sd-hwdb/sd-hwdb.c @@ -19,21 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> -#include <string.h> +#include <fnmatch.h> #include <inttypes.h> +#include <stdio.h> #include <stdlib.h> -#include <fnmatch.h> +#include <string.h> #include <sys/mman.h> #include "sd-hwdb.h" +#include "alloc-util.h" +#include "fd-util.h" #include "hashmap.h" -#include "refcnt.h" - -#include "hwdb-util.h" #include "hwdb-internal.h" +#include "hwdb-util.h" +#include "refcnt.h" +#include "string-util.h" struct sd_hwdb { RefCount n_ref; diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index eb539ad318..1e17ea6a06 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -23,10 +23,14 @@ #include <fcntl.h> #include <unistd.h> -#include "util.h" -#include "macro.h" #include "sd-id128.h" + +#include "fd-util.h" +#include "io-util.h" +#include "macro.h" +#include "hexdecoct.h" #include "random-util.h" +#include "util.h" _public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) { unsigned n; diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 265c7c7db2..3f2e459825 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -19,21 +19,33 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <string.h> #include <errno.h> -#include <sys/inotify.h> #include <poll.h> +#include <string.h> +#include <sys/inotify.h> +#include <unistd.h> -#include "util.h" +#include "sd-login.h" + +#include "alloc-util.h" #include "cgroup-util.h" -#include "macro.h" -#include "strv.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" -#include "login-util.h" #include "formats-util.h" +#include "fs-util.h" #include "hostname-util.h" -#include "sd-login.h" +#include "io-util.h" +#include "login-util.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" /* Error codes: * @@ -920,9 +932,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) { *(char*) (mempcpy(buf, word, l)) = 0; - if (safe_atoi(buf, &ifi) < 0) - continue; - if (ifi <= 0) + if (parse_ifindex(buf, &ifi) < 0) continue; if (!GREEDY_REALLOC(ni, allocated, nr+1)) { diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index f734ce9eee..b0f94c9522 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -22,11 +22,14 @@ #include <poll.h> #include <string.h> -#include "systemd/sd-login.h" +#include "sd-login.h" -#include "util.h" -#include "strv.h" +#include "alloc-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static void test_login(void) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c index e2f637f7f9..a00865b56b 100644 --- a/src/libsystemd/sd-netlink/local-addresses.c +++ b/src/libsystemd/sd-netlink/local-addresses.c @@ -21,6 +21,8 @@ ***/ #include "sd-netlink.h" + +#include "alloc-util.h" #include "netlink-util.h" #include "macro.h" #include "local-addresses.h" diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 4026e2c341..8519a4d523 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -23,13 +23,12 @@ #include <linux/netlink.h> -#include "refcnt.h" -#include "prioq.h" -#include "list.h" - #include "sd-netlink.h" +#include "list.h" #include "netlink-types.h" +#include "prioq.h" +#include "refcnt.h" #define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) @@ -64,6 +63,9 @@ struct sd_netlink { struct sockaddr_nl nl; } sockaddr; + Hashmap *broadcast_group_refs; + bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */ + sd_netlink_message **rqueue; unsigned rqueue_size; size_t rqueue_allocated; @@ -124,7 +126,8 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret); int socket_open(int family); int socket_bind(sd_netlink *nl); -int socket_join_broadcast_group(sd_netlink *nl, unsigned group); +int socket_broadcast_group_ref(sd_netlink *nl, unsigned group); +int socket_broadcast_group_unref(sd_netlink *nl, unsigned group); int socket_write_message(sd_netlink *nl, sd_netlink_message *m); int socket_read_message(sd_netlink *nl); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index cf693de5fb..03971b3596 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -23,16 +23,17 @@ #include <stdbool.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" +#include "sd-netlink.h" + +#include "alloc-util.h" #include "formats-util.h" -#include "refcnt.h" #include "missing.h" - -#include "sd-netlink.h" -#include "netlink-util.h" #include "netlink-internal.h" #include "netlink-types.h" +#include "netlink-util.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL) #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 84ff7c38c9..13945202e4 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -23,16 +23,17 @@ #include <stdbool.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" +#include "sd-netlink.h" + +#include "alloc-util.h" #include "formats-util.h" -#include "refcnt.h" #include "missing.h" - -#include "sd-netlink.h" -#include "netlink-util.h" #include "netlink-internal.h" #include "netlink-types.h" +#include "netlink-util.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" int socket_open(int family) { int fd; @@ -44,6 +45,65 @@ int socket_open(int family) { return fd; } +static int broadcast_groups_get(sd_netlink *nl) { + _cleanup_free_ uint32_t *groups = NULL; + socklen_t len = 0, old_len; + unsigned i, j; + int r; + + assert(nl); + assert(nl->fd > 0); + + r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len); + if (r < 0) { + if (errno == ENOPROTOOPT) { + nl->broadcast_group_dont_leave = true; + return 0; + } else + return -errno; + } + + if (len == 0) + return 0; + + groups = new0(uint32_t, len); + if (!groups) + return -ENOMEM; + + old_len = len; + + r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len); + if (r < 0) + return -errno; + + if (old_len != len) + return -EIO; + + r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL); + if (r < 0) + return r; + + for (i = 0; i < len; i++) { + for (j = 0; j < sizeof(uint32_t) * 8; j ++) { + uint32_t offset; + unsigned group; + + offset = 1U << j; + + if (!(groups[i] & offset)) + continue; + + group = i * sizeof(uint32_t) * 8 + j + 1; + + r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1)); + if (r < 0) + return r; + } + } + + return 0; +} + int socket_bind(sd_netlink *nl) { socklen_t addrlen; int r, one = 1; @@ -63,11 +123,32 @@ int socket_bind(sd_netlink *nl) { if (r < 0) return -errno; + r = broadcast_groups_get(nl); + if (r < 0) + return r; + return 0; } +static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) { + assert(nl); + + return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group))); +} -int socket_join_broadcast_group(sd_netlink *nl, unsigned group) { +static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) { + int r; + + assert(nl); + + r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref)); + if (r < 0) + return r; + + return 0; +} + +static int broadcast_group_join(sd_netlink *nl, unsigned group) { int r; assert(nl); @@ -81,6 +162,79 @@ int socket_join_broadcast_group(sd_netlink *nl, unsigned group) { return 0; } +int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) { + unsigned n_ref; + int r; + + assert(nl); + + n_ref = broadcast_group_get_ref(nl, group); + + n_ref ++; + + r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL); + if (r < 0) + return r; + + r = broadcast_group_set_ref(nl, group, n_ref); + if (r < 0) + return r; + + if (n_ref > 1) + /* not yet in the group */ + return 0; + + r = broadcast_group_join(nl, group); + if (r < 0) + return r; + + return 0; +} + +static int broadcast_group_leave(sd_netlink *nl, unsigned group) { + int r; + + assert(nl); + assert(nl->fd >= 0); + assert(group > 0); + + if (nl->broadcast_group_dont_leave) + return 0; + + r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group)); + if (r < 0) + return -errno; + + return 0; +} + +int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) { + unsigned n_ref; + int r; + + assert(nl); + + n_ref = broadcast_group_get_ref(nl, group); + + assert(n_ref > 0); + + n_ref --; + + r = broadcast_group_set_ref(nl, group, n_ref); + if (r < 0) + return r; + + if (n_ref > 0) + /* still refs left */ + return 0; + + r = broadcast_group_leave(nl, group); + if (r < 0) + return r; + + return 0; +} + /* returns the number of bytes sent, or a negative error code */ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) { union { diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 4a5340e659..135354e5f3 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -28,16 +28,15 @@ #include <linux/if_bridge.h> #include <linux/if_addr.h> #include <linux/if.h> - #include <linux/ip.h> #include <linux/if_link.h> #include <linux/if_tunnel.h> #include "macro.h" -#include "util.h" - -#include "netlink-types.h" #include "missing.h" +#include "netlink-types.h" +#include "string-table.h" +#include "util.h" /* Maximum ARP IP target defined in kernel */ #define BOND_MAX_ARP_TARGETS 16 @@ -84,20 +83,20 @@ static const NLTypeSystem empty_type_system = { .types = empty_types, }; -static const NLType rtnl_link_info_data_veth_types[VETH_INFO_MAX + 1] = { +static const NLType rtnl_link_info_data_veth_types[] = { [VETH_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, }; -static const NLType rtnl_link_info_data_ipvlan_types[IFLA_IPVLAN_MAX + 1] = { +static const NLType rtnl_link_info_data_ipvlan_types[] = { [IFLA_IPVLAN_MODE] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = { +static const NLType rtnl_link_info_data_macvlan_types[] = { [IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 }, [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_bridge_management_types[IFLA_BRIDGE_MAX + 1] = { +static const NLType rtnl_link_bridge_management_types[] = { [IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 }, [IFLA_BRIDGE_MODE] = { .type = NETLINK_TYPE_U16 }, /* @@ -106,7 +105,7 @@ static const NLType rtnl_link_bridge_management_types[IFLA_BRIDGE_MAX + 1] = { */ }; -static const NLType rtnl_link_info_data_bridge_types[IFLA_BR_MAX + 1] = { +static const NLType rtnl_link_info_data_bridge_types[] = { [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 }, [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 }, [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 }, @@ -115,7 +114,7 @@ static const NLType rtnl_link_info_data_bridge_types[IFLA_BR_MAX + 1] = { [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = { +static const NLType rtnl_link_info_data_vlan_types[] = { [IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 }, /* [IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) }, @@ -125,7 +124,7 @@ static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = { [IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = { +static const NLType rtnl_link_info_data_vxlan_types[] = { [IFLA_VXLAN_ID] = { .type = NETLINK_TYPE_U32 }, [IFLA_VXLAN_GROUP] = { .type = NETLINK_TYPE_IN_ADDR }, [IFLA_VXLAN_LINK] = { .type = NETLINK_TYPE_U32 }, @@ -152,7 +151,7 @@ static const NLType rtnl_link_info_data_vxlan_types[IFLA_VXLAN_MAX+1] = { [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NETLINK_TYPE_FLAG }, }; -static const NLType rtnl_bond_arp_target_types[BOND_ARP_TARGETS_MAX + 1] = { +static const NLType rtnl_bond_arp_target_types[] = { [BOND_ARP_TARGETS_0] = { .type = NETLINK_TYPE_U32 }, [BOND_ARP_TARGETS_1] = { .type = NETLINK_TYPE_U32 }, [BOND_ARP_TARGETS_2] = { .type = NETLINK_TYPE_U32 }, @@ -176,7 +175,7 @@ static const NLTypeSystem rtnl_bond_arp_type_system = { .types = rtnl_bond_arp_target_types, }; -static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = { +static const NLType rtnl_link_info_data_bond_types[] = { [IFLA_BOND_MODE] = { .type = NETLINK_TYPE_U8 }, [IFLA_BOND_ACTIVE_SLAVE] = { .type = NETLINK_TYPE_U32 }, [IFLA_BOND_MIIMON] = { .type = NETLINK_TYPE_U32 }, @@ -202,7 +201,7 @@ static const NLType rtnl_link_info_data_bond_types[IFLA_BOND_MAX + 1] = { [IFLA_BOND_AD_INFO] = { .type = NETLINK_TYPE_NESTED }, }; -static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = { +static const NLType rtnl_link_info_data_iptun_types[] = { [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, @@ -221,7 +220,7 @@ static const NLType rtnl_link_info_data_iptun_types[IFLA_IPTUN_MAX + 1] = { [IFLA_IPTUN_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = { +static const NLType rtnl_link_info_data_ipgre_types[] = { [IFLA_GRE_LINK] = { .type = NETLINK_TYPE_U32 }, [IFLA_GRE_IFLAGS] = { .type = NETLINK_TYPE_U16 }, [IFLA_GRE_OFLAGS] = { .type = NETLINK_TYPE_U16 }, @@ -240,7 +239,7 @@ static const NLType rtnl_link_info_data_ipgre_types[IFLA_GRE_MAX + 1] = { [IFLA_GRE_ENCAP_DPORT] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = { +static const NLType rtnl_link_info_data_ipvti_types[] = { [IFLA_VTI_LINK] = { .type = NETLINK_TYPE_U32 }, [IFLA_VTI_IKEY] = { .type = NETLINK_TYPE_U32 }, [IFLA_VTI_OKEY] = { .type = NETLINK_TYPE_U32 }, @@ -248,7 +247,7 @@ static const NLType rtnl_link_info_data_ipvti_types[IFLA_VTI_MAX + 1] = { [IFLA_VTI_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, }; -static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = { +static const NLType rtnl_link_info_data_ip6tnl_types[] = { [IFLA_IPTUN_LINK] = { .type = NETLINK_TYPE_U32 }, [IFLA_IPTUN_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, [IFLA_IPTUN_REMOTE] = { .type = NETLINK_TYPE_IN_ADDR }, @@ -260,7 +259,7 @@ static const NLType rtnl_link_info_data_ip6tnl_types[IFLA_IPTUN_MAX + 1] = { }; /* these strings must match the .kind entries in the kernel */ -static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_MAX] = { +static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_BOND] = "bond", [NL_UNION_LINK_INFO_DATA_BRIDGE] = "bridge", [NL_UNION_LINK_INFO_DATA_VLAN] = "vlan", @@ -283,7 +282,7 @@ static const char* const nl_union_link_info_data_table[_NL_UNION_LINK_INFO_DATA_ DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData); -static const NLTypeSystem rtnl_link_info_data_type_systems[_NL_UNION_LINK_INFO_DATA_MAX] = { +static const NLTypeSystem rtnl_link_info_data_type_systems[] = { [NL_UNION_LINK_INFO_DATA_BOND] = { .count = ELEMENTSOF(rtnl_link_info_data_bond_types), .types = rtnl_link_info_data_bond_types }, [NL_UNION_LINK_INFO_DATA_BRIDGE] = { .count = ELEMENTSOF(rtnl_link_info_data_bridge_types), @@ -329,7 +328,7 @@ static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = { .match = IFLA_INFO_KIND, }; -static const NLType rtnl_link_info_types[IFLA_INFO_MAX + 1] = { +static const NLType rtnl_link_info_types[] = { [IFLA_INFO_KIND] = { .type = NETLINK_TYPE_STRING }, [IFLA_INFO_DATA] = { .type = NETLINK_TYPE_UNION, .type_system_union = &rtnl_link_info_data_type_system_union}, /* @@ -344,7 +343,7 @@ static const NLTypeSystem rtnl_link_info_type_system = { .types = rtnl_link_info_types, }; -static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] = { +static const struct NLType rtnl_prot_info_bridge_port_types[] = { [IFLA_BRPORT_STATE] = { .type = NETLINK_TYPE_U8 }, [IFLA_BRPORT_COST] = { .type = NETLINK_TYPE_U32 }, [IFLA_BRPORT_PRIORITY] = { .type = NETLINK_TYPE_U16 }, @@ -358,7 +357,7 @@ static const struct NLType rtnl_prot_info_bridge_port_types[IFLA_BRPORT_MAX + 1] [IFLA_BRPORT_LEARNING_SYNC] = { .type = NETLINK_TYPE_U8 }, }; -static const NLTypeSystem rtnl_prot_info_type_systems[AF_MAX] = { +static const NLTypeSystem rtnl_prot_info_type_systems[] = { [AF_BRIDGE] = { .count = ELEMENTSOF(rtnl_prot_info_bridge_port_types), .types = rtnl_prot_info_bridge_port_types }, }; @@ -369,7 +368,7 @@ static const NLTypeSystemUnion rtnl_prot_info_type_system_union = { .match_type = NL_MATCH_PROTOCOL, }; -static const struct NLType rtnl_af_spec_inet6_types[IFLA_INET6_MAX + 1] = { +static const struct NLType rtnl_af_spec_inet6_types[] = { [IFLA_INET6_FLAGS] = { .type = NETLINK_TYPE_U32 }, /* IFLA_INET6_CONF, @@ -387,7 +386,7 @@ static const NLTypeSystem rtnl_af_spec_inet6_type_system = { .types = rtnl_af_spec_inet6_types, }; -static const NLType rtnl_af_spec_types[AF_MAX + 1] = { +static const NLType rtnl_af_spec_types[] = { [AF_INET6] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_af_spec_inet6_type_system }, }; @@ -396,7 +395,7 @@ static const NLTypeSystem rtnl_af_spec_type_system = { .types = rtnl_af_spec_types, }; -static const NLType rtnl_link_types[IFLA_MAX + 1 ] = { +static const NLType rtnl_link_types[] = { [IFLA_ADDRESS] = { .type = NETLINK_TYPE_ETHER_ADDR }, [IFLA_BROADCAST] = { .type = NETLINK_TYPE_ETHER_ADDR }, [IFLA_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, @@ -455,7 +454,7 @@ static const NLTypeSystem rtnl_link_type_system = { /* IFA_FLAGS was defined in kernel 3.14, but we still support older * kernels where IFA_MAX is lower. */ -static const NLType rtnl_address_types[CONST_MAX(IFA_MAX, IFA_FLAGS) + 1] = { +static const NLType rtnl_address_types[] = { [IFA_ADDRESS] = { .type = NETLINK_TYPE_IN_ADDR }, [IFA_LOCAL] = { .type = NETLINK_TYPE_IN_ADDR }, [IFA_LABEL] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, @@ -473,7 +472,7 @@ static const NLTypeSystem rtnl_address_type_system = { .types = rtnl_address_types, }; -static const NLType rtnl_route_types[RTA_MAX + 1] = { +static const NLType rtnl_route_types[] = { [RTA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ [RTA_SRC] = { .type = NETLINK_TYPE_IN_ADDR }, /* 6? */ [RTA_IIF] = { .type = NETLINK_TYPE_U32 }, @@ -491,7 +490,11 @@ static const NLType rtnl_route_types[RTA_MAX + 1] = { RTA_TABLE, RTA_MARK, RTA_MFC_STATS, + RTA_VIA, + RTA_NEWDST, */ + [RTA_PREF] = { .type = NETLINK_TYPE_U8 }, + }; static const NLTypeSystem rtnl_route_type_system = { @@ -499,7 +502,7 @@ static const NLTypeSystem rtnl_route_type_system = { .types = rtnl_route_types, }; -static const NLType rtnl_neigh_types[NDA_MAX + 1] = { +static const NLType rtnl_neigh_types[] = { [NDA_DST] = { .type = NETLINK_TYPE_IN_ADDR }, [NDA_LLADDR] = { .type = NETLINK_TYPE_ETHER_ADDR }, [NDA_CACHEINFO] = { .type = NETLINK_TYPE_CACHE_INFO, .size = sizeof(struct nda_cacheinfo) }, @@ -515,7 +518,7 @@ static const NLTypeSystem rtnl_neigh_type_system = { .types = rtnl_neigh_types, }; -static const NLType rtnl_types[RTM_MAX + 1] = { +static const NLType rtnl_types[] = { [NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 }, [NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) }, [RTM_NEWLINK] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 482ff6b1c2..6f9fd2993b 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -19,7 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - #include "sd-netlink.h" #include "netlink-util.h" diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 9df0aa28bf..acc6c15ff3 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -21,9 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-netlink.h" #include "util.h" -#include "sd-netlink.h" int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret); uint32_t rtnl_message_get_serial(sd_netlink_message *m); diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 2f31f4ee69..3e605db661 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -23,16 +23,16 @@ #include <stdbool.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" +#include "sd-netlink.h" + #include "formats-util.h" -#include "refcnt.h" #include "missing.h" - -#include "sd-netlink.h" -#include "netlink-util.h" #include "netlink-internal.h" #include "netlink-types.h" +#include "netlink-util.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) { struct rtmsg *rtm; @@ -84,6 +84,35 @@ int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) return 0; } +int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + rtm->rtm_flags = flags; + + return 0; +} + +int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(flags, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *flags = rtm->rtm_flags; + + return 0; +} + int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) { struct rtmsg *rtm; @@ -99,6 +128,66 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) { return 0; } +int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(protocol, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *protocol = rtm->rtm_protocol; + + return 0; +} + +int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(scope, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *scope = rtm->rtm_scope; + + return 0; +} + +int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(tos, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *tos = rtm->rtm_tos; + + return 0; +} + +int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(table, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *table = rtm->rtm_table; + + return 0; +} + int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) { struct rtmsg *rtm; diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index d248869c8d..7c24e053cf 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -19,17 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <poll.h> - -#include "missing.h" -#include "macro.h" -#include "util.h" -#include "hashmap.h" +#include <sys/socket.h> #include "sd-netlink.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "hashmap.h" +#include "macro.h" +#include "missing.h" #include "netlink-internal.h" #include "netlink-util.h" +#include "socket-util.h" +#include "util.h" static int sd_netlink_new(sd_netlink **ret) { _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; @@ -183,10 +186,11 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) { sd_event_unref(rtnl->event); while ((f = rtnl->match_callbacks)) { - LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f); - free(f); + sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata); } + hashmap_free(rtnl->broadcast_group_refs); + safe_close(rtnl->fd); free(rtnl); } @@ -856,26 +860,33 @@ int sd_netlink_add_match(sd_netlink *rtnl, switch (type) { case RTM_NEWLINK: - case RTM_SETLINK: - case RTM_GETLINK: case RTM_DELLINK: - r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK); + r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK); if (r < 0) return r; break; case RTM_NEWADDR: - case RTM_GETADDR: case RTM_DELADDR: - r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR); + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR); if (r < 0) return r; - r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR); + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR); if (r < 0) return r; break; + case RTM_NEWROUTE: + case RTM_DELROUTE: + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE); + if (r < 0) + return r; + + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE); + if (r < 0) + return r; + break; default: return -EOPNOTSUPP; } @@ -892,23 +903,50 @@ int sd_netlink_remove_match(sd_netlink *rtnl, sd_netlink_message_handler_t callback, void *userdata) { struct match_callback *c; + int r; assert_return(rtnl, -EINVAL); assert_return(callback, -EINVAL); assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - /* we should unsubscribe from the broadcast groups at this point, but it is not so - trivial for a few reasons: the refcounting is a bit of a mess and not obvious - how it will look like after we add genetlink support, and it is also not possible - to query what broadcast groups were subscribed to when we inherit the socket to get - the initial refcount. The latter could indeed be done for the first 32 broadcast - groups (which incidentally is all we currently support in .socket units anyway), - but we better not rely on only ever using 32 groups. */ LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) if (c->callback == callback && c->type == type && c->userdata == userdata) { LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c); free(c); + switch (type) { + case RTM_NEWLINK: + case RTM_DELLINK: + r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK); + if (r < 0) + return r; + + break; + case RTM_NEWADDR: + case RTM_DELADDR: + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR); + if (r < 0) + return r; + + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR); + if (r < 0) + return r; + + break; + case RTM_NEWROUTE: + case RTM_DELROUTE: + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE); + if (r < 0) + return r; + + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE); + if (r < 0) + return r; + break; + default: + return -EOPNOTSUPP; + } + return 1; } diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c index 9867eec065..7180175970 100644 --- a/src/libsystemd/sd-netlink/test-local-addresses.c +++ b/src/libsystemd/sd-netlink/test-local-addresses.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "in-addr-util.h" #include "local-addresses.h" #include "af-list.h" diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index c9cb415ca0..58b774e0e1 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -19,16 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/ether.h> #include <net/if.h> +#include <netinet/ether.h> -#include "util.h" -#include "macro.h" #include "sd-netlink.h" -#include "socket-util.h" -#include "netlink-util.h" + +#include "ether-addr-util.h" #include "event-util.h" +#include "macro.h" #include "missing.h" +#include "netlink-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" static void test_message_link_bridge(sd_netlink *rtnl) { _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index 48958e8a9f..a2d6c59314 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" +#include "alloc-util.h" +#include "fd-util.h" #include "network-util.h" +#include "strv.h" bool network_is_online(void) { _cleanup_free_ char *state = NULL; diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 87d87359b8..efbceba83d 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -20,16 +20,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> -#include <sys/inotify.h> #include <poll.h> +#include <string.h> +#include <sys/inotify.h> -#include "util.h" +#include "sd-network.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "macro.h" +#include "parse-util.h" +#include "string-util.h" #include "strv.h" -#include "fileio.h" -#include "sd-network.h" +#include "util.h" _public_ int sd_network_get_operational_state(char **state) { _cleanup_free_ char *s = NULL; diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c index 7363be2794..480f1ad065 100644 --- a/src/libsystemd/sd-path/sd-path.c +++ b/src/libsystemd/sd-path/sd-path.c @@ -17,12 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "sd-path.h" + +#include "alloc-util.h" #include "architecture.h" +#include "fd-util.h" +#include "fileio.h" +#include "missing.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" -#include "sd-path.h" -#include "missing.h" +#include "user-util.h" +#include "util.h" static int from_environment(const char *envname, const char *fallback, const char **ret) { assert(ret); diff --git a/src/libsystemd/sd-resolve/resolve-util.h b/src/libsystemd/sd-resolve/resolve-util.h index 019cdaffe1..51a8a8af83 100644 --- a/src/libsystemd/sd-resolve/resolve-util.h +++ b/src/libsystemd/sd-resolve/resolve-util.h @@ -21,9 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "sd-resolve.h" +#include "util.h" + DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve*, sd_resolve_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve_query*, sd_resolve_query_unref); diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 888b372c99..34a0b03f92 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -19,24 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <signal.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <errno.h> +#include <poll.h> +#include <pthread.h> #include <resolv.h> +#include <signal.h> #include <stdint.h> -#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/prctl.h> -#include <poll.h> +#include <unistd.h> -#include "util.h" +#include "sd-resolve.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "list.h" -#include "socket-util.h" #include "missing.h" #include "resolve-util.h" -#include "sd-resolve.h" +#include "socket-util.h" +#include "util.h" #define WORKERS_MIN 1U #define WORKERS_MAX 16U @@ -580,12 +584,8 @@ static void resolve_free(sd_resolve *resolve) { } /* Now terminate them and wait until they are gone. */ - for (i = 0; i < resolve->n_valid_workers; i++) { - for (;;) { - if (pthread_join(resolve->workers[i], NULL) != EINTR) - break; - } - } + for (i = 0; i < resolve->n_valid_workers; i++) + pthread_join(resolve->workers[i], NULL); /* Close all communication channels */ for (i = 0; i < _FD_MAX; i++) diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c index e8056529f5..05544a584c 100644 --- a/src/libsystemd/sd-resolve/test-resolve.c +++ b/src/libsystemd/sd-resolve/test-resolve.c @@ -20,18 +20,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <sys/socket.h> #include <arpa/inet.h> -#include <stdio.h> +#include <errno.h> #include <netinet/in.h> #include <resolv.h> -#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> -#include "socket-util.h" #include "sd-resolve.h" -#include "resolve-util.h" + +#include "alloc-util.h" #include "macro.h" +#include "resolve-util.h" +#include "socket-util.h" +#include "string-util.h" static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) { const struct addrinfo *i; diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c index 6f2aa6064c..381397cc52 100644 --- a/src/libsystemd/sd-utf8/sd-utf8.c +++ b/src/libsystemd/sd-utf8/sd-utf8.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-utf8.h" + #include "util.h" #include "utf8.h" -#include "sd-utf8.h" _public_ const char *sd_utf8_is_valid(const char *s) { assert_return(s, NULL); diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h index aa36b8cb12..40d59201cf 100644 --- a/src/libudev/libudev-device-internal.h +++ b/src/libudev/libudev-device-internal.h @@ -21,9 +21,10 @@ #pragma once #include "libudev.h" -#include "libudev-private.h" #include "sd-device.h" +#include "libudev-private.h" + /** * udev_device: * diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c index 4b9c053b54..2d3e62410c 100644 --- a/src/libudev/libudev-device-private.c +++ b/src/libudev/libudev-device-private.c @@ -19,10 +19,10 @@ ***/ #include "libudev.h" -#include "libudev-private.h" -#include "libudev-device-internal.h" #include "device-private.h" +#include "libudev-device-internal.h" +#include "libudev-private.h" int udev_device_tag_index(struct udev_device *udev_device, struct udev_device *udev_device_old, bool add) { sd_device *device_old = NULL; diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index 9a8d682107..814e016800 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -18,29 +18,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdbool.h> -#include <errno.h> -#include <string.h> +#include <ctype.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> -#include <ctype.h> +#include <linux/sockios.h> #include <net/if.h> -#include <sys/stat.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/socket.h> -#include <linux/sockios.h> +#include <sys/stat.h> +#include <unistd.h> +#include "libudev.h" #include "sd-device.h" -#include "device-util.h" -#include "device-private.h" -#include "libudev.h" -#include "libudev-private.h" +#include "alloc-util.h" +#include "device-private.h" +#include "device-util.h" #include "libudev-device-internal.h" +#include "libudev-private.h" +#include "parse-util.h" /** * SECTION:libudev-device diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c index df088946df..442f9615f2 100644 --- a/src/libudev/libudev-enumerate.c +++ b/src/libudev/libudev-enumerate.c @@ -18,22 +18,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <errno.h> -#include <string.h> #include <dirent.h> +#include <errno.h> #include <fnmatch.h> #include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include "libudev.h" -#include "libudev-device-internal.h" #include "sd-device.h" -#include "device-util.h" -#include "device-enumerator-private.h" +#include "alloc-util.h" +#include "device-enumerator-private.h" +#include "device-util.h" +#include "libudev-device-internal.h" /** * SECTION:libudev-enumerate diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c index 98951fb85b..eba698d163 100644 --- a/src/libudev/libudev-hwdb.c +++ b/src/libudev/libudev-hwdb.c @@ -17,9 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "libudev-private.h" #include "sd-hwdb.h" + +#include "alloc-util.h" #include "hwdb-util.h" +#include "libudev-private.h" /** * SECTION:libudev-hwdb diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c index 19e9130be0..da496ed456 100644 --- a/src/libudev/libudev-list.c +++ b/src/libudev/libudev-list.c @@ -17,11 +17,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stddef.h> #include <errno.h> +#include <stddef.h> +#include <stdlib.h> #include <string.h> +#include "alloc-util.h" #include "libudev-private.h" /** diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index 282aa2b0d9..f870eba9eb 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -17,22 +17,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> +#include <linux/filter.h> +#include <linux/netlink.h> +#include <poll.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> #include <string.h> -#include <poll.h> #include <sys/socket.h> -#include <linux/netlink.h> -#include <linux/filter.h> +#include <unistd.h> #include "libudev.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" #include "libudev-private.h" -#include "socket-util.h" #include "missing.h" -#include "formats-util.h" +#include "mount-util.h" +#include "socket-util.h" +#include "string-util.h" /** * SECTION:libudev-monitor @@ -408,10 +414,8 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) if (err >= 0) monitor_set_nl_address(udev_monitor); - else { - log_debug_errno(errno, "bind failed: %m"); - return -errno; - } + else + return log_debug_errno(errno, "bind failed: %m"); /* enable receiving of sender credentials */ err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 1240ea79cc..5f50496291 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -25,10 +25,11 @@ #include <stdbool.h> #include "libudev.h" + #include "macro.h" -#include "util.h" #include "mkdir.h" #include "strxcpyx.h" +#include "util.h" #define READ_END 0 #define WRITE_END 1 @@ -135,8 +136,6 @@ int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_expor #define UTIL_NAME_SIZE 512 #define UTIL_LINE_SIZE 16384 #define UDEV_ALLOWED_CHARS_INPUT "/ $%?," -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size); -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size); int util_log_priority(const char *priority); size_t util_path_encode(const char *src, char *dest, size_t size); void util_remove_trailing_chars(char *path, char c); diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c index 11e15d13e6..58410b1b8f 100644 --- a/src/libudev/libudev-queue.c +++ b/src/libudev/libudev-queue.c @@ -24,6 +24,9 @@ #include <errno.h> #include <sys/inotify.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "libudev-private.h" /** diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index f4656277c6..574cfeac85 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -17,18 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> +#include <ctype.h> #include <errno.h> +#include <stddef.h> +#include <stdlib.h> #include <string.h> -#include <ctype.h> +#include <unistd.h> -#include "device-nodes.h" #include "libudev.h" + +#include "MurmurHash2.h" +#include "device-nodes.h" #include "libudev-private.h" +#include "syslog-util.h" #include "utf8.h" -#include "MurmurHash2.h" /** * SECTION:libudev-util @@ -100,52 +102,6 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string, return 0; } -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size) -{ - char path[UTIL_PATH_SIZE]; - char target[UTIL_PATH_SIZE]; - ssize_t len; - const char *pos; - - strscpyl(path, sizeof(path), syspath, "/", slink, NULL); - len = readlink(path, target, sizeof(target)); - if (len <= 0 || len == (ssize_t)sizeof(target)) - return -1; - target[len] = '\0'; - pos = strrchr(target, '/'); - if (pos == NULL) - return -1; - pos = &pos[1]; - return strscpy(value, size, pos); -} - -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size) -{ - char link_target[UTIL_PATH_SIZE]; - - ssize_t len; - int i; - int back; - char *base = NULL; - - len = readlink(syspath, link_target, sizeof(link_target)); - if (len <= 0 || len == (ssize_t)sizeof(link_target)) - return -1; - link_target[len] = '\0'; - - for (back = 0; startswith(&link_target[back * 3], "../"); back++) - ; - for (i = 0; i <= back; i++) { - base = strrchr(syspath, '/'); - if (base == NULL) - return -EINVAL; - base[0] = '\0'; - } - - strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL); - return 0; -} - int util_log_priority(const char *priority) { char *endptr; diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c index ec15d2576b..63fb05547d 100644 --- a/src/libudev/libudev.c +++ b/src/libudev/libudev.c @@ -17,16 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <ctype.h> +#include <stdarg.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> #include <string.h> -#include <ctype.h> #include "libudev.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "libudev-private.h" #include "missing.h" +#include "string-util.h" /** * SECTION:libudev diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 880a1794aa..4a339dcfd4 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -32,6 +32,7 @@ #include "bus-error.h" #include "bus-util.h" #include "def.h" +#include "fd-util.h" #include "fileio.h" #include "locale-util.h" #include "pager.h" diff --git a/src/locale/localed.c b/src/locale/localed.c index e3eef4a610..720cbbaaba 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -24,25 +24,29 @@ #include <string.h> #include <unistd.h> +#ifdef HAVE_XKBCOMMON +#include <xkbcommon/xkbcommon.h> +#endif + #include "sd-bus.h" -#include "util.h" -#include "mkdir.h" -#include "strv.h" -#include "def.h" -#include "env-util.h" -#include "fileio.h" -#include "fileio-label.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-message.h" +#include "bus-util.h" +#include "def.h" +#include "env-util.h" #include "event-util.h" +#include "fd-util.h" +#include "fileio-label.h" +#include "fileio.h" #include "locale-util.h" +#include "mkdir.h" +#include "path-util.h" #include "selinux-util.h" - -#ifdef HAVE_XKBCOMMON -#include <xkbcommon/xkbcommon.h> -#endif +#include "strv.h" +#include "user-util.h" +#include "util.h" enum { /* We don't list LC_ALL here on purpose. People should be diff --git a/src/login/inhibit.c b/src/login/inhibit.c index e671341b42..70fef332f7 100644 --- a/src/login/inhibit.c +++ b/src/login/inhibit.c @@ -27,12 +27,15 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" +#include "fd-util.h" #include "formats-util.h" #include "process-util.h" #include "signal-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" static const char* arg_what = "idle:sleep:shutdown"; diff --git a/src/login/loginctl.c b/src/login/loginctl.c index bfc8716009..aff68a49fe 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -27,6 +27,7 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "cgroup-show.h" @@ -35,6 +36,7 @@ #include "logs-show.h" #include "macro.h" #include "pager.h" +#include "parse-util.h" #include "process-util.h" #include "signal-util.h" #include "spawn-polkit-agent.h" @@ -42,6 +44,7 @@ #include "sysfs-show.h" #include "terminal-util.h" #include "unit-name.h" +#include "user-util.h" #include "util.h" #include "verbs.h" diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c index 466225d69c..d0dd569a03 100644 --- a/src/login/logind-acl.c +++ b/src/login/logind-acl.c @@ -22,12 +22,17 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "formats-util.h" #include "acl-util.h" -#include "set.h" +#include "alloc-util.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" +#include "formats-util.h" #include "logind-acl.h" +#include "set.h" +#include "string-util.h" #include "udev-util.h" +#include "util.h" static int flush_acl(acl_t acl) { acl_entry_t i; diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h index ec09843a78..93e9ed02eb 100644 --- a/src/login/logind-acl.h +++ b/src/login/logind-acl.h @@ -23,7 +23,8 @@ #include <sys/types.h> #include <stdbool.h> -#include <libudev.h> + +#include "libudev.h" #ifdef HAVE_ACL diff --git a/src/login/logind-action.c b/src/login/logind-action.c index a44e369149..185108f8f1 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -21,15 +21,18 @@ #include <unistd.h> -#include "conf-parser.h" -#include "special.h" -#include "sleep-config.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" -#include "logind-action.h" +#include "bus-util.h" +#include "conf-parser.h" #include "formats-util.h" +#include "logind-action.h" #include "process-util.h" +#include "sleep-config.h" +#include "special.h" +#include "string-table.h" #include "terminal-util.h" +#include "user-util.h" int manager_handle_action( Manager *m, diff --git a/src/login/logind-action.h b/src/login/logind-action.h index ff98065371..e9b424b5f6 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -36,6 +36,7 @@ typedef enum HandleAction { } HandleAction; #include "logind.h" +#include "logind-inhibit.h" int manager_handle_action( Manager *m, diff --git a/src/login/logind-button.c b/src/login/logind-button.c index f40e35a8cb..b08b69dbfc 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -19,16 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> #include <fcntl.h> +#include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <linux/input.h> #include "sd-messages.h" -#include "util.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "logind-button.h" +#include "string-util.h" +#include "util.h" Button* button_new(Manager *m, const char *name) { Button *b; diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 6c05c11dbd..b3f30c8dc9 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -25,13 +25,16 @@ #include <pwd.h> #include <linux/vt.h> -#include "strv.h" -#include "cgroup-util.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" -#include "udev-util.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "fd-util.h" #include "logind.h" +#include "strv.h" #include "terminal-util.h" +#include "udev-util.h" +#include "user-util.h" int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) { Device *d; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 40d587ddb8..7890d68aa0 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -20,29 +20,36 @@ ***/ #include <errno.h> +#include <pwd.h> #include <string.h> #include <unistd.h> -#include <pwd.h> #include "sd-messages.h" -#include "strv.h" -#include "mkdir.h" -#include "path-util.h" -#include "special.h" -#include "sleep-config.h" -#include "fileio-label.h" -#include "unit-name.h" -#include "audit.h" -#include "bus-util.h" -#include "bus-error.h" + +#include "alloc-util.h" +#include "audit-util.h" #include "bus-common-errors.h" -#include "udev-util.h" -#include "selinux-util.h" +#include "bus-error.h" +#include "bus-util.h" +#include "dirent-util.h" #include "efivars.h" -#include "logind.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio-label.h" #include "formats-util.h" +#include "fs-util.h" +#include "logind.h" +#include "mkdir.h" +#include "path-util.h" #include "process-util.h" +#include "selinux-util.h" +#include "sleep-config.h" +#include "special.h" +#include "strv.h" #include "terminal-util.h" +#include "udev-util.h" +#include "unit-name.h" +#include "user-util.h" #include "utmp-wtmp.h" int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) { @@ -2024,7 +2031,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd } utmp_wall("The system shutdown has been cancelled", - lookup_uid(uid), tty, logind_wall_tty_filter, m); + uid_to_name(uid), tty, logind_wall_tty_filter, m); } return sd_bus_reply_method_return(message, "b", cancelled); @@ -2588,7 +2595,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err } if (m->action_job && streq(m->action_job, path)) { - log_info("Operation finished."); + log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what)); /* Tell people that they now may take a lock again */ send_prepare_for(m, m->action_what, false); diff --git a/src/login/logind-device.c b/src/login/logind-device.c index ee4c45fb8d..ffb9162e56 100644 --- a/src/login/logind-device.c +++ b/src/login/logind-device.c @@ -21,8 +21,9 @@ #include <string.h> -#include "util.h" +#include "alloc-util.h" #include "logind-device.h" +#include "util.h" Device* device_new(Manager *m, const char *sysfs, bool master) { Device *d; diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 0c9c1e5e97..33fbdde557 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -24,11 +24,18 @@ #include <string.h> #include <unistd.h> -#include "util.h" -#include "mkdir.h" -#include "logind-inhibit.h" +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "logind-inhibit.h" +#include "mkdir.h" +#include "parse-util.h" +#include "string-table.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" Inhibitor* inhibitor_new(Manager *m, const char* id) { Inhibitor *i; diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 346e1d2cec..43b578f364 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -22,13 +22,15 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "bus-util.h" -#include "strv.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" -#include "logind.h" +#include "bus-util.h" #include "logind-seat.h" +#include "logind.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" static int property_get_active_session( sd_bus *bus, diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index 8d13a63688..1f4936cebe 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -20,17 +20,23 @@ ***/ #include <errno.h> -#include <unistd.h> #include <fcntl.h> #include <string.h> +#include <unistd.h> #include "sd-messages.h" -#include "logind-seat.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" #include "logind-acl.h" -#include "util.h" +#include "logind-seat.h" #include "mkdir.h" -#include "formats-util.h" +#include "parse-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" Seat *seat_new(Manager *m, const char *id) { Seat *s; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index e6b4ccd7c6..7810199a54 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -22,15 +22,16 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "strv.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" - -#include "logind.h" -#include "logind-session.h" +#include "bus-util.h" +#include "fd-util.h" #include "logind-session-device.h" +#include "logind-session.h" +#include "logind.h" +#include "strv.h" +#include "util.h" static int property_get_user( sd_bus *bus, diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c index 656f268dba..9bf3ca0995 100644 --- a/src/login/logind-session-device.c +++ b/src/login/logind-session-device.c @@ -20,16 +20,19 @@ ***/ #include <fcntl.h> -#include <libudev.h> #include <linux/input.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> -#include "util.h" -#include "missing.h" +#include "libudev.h" + +#include "alloc-util.h" #include "bus-util.h" +#include "fd-util.h" #include "logind-session-device.h" +#include "missing.h" +#include "util.h" enum SessionDeviceNotifications { SESSION_DEVICE_RESUME, diff --git a/src/login/logind-session.c b/src/login/logind-session.c index f5fe030b07..1d561a6f8a 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -21,24 +21,33 @@ #include <errno.h> #include <fcntl.h> -#include <linux/vt.h> #include <linux/kd.h> +#include <linux/vt.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include "sd-messages.h" -#include "util.h" -#include "mkdir.h" -#include "path-util.h" -#include "fileio.h" -#include "audit.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "audit-util.h" #include "bus-error.h" -#include "logind-session.h" +#include "bus-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "io-util.h" +#include "logind-session.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-table.h" #include "terminal-util.h" +#include "user-util.h" +#include "util.h" #define RELEASE_USEC (20*USEC_PER_SEC) @@ -987,7 +996,7 @@ static int session_open_vt(Session *s) { sprintf(path, "/dev/tty%u", s->vtnr); s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); if (s->vtfd < 0) - return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id); + return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id); return s->vtfd; } @@ -1049,9 +1058,13 @@ error: } void session_restore_vt(Session *s) { + + static const struct vt_mode mode = { + .mode = VT_AUTO, + }; + _cleanup_free_ char *utf8 = NULL; - int vt, kb = K_XLATE; - struct vt_mode mode = { 0 }; + int vt, kb, old_fd; /* We need to get a fresh handle to the virtual terminal, * since the old file-descriptor is potentially in a hung-up @@ -1059,7 +1072,7 @@ void session_restore_vt(Session *s) { * little dance to avoid having the terminal be available * for reuse before we've cleaned it up. */ - int old_fd = s->vtfd; + old_fd = s->vtfd; s->vtfd = -1; vt = session_open_vt(s); @@ -1072,13 +1085,13 @@ void session_restore_vt(Session *s) { if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1') kb = K_UNICODE; + else + kb = K_XLATE; (void) ioctl(vt, KDSKBMODE, kb); - mode.mode = VT_AUTO; (void) ioctl(vt, VT_SETMODE, &mode); - - fchown(vt, 0, -1); + (void) fchown(vt, 0, (gid_t) -1); s->vtfd = safe_close(s->vtfd); } diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index 20ea2fbdc4..df901f6558 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -22,11 +22,13 @@ #include <errno.h> #include <string.h> -#include "strv.h" +#include "alloc-util.h" #include "bus-util.h" -#include "logind.h" -#include "logind-user.h" #include "formats-util.h" +#include "logind-user.h" +#include "logind.h" +#include "strv.h" +#include "user-util.h" static int property_get_display( sd_bus *bus, diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 451954e860..56bc5a010c 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -19,27 +19,35 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/mount.h> +#include <errno.h> #include <string.h> +#include <sys/mount.h> #include <unistd.h> -#include <errno.h> -#include "util.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "hashmap.h" -#include "fileio.h" -#include "path-util.h" -#include "special.h" -#include "unit-name.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" -#include "conf-parser.h" +#include "bus-util.h" #include "clean-ipc.h" -#include "smack-util.h" +#include "conf-parser.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "hashmap.h" #include "label.h" #include "logind-user.h" +#include "mkdir.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "rm-rf.h" +#include "smack-util.h" +#include "special.h" +#include "string-table.h" +#include "unit-name.h" +#include "user-util.h" +#include "util.h" User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) { User *u; diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 1e13ff01de..3e7a935a34 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -25,15 +25,18 @@ #include <pwd.h> #include "sd-messages.h" -#include "strv.h" -#include "special.h" -#include "unit-name.h" -#include "audit.h" -#include "bus-util.h" -#include "bus-error.h" + +#include "alloc-util.h" +#include "audit-util.h" #include "bus-common-errors.h" -#include "logind.h" +#include "bus-error.h" +#include "bus-util.h" #include "formats-util.h" +#include "logind.h" +#include "special.h" +#include "strv.h" +#include "unit-name.h" +#include "user-util.h" #include "utmp-wtmp.h" _const_ static usec_t when_wall(usec_t n, usec_t elapse) { @@ -94,7 +97,7 @@ static int warn_wall(Manager *m, usec_t n) { return 0; } - utmp_wall(l, lookup_uid(m->scheduled_shutdown_uid), + utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid), m->scheduled_shutdown_tty, logind_wall_tty_filter, m); return 1; diff --git a/src/login/logind.c b/src/login/logind.c index 8ac2aceb9b..be6bbe5b5c 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -20,20 +20,25 @@ ***/ #include <errno.h> -#include <libudev.h> #include <fcntl.h> #include <string.h> #include <unistd.h> +#include "libudev.h" #include "sd-daemon.h" -#include "strv.h" -#include "conf-parser.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "udev-util.h" +#include "bus-util.h" +#include "conf-parser.h" +#include "def.h" +#include "dirent-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "signal-util.h" #include "logind.h" +#include "signal-util.h" +#include "strv.h" +#include "udev-util.h" static void manager_free(Manager *m); @@ -292,8 +297,7 @@ static int manager_enumerate_seats(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/seats: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/seats: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -329,8 +333,7 @@ static int manager_enumerate_linger_users(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -365,8 +368,7 @@ static int manager_enumerate_users(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/users: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/users: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -406,8 +408,7 @@ static int manager_enumerate_sessions(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/sessions: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/sessions: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -453,8 +454,7 @@ static int manager_enumerate_inhibitors(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -744,8 +744,7 @@ static int manager_connect_console(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m"); } r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m); @@ -1103,8 +1102,8 @@ static int manager_run(Manager *m) { static int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many("/etc/systemd/logind.conf", - CONF_DIRS_NULSTR("systemd/logind.conf"), + return config_parse_many(PKGSYSCONFDIR "/logind.conf", + CONF_PATHS_NULSTR("systemd/logind.conf.d"), "Login\0", config_item_perf_lookup, logind_gperf_lookup, false, m); diff --git a/src/login/logind.h b/src/login/logind.h index 7990da5a93..44e05d8b01 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -22,20 +22,21 @@ ***/ #include <stdbool.h> -#include <libudev.h> -#include "sd-event.h" +#include "libudev.h" #include "sd-bus.h" -#include "list.h" +#include "sd-event.h" + #include "hashmap.h" +#include "list.h" #include "set.h" typedef struct Manager Manager; +#include "logind-action.h" +#include "logind-button.h" #include "logind-device.h" #include "logind-inhibit.h" -#include "logind-button.h" -#include "logind-action.h" struct Manager { sd_event *event; diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index f66f1ce842..0d61f528db 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -19,31 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <endian.h> #include <errno.h> #include <fcntl.h> -#include <sys/file.h> #include <pwd.h> -#include <endian.h> - -#include <security/pam_modules.h> #include <security/_pam_macros.h> -#include <security/pam_modutil.h> #include <security/pam_ext.h> #include <security/pam_misc.h> +#include <security/pam_modules.h> +#include <security/pam_modutil.h> +#include <sys/file.h> +#include "alloc-util.h" +#include "audit-util.h" #include "bus-common-errors.h" -#include "util.h" -#include "audit.h" -#include "macro.h" -#include "strv.h" +#include "bus-error.h" #include "bus-util.h" #include "def.h" -#include "socket-util.h" +#include "fd-util.h" #include "fileio.h" -#include "bus-error.h" #include "formats-util.h" -#include "terminal-util.h" #include "hostname-util.h" +#include "login-util.h" +#include "macro.h" +#include "parse-util.h" +#include "socket-util.h" +#include "strv.h" +#include "terminal-util.h" +#include "util.h" static int parse_argv( pam_handle_t *handle, diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c index f38f06baf9..e9ca4bb03d 100644 --- a/src/login/sysfs-show.c +++ b/src/login/sysfs-show.c @@ -21,13 +21,17 @@ #include <errno.h> #include <string.h> -#include <libudev.h> -#include "util.h" -#include "sysfs-show.h" +#include "libudev.h" + +#include "alloc-util.h" +#include "locale-util.h" #include "path-util.h" -#include "udev-util.h" +#include "string-util.h" +#include "sysfs-show.h" #include "terminal-util.h" +#include "udev-util.h" +#include "util.h" static int show_sysfs_one( struct udev *udev, diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c index 03516de916..d0727ff7c7 100644 --- a/src/login/test-inhibit.c +++ b/src/login/test-inhibit.c @@ -21,10 +21,12 @@ #include <unistd.h> -#include "macro.h" -#include "util.h" #include "sd-bus.h" + #include "bus-util.h" +#include "fd-util.h" +#include "macro.h" +#include "util.h" static int inhibit(sd_bus *bus, const char *what) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index a9c4e3fadf..f1165ea09c 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -27,8 +27,9 @@ #include "log.h" #include "machine-id-setup.h" #include "util.h" +#include "path-util.h" -static const char *arg_root = NULL; +static char *arg_root = NULL; static bool arg_commit = false; static void help(void) { @@ -57,7 +58,7 @@ static int parse_argv(int argc, char *argv[]) { {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -74,7 +75,9 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_ROOT: - arg_root = optarg; + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case ARG_COMMIT: @@ -104,13 +107,14 @@ int main(int argc, char *argv[]) { r = parse_argv(argc, argv); if (r <= 0) - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + goto finish; if (arg_commit) r = machine_id_commit(arg_root); else r = machine_id_setup(arg_root); - +finish: + free(arg_root); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 2453a9ff04..4ec1766033 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -19,11 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-label.h" -#include "strv.h" #include "bus-util.h" -#include "machine-image.h" #include "image-dbus.h" +#include "machine-image.h" +#include "strv.h" +#include "user-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 6e41e92962..452130a29c 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -29,23 +29,27 @@ #include <libgen.h> #undef basename -#include "bus-util.h" -#include "bus-label.h" -#include "strv.h" +#include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-internal.h" +#include "bus-label.h" +#include "bus-util.h" #include "copy.h" +#include "env-util.h" +#include "fd-util.h" #include "fileio.h" +#include "formats-util.h" +#include "fs-util.h" #include "in-addr-util.h" #include "local-addresses.h" -#include "path-util.h" -#include "mkdir.h" -#include "bus-internal.h" -#include "machine.h" #include "machine-dbus.h" -#include "formats-util.h" +#include "machine.h" +#include "mkdir.h" +#include "path-util.h" #include "process-util.h" -#include "env-util.h" +#include "strv.h" #include "terminal-util.h" +#include "user-util.h" static int property_get_id( sd_bus *bus, diff --git a/src/machine/machine.c b/src/machine/machine.c index 7ab84607fb..196bc4b8f4 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -25,18 +25,24 @@ #include "sd-messages.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "hashmap.h" +#include "machine-dbus.h" +#include "machine.h" #include "mkdir.h" +#include "parse-util.h" #include "special.h" +#include "string-table.h" #include "terminal-util.h" #include "unit-name.h" #include "util.h" -#include "machine-dbus.h" -#include "machine.h" +#include "extract-word.h" Machine* machine_new(Manager *manager, MachineClass class, const char *name) { Machine *m; @@ -307,19 +313,26 @@ int machine_load(Machine *m) { } if (netif) { - size_t l, allocated = 0, nr = 0; - const char *word, *state; + size_t allocated = 0, nr = 0; + const char *p; int *ni = NULL; - FOREACH_WORD(word, l, netif, state) { - char buf[l+1]; + p = netif; + for(;;) { + _cleanup_free_ char *word = NULL; int ifi; - *(char*) (mempcpy(buf, word, l)) = 0; + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_warning_errno(r, "Failed to parse NETIF: %s", netif); + break; + } - if (safe_atoi(buf, &ifi) < 0) - continue; - if (ifi <= 0) + if (parse_ifindex(word, &ifi) < 0) continue; if (!GREEDY_REALLOC(ni, allocated, nr+1)) { @@ -539,7 +552,7 @@ int machine_kill(Machine *m, KillWho who, int signo) { return 0; } - /* Otherwise make PID 1 do it for us, for the entire cgroup */ + /* Otherwise, make PID 1 do it for us, for the entire cgroup */ return manager_kill_unit(m->manager, m->unit, signo, NULL); } diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 0a21ab4415..7e17c7a41c 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -33,6 +33,7 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "cgroup-show.h" @@ -40,6 +41,7 @@ #include "copy.h" #include "env-util.h" #include "event-util.h" +#include "fd-util.h" #include "hostname-util.h" #include "import-util.h" #include "log.h" @@ -47,6 +49,7 @@ #include "macro.h" #include "mkdir.h" #include "pager.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "ptyfwd.h" @@ -57,6 +60,7 @@ #include "unit-name.h" #include "util.h" #include "verbs.h" +#include "web-util.h" static char **arg_property = NULL; static bool arg_all = false; @@ -1092,9 +1096,10 @@ static int copy_files(int argc, char *argv[], void *userdata) { container_path = copy_from ? argv[2] : dest; if (!path_is_absolute(host_path)) { - abs_host_path = path_make_absolute_cwd(host_path); - if (!abs_host_path) - return log_oom(); + r = path_make_absolute_cwd(host_path, &abs_host_path); + if (r < 0) + return log_error_errno(r, "Failed to make path absolute: %m"); + host_path = abs_host_path; } @@ -1110,10 +1115,8 @@ static int copy_files(int argc, char *argv[], void *userdata) { argv[1], copy_from ? container_path : host_path, copy_from ? host_path : container_path); - if (r < 0) { - log_error("Failed to copy: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r)); return 0; } @@ -2382,7 +2385,7 @@ static int set_limit(int argc, char *argv[], void *userdata) { uint64_t limit; int r; - if (streq(argv[argc-1], "-")) + if (STR_IN_SET(argv[argc-1], "-", "none", "infinity")) limit = (uint64_t) -1; else { r = parse_size(argv[argc-1], 1024, &limit); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 41bb106d28..7827f063c1 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -24,21 +24,26 @@ #include <unistd.h> #include "sd-id128.h" -#include "strv.h" -#include "path-util.h" -#include "unit-name.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "btrfs-util.h" #include "bus-common-errors.h" +#include "bus-util.h" #include "cgroup-util.h" -#include "btrfs-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "process-util.h" #include "hostname-util.h" +#include "image-dbus.h" +#include "machine-dbus.h" #include "machine-image.h" #include "machine-pool.h" -#include "image-dbus.h" #include "machined.h" -#include "machine-dbus.h" +#include "path-util.h" +#include "process-util.h" +#include "stdio-util.h" +#include "strv.h" +#include "unit-name.h" +#include "user-util.h" static int property_get_pool_path( sd_bus *bus, @@ -79,7 +84,7 @@ static int property_get_pool_usage( if (fd >= 0) { BtrfsQuotaInfo q; - if (btrfs_subvol_get_quota_fd(fd, &q) >= 0) + if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0) usage = q.referenced; } @@ -115,7 +120,7 @@ static int property_get_pool_limit( if (fd >= 0) { BtrfsQuotaInfo q; - if (btrfs_subvol_get_quota_fd(fd, &q) >= 0) + if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0) size = q.referenced_max; } @@ -831,7 +836,9 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */ return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m"); - r = btrfs_quota_limit("/var/lib/machines", limit); + (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit); + + r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit); if (r == -ENOTTY) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs."); if (r < 0) diff --git a/src/machine/machined.c b/src/machine/machined.c index df3cc9972a..a099de9f36 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -24,15 +24,19 @@ #include <unistd.h> #include "sd-daemon.h" -#include "cgroup-util.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "label.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "signal-util.h" #include "hostname-util.h" +#include "label.h" #include "machine-image.h" #include "machined.h" +#include "signal-util.h" Manager *manager_new(void) { Manager *m; @@ -146,8 +150,7 @@ int manager_enumerate_machines(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/machines: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/machines: %m"); } FOREACH_DIRENT(de, d, return -errno) { diff --git a/src/machine/machined.h b/src/machine/machined.h index b3e59bf998..dac7a29ed1 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -23,10 +23,11 @@ #include <stdbool.h> -#include "list.h" -#include "hashmap.h" -#include "sd-event.h" #include "sd-bus.h" +#include "sd-event.h" + +#include "hashmap.h" +#include "list.h" typedef struct Manager Manager; diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index b0a3add3e7..a7fdcb09cf 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -21,19 +21,24 @@ #include <errno.h> #include <getopt.h> +#include <libkmod.h> #include <limits.h> #include <string.h> #include <sys/stat.h> -#include <libkmod.h> #include "conf-files.h" +#include "def.h" +#include "fd-util.h" +#include "fileio.h" #include "log.h" +#include "proc-cmdline.h" +#include "string-util.h" #include "strv.h" #include "util.h" static char **arg_proc_cmdline_modules = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("modules-load"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d"); static void systemd_kmod_log(void *data, int priority, const char *file, int line, const char *fn, const char *format, va_list args) { @@ -146,8 +151,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent if (feof(f)) break; - log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); } l = strstrip(line); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index c78b9444b6..446b048ef1 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -28,15 +28,21 @@ #include "sd-netlink.h" #include "sd-network.h" +#include "alloc-util.h" #include "arphrd-list.h" #include "device-util.h" #include "ether-addr-util.h" #include "hwdb-util.h" #include "lldp.h" #include "local-addresses.h" +#include "locale-util.h" +#include "locale-util.h" #include "netlink-util.h" #include "pager.h" +#include "parse-util.h" #include "socket-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "util.h" @@ -515,7 +521,7 @@ static int link_status_one( assert(rtnl); assert(name); - if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0) + if (parse_ifindex(name, &ifindex) >= 0) r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex); else { r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); @@ -904,12 +910,10 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; - const char *state, *word; - double ttl = -1; uint32_t capability; int i, r, c, j; - size_t ll; + const char *p; char **s; pager_open_if_enabled(); @@ -950,14 +954,19 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { return -ENOMEM; STRV_FOREACH(s, l) { - FOREACH_WORD_QUOTED(word, ll, *s, state) { - _cleanup_free_ char *t = NULL, *a = NULL, *b = NULL; - t = strndup(word, ll); - if (!t) - return -ENOMEM; + p = *s; + for (;;) { + _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s); + + if (r == 0) + break; - r = split_pair(t, "=", &a, &b); + r = split_pair(word, "=", &a, &b); if (r < 0) continue; diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c index d609daafde..889fe1e30d 100644 --- a/src/network/networkd-address-pool.c +++ b/src/network/networkd-address-pool.c @@ -19,8 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "networkd.h" +#include "alloc-util.h" #include "networkd-address-pool.h" +#include "networkd.h" +#include "set.h" +#include "string-util.h" int address_pool_new( Manager *m, @@ -96,9 +99,10 @@ static bool address_pool_prefix_is_taken( HASHMAP_FOREACH(l, p->manager->links, i) { Address *a; + Iterator j; /* Don't clash with assigned addresses */ - LIST_FOREACH(addresses, a, l->addresses) { + SET_FOREACH(a, l->addresses, j) { if (a->family != p->family) continue; diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 388beb5d4c..c0562e5788 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -21,26 +21,39 @@ #include <net/if.h> -#include "utf8.h" -#include "util.h" +#include "alloc-util.h" #include "conf-parser.h" #include "firewall-util.h" #include "netlink-util.h" - -#include "networkd.h" #include "networkd-address.h" +#include "networkd.h" +#include "parse-util.h" +#include "set.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" -static void address_init(Address *address) { - assert(address); +int address_new(Address **ret) { + _cleanup_address_free_ Address *address = NULL; + + address = new0(Address, 1); + if (!address) + return -ENOMEM; address->family = AF_UNSPEC; address->scope = RT_SCOPE_UNIVERSE; address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME; address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME; + + *ret = address; + address = NULL; + + return 0; } int address_new_static(Network *network, unsigned section, Address **ret) { _cleanup_address_free_ Address *address = NULL; + int r; if (section) { address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section)); @@ -52,11 +65,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) { } } - address = new0(Address, 1); - if (!address) - return -ENOMEM; - - address_init(address); + r = address_new(&address); + if (r < 0) + return r; address->network = network; @@ -74,21 +85,6 @@ int address_new_static(Network *network, unsigned section, Address **ret) { return 0; } -int address_new_dynamic(Address **ret) { - _cleanup_address_free_ Address *address = NULL; - - address = new0(Address, 1); - if (!address) - return -ENOMEM; - - address_init(address); - - *ret = address; - address = NULL; - - return 0; -} - void address_free(Address *address) { if (!address) return; @@ -101,10 +97,112 @@ void address_free(Address *address) { UINT_TO_PTR(address->section)); } + if (address->link) { + set_remove(address->link->addresses, address); + set_remove(address->link->addresses_foreign, address); + } + free(address); } -int address_establish(Address *address, Link *link) { +static void address_hash_func(const void *b, struct siphash *state) { + const Address *a = b; + + assert(a); + + siphash24_compress(&a->family, sizeof(a->family), state); + + switch (a->family) { + case AF_INET: + siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state); + + /* peer prefix */ + if (a->prefixlen != 0) { + uint32_t prefix; + + if (a->in_addr_peer.in.s_addr != 0) + prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen); + else + prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen); + + siphash24_compress(&prefix, sizeof(prefix), state); + } + + /* fallthrough */ + case AF_INET6: + /* local address */ + siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state); + + break; + default: + /* treat any other address family as AF_UNSPEC */ + break; + } +} + +static int address_compare_func(const void *c1, const void *c2) { + const Address *a1 = c1, *a2 = c2; + + if (a1->family < a2->family) + return -1; + if (a1->family > a2->family) + return 1; + + switch (a1->family) { + /* use the same notion of equality as the kernel does */ + case AF_INET: + if (a1->prefixlen < a2->prefixlen) + return -1; + if (a1->prefixlen > a2->prefixlen) + return 1; + + /* compare the peer prefixes */ + if (a1->prefixlen != 0) { + /* make sure we don't try to shift by 32. + * See ISO/IEC 9899:TC3 § 6.5.7.3. */ + uint32_t b1, b2; + + if (a1->in_addr_peer.in.s_addr != 0) + b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen); + else + b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen); + + if (a2->in_addr_peer.in.s_addr != 0) + b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen); + else + b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen); + + if (b1 < b2) + return -1; + if (b1 > b2) + return 1; + } + + /* fall-through */ + case AF_INET6: + return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family)); + default: + /* treat any other address family as AF_UNSPEC */ + return 0; + } +} + +static const struct hash_ops address_hash_ops = { + .hash = address_hash_func, + .compare = address_compare_func +}; + +bool address_equal(Address *a1, Address *a2) { + if (a1 == a2) + return true; + + if (!a1 || !a2) + return false; + + return address_compare_func(a1, a2) == 0; +} + +static int address_establish(Address *address, Link *link) { bool masq; int r; @@ -112,9 +210,9 @@ int address_establish(Address *address, Link *link) { assert(link); masq = link->network && - link->network->ip_masquerade && - address->family == AF_INET && - address->scope < RT_SCOPE_LINK; + link->network->ip_masquerade && + address->family == AF_INET && + address->scope < RT_SCOPE_LINK; /* Add firewall entry if this is requested */ if (address->ip_masquerade_done != masq) { @@ -131,11 +229,88 @@ int address_establish(Address *address, Link *link) { return 0; } -int address_release(Address *address, Link *link) { +static int address_add_internal(Link *link, Set **addresses, + int family, + const union in_addr_union *in_addr, + unsigned char prefixlen, + Address **ret) { + _cleanup_address_free_ Address *address = NULL; int r; - assert(address); assert(link); + assert(addresses); + assert(in_addr); + + r = address_new(&address); + if (r < 0) + return r; + + address->family = family; + address->in_addr = *in_addr; + address->prefixlen = prefixlen; + /* Consider address tentative until we get the real flags from the kernel */ + address->flags = IFA_F_TENTATIVE; + + r = set_ensure_allocated(addresses, &address_hash_ops); + if (r < 0) + return r; + + r = set_put(*addresses, address); + if (r < 0) + return r; + + address->link = link; + + if (ret) + *ret = address; + + address = NULL; + + return 0; +} + +int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) { + return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret); +} + +int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) { + Address *address; + int r; + + r = address_get(link, family, in_addr, prefixlen, &address); + if (r == -ENOENT) { + /* Address does not exist, create a new one */ + r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address); + if (r < 0) + return r; + } else if (r == 0) { + /* Take over a foreign address */ + r = set_ensure_allocated(&link->addresses, &address_hash_ops); + if (r < 0) + return r; + + r = set_put(link->addresses, address); + if (r < 0) + return r; + + set_remove(link->addresses_foreign, address); + } else if (r == 1) { + /* Already exists, do nothing */ + ; + } else + return r; + + if (ret) + *ret = address; + + return 0; +} + +static int address_release(Address *address) { + int r; + + assert(address); + assert(address->link); /* Remove masquerading firewall entry if it was added */ if (address->ip_masquerade_done) { @@ -144,7 +319,7 @@ int address_release(Address *address, Link *link) { r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0); if (r < 0) - log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m"); + log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m"); address->ip_masquerade_done = false; } @@ -152,81 +327,106 @@ int address_release(Address *address, Link *link) { return 0; } -int address_drop(Address *address, Link *link, - sd_netlink_message_handler_t callback) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; +int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) { + bool ready; int r; assert(address); - assert(address->family == AF_INET || address->family == AF_INET6); - assert(link); - assert(link->ifindex > 0); - assert(link->manager); - assert(link->manager->rtnl); + assert(cinfo); - address_release(address, link); + ready = address_is_ready(address); - r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, - link->ifindex, address->family); - if (r < 0) - return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m"); + address->flags = flags; + address->scope = scope; + address->cinfo = *cinfo; - r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); - if (r < 0) - return log_error_errno(r, "Could not set prefixlen: %m"); + if (address->link) { + link_update_operstate(address->link); - if (address->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); - else if (address->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6); - if (r < 0) - return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m"); + if (!ready && address_is_ready(address)) { + link_check_ready(address->link); - r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); - if (r < 0) - return log_error_errno(r, "Could not send rtnetlink message: %m"); + if (address->family == AF_INET6 && + in_addr_is_link_local(AF_INET6, &address->in_addr) && + !address->link->ipv6ll_address) { + r = link_ipv6ll_gained(address->link); + if (r < 0) + return r; + } + } + } - link_ref(link); + return 0; +} + +int address_drop(Address *address) { + Link *link; + bool ready; + + assert(address); + + ready = address_is_ready(address); + link = address->link; + + address_release(address); + address_free(address); + + link_update_operstate(link); + + if (link && !ready) + link_check_ready(link); return 0; } -int address_update(Address *address, Link *link, - sd_netlink_message_handler_t callback) { +int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) { + Address address = {}, *existing; + + assert(link); + assert(in_addr); + assert(ret); + + address.family = family; + address.in_addr = *in_addr; + address.prefixlen = prefixlen; + + existing = set_get(link->addresses, &address); + if (existing) { + *ret = existing; + + return 1; + } else { + existing = set_get(link->addresses_foreign, &address); + if (!existing) + return -ENOENT; + } + + *ret = existing; + + return 0; +} + +int address_remove(Address *address, Link *link, + sd_netlink_message_handler_t callback) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; int r; assert(address); assert(address->family == AF_INET || address->family == AF_INET6); + assert(link); assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); - r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req, + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, link->ifindex, address->family); if (r < 0) - return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m"); + return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m"); r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); if (r < 0) return log_error_errno(r, "Could not set prefixlen: %m"); - address->flags |= IFA_F_PERMANENT; - - r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff); - if (r < 0) - return log_error_errno(r, "Could not set flags: %m"); - - if (address->flags & ~0xff && link->rtnl_extended_attrs) { - r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags); - if (r < 0) - return log_error_errno(r, "Could not set extended flags: %m"); - } - - r = sd_rtnl_message_addr_set_scope(req, address->scope); - if (r < 0) - return log_error_errno(r, "Could not set scope: %m"); - if (address->family == AF_INET) r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); else if (address->family == AF_INET6) @@ -234,22 +434,6 @@ int address_update(Address *address, Link *link, if (r < 0) return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m"); - if (address->family == AF_INET) { - r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); - if (r < 0) - return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m"); - } - - if (address->label) { - r = sd_netlink_message_append_string(req, IFA_LABEL, address->label); - if (r < 0) - return log_error_errno(r, "Could not append IFA_LABEL attribute: %m"); - } - - r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo); - if (r < 0) - return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m"); - r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); if (r < 0) return log_error_errno(r, "Could not send rtnetlink message: %m"); @@ -292,7 +476,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) { } else if (original->family == AF_INET6) in_addr.in6.s6_addr[15] |= 1; - r = address_new_dynamic(&na); + r = address_new(&na); if (r < 0) return r; @@ -318,8 +502,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) { return 0; } -int address_configure(Address *address, Link *link, - sd_netlink_message_handler_t callback) { +int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; int r; @@ -334,8 +517,12 @@ int address_configure(Address *address, Link *link, if (r < 0) return r; - r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR, - link->ifindex, address->family); + if (update) + r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req, + link->ifindex, address->family); + else + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR, + link->ifindex, address->family); if (r < 0) return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m"); @@ -392,13 +579,23 @@ int address_configure(Address *address, Link *link, if (r < 0) return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m"); - r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + r = address_establish(address, link); if (r < 0) + return r; + + r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) { + address_release(address); return log_error_errno(r, "Could not send rtnetlink message: %m"); + } link_ref(link); - address_establish(address, link); + r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); + if (r < 0) { + address_release(address); + return log_error_errno(r, "Could not add address: %m"); + } return 0; } @@ -580,49 +777,8 @@ int config_parse_label(const char *unit, return 0; } -bool address_equal(Address *a1, Address *a2) { - /* same object */ - if (a1 == a2) - return true; - - /* one, but not both, is NULL */ - if (!a1 || !a2) - return false; - - if (a1->family != a2->family) - return false; - - switch (a1->family) { - /* use the same notion of equality as the kernel does */ - case AF_UNSPEC: - return true; +bool address_is_ready(const Address *a) { + assert(a); - case AF_INET: - if (a1->prefixlen != a2->prefixlen) - return false; - else if (a1->prefixlen == 0) - /* make sure we don't try to shift by 32. - * See ISO/IEC 9899:TC3 § 6.5.7.3. */ - return true; - else { - uint32_t b1, b2; - - b1 = be32toh(a1->in_addr.in.s_addr); - b2 = be32toh(a2->in_addr.in.s_addr); - - return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen)); - } - - case AF_INET6: { - uint64_t *b1, *b2; - - b1 = (uint64_t*)&a1->in_addr.in6; - b2 = (uint64_t*)&a2->in_addr.in6; - - return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL); - } - - default: - assert_not_reached("Invalid address family"); - } + return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)); } diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 39789a2382..4049a23bdc 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -38,6 +38,8 @@ struct Address { Network *network; unsigned section; + Link *link; + int family; unsigned char prefixlen; unsigned char scope; @@ -50,20 +52,23 @@ struct Address { union in_addr_union in_addr; union in_addr_union in_addr_peer; - bool ip_masquerade_done; + bool ip_masquerade_done:1; LIST_FIELDS(Address, addresses); }; int address_new_static(Network *network, unsigned section, Address **ret); -int address_new_dynamic(Address **ret); +int address_new(Address **ret); void address_free(Address *address); -int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_establish(Address *address, Link *link); -int address_release(Address *address, Link *link); +int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); +int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); +int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); +int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo); +int address_drop(Address *address); +int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update); +int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback); bool address_equal(Address *a1, Address *a2); +bool address_is_ready(const Address *a); DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); #define _cleanup_address_free_ _cleanup_(address_freep) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 04f04df117..b9c60a3c77 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -22,10 +22,11 @@ #include <netinet/ether.h> #include <linux/if.h> +#include "alloc-util.h" +#include "dhcp-lease-internal.h" #include "hostname-util.h" -#include "networkd-link.h" #include "network-internal.h" -#include "dhcp-lease-internal.h" +#include "networkd-link.h" static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { @@ -33,7 +34,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, int r; assert(link); - assert(link->dhcp4_messages); + assert(link->dhcp4_messages > 0); link->dhcp4_messages --; @@ -43,9 +44,9 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, link_enter_failed(link); } - if (!link->dhcp4_messages) { + if (link->dhcp4_messages == 0) { link->dhcp4_configured = true; - link_client_handler(link); + link_check_ready(link); } return 1; @@ -72,11 +73,13 @@ static int link_set_dhcp_routes(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "DHCP error: could not get address: %m"); - r = route_new_dynamic(&route, RTPROT_DHCP); + r = route_new(&route); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); - r = route_new_dynamic(&route_gw, RTPROT_DHCP); + route->protocol = RTPROT_DHCP; + + r = route_new(&route_gw); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); @@ -84,11 +87,12 @@ static int link_set_dhcp_routes(Link *link) { * route for the gw host so that we can route no matter the * netmask or existing kernel route tables. */ route_gw->family = AF_INET; - route_gw->dst_addr.in = gateway; + route_gw->dst.in = gateway; route_gw->dst_prefixlen = 32; - route_gw->prefsrc_addr.in = address; + route_gw->prefsrc.in = address; route_gw->scope = RT_SCOPE_LINK; - route_gw->metrics = link->network->dhcp_route_metric; + route_gw->protocol = RTPROT_DHCP; + route_gw->priority = link->network->dhcp_route_metric; r = route_configure(route_gw, link, &dhcp4_route_handler); if (r < 0) @@ -97,9 +101,9 @@ static int link_set_dhcp_routes(Link *link) { link->dhcp4_messages ++; route->family = AF_INET; - route->in_addr.in = gateway; - route->prefsrc_addr.in = address; - route->metrics = link->network->dhcp_route_metric; + route->gw.in = gateway; + route->prefsrc.in = address; + route->priority = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); if (r < 0) { @@ -120,15 +124,16 @@ static int link_set_dhcp_routes(Link *link) { for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; - r = route_new_dynamic(&route, RTPROT_DHCP); + r = route_new(&route); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); route->family = AF_INET; - route->in_addr.in = static_routes[i].gw_addr; - route->dst_addr.in = static_routes[i].dst_addr; + route->protocol = RTPROT_DHCP; + route->gw.in = static_routes[i].gw_addr; + route->dst.in = static_routes[i].dst_addr; route->dst_prefixlen = static_routes[i].dst_prefixlen; - route->metrics = link->network->dhcp_route_metric; + route->priority = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); if (r < 0) @@ -162,45 +167,45 @@ static int dhcp_lease_lost(Link *link) { for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; - r = route_new_dynamic(&route, RTPROT_UNSPEC); + r = route_new(&route); if (r >= 0) { route->family = AF_INET; - route->in_addr.in = routes[i].gw_addr; - route->dst_addr.in = routes[i].dst_addr; + route->gw.in = routes[i].gw_addr; + route->dst.in = routes[i].dst_addr; route->dst_prefixlen = routes[i].dst_prefixlen; - route_drop(route, link, - &link_route_drop_handler); + route_remove(route, link, + &link_route_remove_handler); } } } } - r = address_new_dynamic(&address); + r = address_new(&address); if (r >= 0) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r >= 0) { _cleanup_route_free_ Route *route_gw = NULL; _cleanup_route_free_ Route *route = NULL; - r = route_new_dynamic(&route_gw, RTPROT_UNSPEC); + r = route_new(&route_gw); if (r >= 0) { route_gw->family = AF_INET; - route_gw->dst_addr.in = gateway; + route_gw->dst.in = gateway; route_gw->dst_prefixlen = 32; route_gw->scope = RT_SCOPE_LINK; - route_drop(route_gw, link, - &link_route_drop_handler); + route_remove(route_gw, link, + &link_route_remove_handler); } - r = route_new_dynamic(&route, RTPROT_UNSPEC); + r = route_new(&route); if (r >= 0) { route->family = AF_INET; - route->in_addr.in = gateway; + route->gw.in = gateway; - route_drop(route, link, - &link_route_drop_handler); + route_remove(route, link, + &link_route_remove_handler); } } @@ -214,7 +219,7 @@ static int dhcp_lease_lost(Link *link) { address->in_addr.in = addr; address->prefixlen = prefixlen; - address_drop(address, link, &link_address_drop_handler); + address_remove(address, link, &link_address_remove_handler); } } @@ -267,7 +272,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, log_link_error_errno(link, r, "Could not set DHCPv4 address: %m"); link_enter_failed(link); } else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); link_set_dhcp_routes(link); @@ -288,7 +293,7 @@ static int dhcp4_update_address(Link *link, prefixlen = in_addr_netmask_to_prefixlen(netmask); - r = address_new_dynamic(&addr); + r = address_new(&addr); if (r < 0) return r; @@ -299,9 +304,9 @@ static int dhcp4_update_address(Link *link, addr->prefixlen = prefixlen; addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr; - /* use update rather than configure so that we will update the - * lifetime of an existing address if it has already been configured */ - r = address_update(addr, link, &dhcp4_address_handler); + /* allow reusing an existing address and simply update its lifetime + * in case it already exists */ + r = address_configure(addr, link, &dhcp4_address_handler, true); if (r < 0) return r; @@ -528,9 +533,11 @@ int dhcp4_configure(Link *link) { assert(link->network); assert(link->network->dhcp & ADDRESS_FAMILY_IPV4); - r = sd_dhcp_client_new(&link->dhcp_client); - if (r < 0) - return r; + if (!link->dhcp_client) { + r = sd_dhcp_client_new(&link->dhcp_client); + if (r < 0) + return r; + } r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0); if (r < 0) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 3cb7b8d9ca..d407b31b78 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -22,12 +22,11 @@ #include <netinet/ether.h> #include <linux/if.h> -#include "networkd-link.h" -#include "network-internal.h" - -#include "sd-icmp6-nd.h" #include "sd-dhcp6-client.h" +#include "network-internal.h" +#include "networkd-link.h" + static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link); static int dhcp6_lease_information_acquired(sd_dhcp6_client *client, @@ -58,18 +57,17 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, link_enter_failed(link); } else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); return 1; } -static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr, - uint8_t prefixlen, uint32_t lifetime_preferred, - uint32_t lifetime_valid) { +static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr, + uint32_t lifetime_preferred, uint32_t lifetime_valid) { int r; _cleanup_address_free_ Address *addr = NULL; - r = address_new_dynamic(&addr); + r = address_new(&addr); if (r < 0) return r; @@ -77,17 +75,17 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr, memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr)); addr->flags = IFA_F_NOPREFIXROUTE; - addr->prefixlen = prefixlen; + addr->prefixlen = 128; addr->cinfo.ifa_prefered = lifetime_preferred; addr->cinfo.ifa_valid = lifetime_valid; log_link_info(link, - "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6), + "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", + SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6), addr->prefixlen, lifetime_preferred, lifetime_valid); - r = address_update(addr, link, dhcp6_address_handler); + r = address_configure(addr, link, dhcp6_address_handler, true); if (r < 0) log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m"); @@ -99,7 +97,6 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { sd_dhcp6_lease *lease; struct in6_addr ip6_addr; uint32_t lifetime_preferred, lifetime_valid; - uint8_t prefixlen; r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) @@ -111,18 +108,7 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { &lifetime_preferred, &lifetime_valid) >= 0) { - r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery, - &ip6_addr, &prefixlen); - if (r < 0 && r != -EADDRNOTAVAIL) { - log_link_warning_errno(link, r, "Could not get prefix information: %m"); - return r; - } - - if (r == -EADDRNOTAVAIL) - prefixlen = 128; - - r = dhcp6_address_update(link, &ip6_addr, prefixlen, - lifetime_preferred, lifetime_valid); + r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid); if (r < 0) return r; } @@ -145,7 +131,8 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { case SD_DHCP6_CLIENT_EVENT_STOP: case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: - log_link_warning(link, "DHCPv6 lease lost"); + if (sd_dhcp6_client_get_lease(client, NULL) >= 0) + log_link_warning(link, "DHCPv6 lease lost"); link->dhcp6_configured = false; break; @@ -176,197 +163,85 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { return; } - link_client_handler(link); + link_check_ready(link); } -static int dhcp6_configure(Link *link, int event) { - int r; - bool information_request; - - assert_return(link, -EINVAL); - assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL); - - link->dhcp6_configured = false; - - if (link->dhcp6_client) { - r = sd_dhcp6_client_get_information_request(link->dhcp6_client, - &information_request); - if (r < 0) { - log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m"); - goto error; - } - - if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) { - r = sd_dhcp6_client_stop(link->dhcp6_client); - if (r < 0) { - log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m"); - goto error; - } - - r = sd_dhcp6_client_set_information_request(link->dhcp6_client, - false); - if (r < 0) { - log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m"); - goto error; - } - - } - - r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0 && r != -EALREADY) { - log_link_warning_errno(link, r, "Could not restart DHCPv6: %m"); - goto error; - } - - if (r == -EALREADY) - link->dhcp6_configured = true; - - return r; - } - - r = sd_dhcp6_client_new(&link->dhcp6_client); - if (r < 0) - goto error; +int dhcp6_request_address(Link *link) { + int r, inf_req; + bool running; - r = sd_dhcp6_client_attach_event(link->dhcp6_client, NULL, 0); - if (r < 0) - goto error; + assert(link); + assert(link->dhcp6_client); - r = sd_dhcp6_client_set_mac(link->dhcp6_client, - (const uint8_t *) &link->mac, - sizeof (link->mac), ARPHRD_ETHER); + r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &inf_req); if (r < 0) - goto error; + return r; - r = sd_dhcp6_client_set_index(link->dhcp6_client, link->ifindex); - if (r < 0) - goto error; + if (!inf_req) + return 0; - r = sd_dhcp6_client_set_callback(link->dhcp6_client, dhcp6_handler, - link); + r = sd_dhcp6_client_is_running(link->dhcp6_client); if (r < 0) - goto error; + return r; + else + running = !!r; - if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) { - r = sd_dhcp6_client_set_information_request(link->dhcp6_client, - true); + if (running) { + r = sd_dhcp6_client_stop(link->dhcp6_client); if (r < 0) - goto error; + return r; } - r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0) - goto error; - - return r; - - error: - link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); - return r; -} - -static int dhcp6_prefix_expired(Link *link) { - int r; - sd_dhcp6_lease *lease; - struct in6_addr *expired_prefix, ip6_addr; - uint8_t expired_prefixlen; - uint32_t lifetime_preferred, lifetime_valid; - - r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery, - &expired_prefix, &expired_prefixlen); + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false); if (r < 0) return r; - r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease); - if (r < 0) - return r; - - log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix), - expired_prefixlen); - - sd_dhcp6_lease_reset_address_iter(lease); - - while (sd_dhcp6_lease_get_address(lease, &ip6_addr, - &lifetime_preferred, - &lifetime_valid) >= 0) { - - r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen, - &ip6_addr); + if (running) { + r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0) - continue; - - log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128); - - dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid); + return r; } return 0; } -static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) { - Link *link = userdata; +int dhcp6_configure(Link *link) { + sd_dhcp6_client *client = NULL; + int r; assert(link); - assert(link->network); - assert(link->manager); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return; - - switch(event) { - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE: - return; - - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT: - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER: - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED: - dhcp6_configure(link, event); - - break; - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED: - if (!link->rtnl_extended_attrs) - dhcp6_prefix_expired(link); - - break; - - default: - if (event < 0) - log_link_warning_errno(link, event, "ICMPv6 error: %m"); - else - log_link_warning(link, "ICMPv6 unknown event: %d", event); - - break; - } - -} - -int icmp6_configure(Link *link) { - int r; + r = sd_dhcp6_client_new(&client); + if (r < 0) + return r; - assert_return(link, -EINVAL); + r = sd_dhcp6_client_attach_event(client, NULL, 0); + if (r < 0) + goto error; - r = sd_icmp6_nd_new(&link->icmp6_router_discovery); + r = sd_dhcp6_client_set_information_request(client, true); if (r < 0) return r; - r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, NULL, 0); + r = sd_dhcp6_client_set_mac(client, + (const uint8_t *) &link->mac, + sizeof (link->mac), ARPHRD_ETHER); if (r < 0) - return r; + goto error; - r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, &link->mac); + r = sd_dhcp6_client_set_index(client, link->ifindex); if (r < 0) - return r; + goto error; - r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, link->ifindex); + r = sd_dhcp6_client_set_callback(client, dhcp6_handler, link); if (r < 0) - return r; + goto error; + + link->dhcp6_client = client; - r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery, - icmp6_router_handler, link); + return 0; +error: + sd_dhcp6_client_unref(client); return r; } diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 9cb63cb79f..c9222b8cb8 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -22,12 +22,12 @@ #include <net/if.h> #include <net/ethernet.h> +#include "alloc-util.h" #include "conf-parser.h" -#include "util.h" #include "netlink-util.h" - -#include "networkd.h" #include "networkd-fdb.h" +#include "networkd.h" +#include "util.h" /* create a new FDB entry or get an existing one. */ int fdb_entry_new_static(Network *const network, diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 1902b3d23a..ed0d861e7a 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -42,7 +42,7 @@ static int ipv4ll_address_lost(Link *link) { log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr)); - r = address_new_dynamic(&address); + r = address_new(&address); if (r < 0) { log_link_error_errno(link, r, "Could not allocate address: %m"); return r; @@ -53,9 +53,9 @@ static int ipv4ll_address_lost(Link *link) { address->prefixlen = 16; address->scope = RT_SCOPE_LINK; - address_drop(address, link, &link_address_drop_handler); + address_remove(address, link, &link_address_remove_handler); - r = route_new_dynamic(&route, RTPROT_UNSPEC); + r = route_new(&route); if (r < 0) { log_link_error_errno(link, r, "Could not allocate route: %m"); return r; @@ -63,11 +63,11 @@ static int ipv4ll_address_lost(Link *link) { route->family = AF_INET; route->scope = RT_SCOPE_LINK; - route->metrics = IPV4LL_ROUTE_METRIC; + route->priority = IPV4LL_ROUTE_METRIC; - route_drop(route, link, &link_route_drop_handler); + route_remove(route, link, &link_route_remove_handler); - link_client_handler(link); + link_check_ready(link); return 0; } @@ -88,7 +88,7 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u link->ipv4ll_route = true; if (link->ipv4ll_address == true) - link_client_handler(link); + link_check_ready(link); return 1; } @@ -105,12 +105,12 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void log_link_error_errno(link, r, "could not set ipv4ll address: %m"); link_enter_failed(link); } else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); link->ipv4ll_address = true; if (link->ipv4ll_route == true) - link_client_handler(link); + link_check_ready(link); return 1; } @@ -133,7 +133,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u", ADDRESS_FMT_VAL(address)); - r = address_new_dynamic(&ll_addr); + r = address_new(&ll_addr); if (r < 0) return r; @@ -143,19 +143,20 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen); ll_addr->scope = RT_SCOPE_LINK; - r = address_configure(ll_addr, link, ipv4ll_address_handler); + r = address_configure(ll_addr, link, ipv4ll_address_handler, false); if (r < 0) return r; link->ipv4ll_address = false; - r = route_new_dynamic(&route, RTPROT_STATIC); + r = route_new(&route); if (r < 0) return r; route->family = AF_INET; route->scope = RT_SCOPE_LINK; - route->metrics = IPV4LL_ROUTE_METRIC; + route->protocol = RTPROT_STATIC; + route->priority = IPV4LL_ROUTE_METRIC; r = route_configure(route, link, ipv4ll_route_handler); if (r < 0) @@ -207,9 +208,11 @@ int ipv4ll_configure(Link *link) { assert(link->network); assert(link->network->link_local & ADDRESS_FAMILY_IPV4); - r = sd_ipv4ll_new(&link->ipv4ll); - if (r < 0) - return r; + if (!link->ipv4ll) { + r = sd_ipv4ll_new(&link->ipv4ll); + if (r < 0) + return r; + } if (link->udev_device) { r = net_get_unique_predictable_data(link->udev_device, seed); diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 1a1524dfb4..11b35d6cf8 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -22,8 +22,10 @@ #include "bus-util.h" #include "strv.h" -#include "networkd.h" +#include "alloc-util.h" #include "networkd-link.h" +#include "networkd.h" +#include "parse-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState); @@ -101,7 +103,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void if (r < 0) return 0; - r = safe_atoi(identifier, &ifindex); + r = parse_ifindex(identifier, &ifindex); if (r < 0) return 0; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index ffc9578e86..a415035887 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -23,18 +23,23 @@ #include <linux/if.h> #include <unistd.h> -#include "util.h" -#include "virt.h" -#include "fileio.h" -#include "socket-util.h" +#include "alloc-util.h" #include "bus-util.h" -#include "udev-util.h" -#include "netlink-util.h" #include "dhcp-lease-internal.h" +#include "event-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "netlink-util.h" #include "network-internal.h" - #include "networkd-link.h" #include "networkd-netdev.h" +#include "set.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "udev-util.h" +#include "util.h" +#include "virt.h" bool link_dhcp6_enabled(Link *link) { if (link->flags & IFF_LOOPBACK) @@ -106,20 +111,56 @@ static bool link_ipv4_forward_enabled(Link *link) { if (!link->network) return false; + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + return false; + return link->network->ip_forward & ADDRESS_FAMILY_IPV4; } static bool link_ipv6_forward_enabled(Link *link) { + + if (!socket_ipv6_is_supported()) + return false; + if (link->flags & IFF_LOOPBACK) return false; if (!link->network) return false; + if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + return false; + return link->network->ip_forward & ADDRESS_FAMILY_IPV6; } +bool link_ipv6_accept_ra_enabled(Link *link) { + if (link->flags & IFF_LOOPBACK) + return false; + + if (!link->network) + return false; + + /* If unset use system default (enabled if local forwarding is disabled. + * disabled if local forwarding is enabled). + * If set, ignore or enforce RA independent of local forwarding state. + */ + if (link->network->ipv6_accept_ra < 0) + /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */ + return !link_ipv6_forward_enabled(link); + else if (link->network->ipv6_accept_ra > 0) + /* accept RA even if ip_forward is enabled */ + return true; + else + /* ignore RA */ + return false; +} + static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) { + + if (!socket_ipv6_is_supported()) + return _IPV6_PRIVACY_EXTENSIONS_INVALID; + if (link->flags & IFF_LOOPBACK) return _IPV6_PRIVACY_EXTENSIONS_INVALID; @@ -129,6 +170,57 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) { return link->network->ipv6_privacy_extensions; } +void link_update_operstate(Link *link) { + LinkOperationalState operstate; + assert(link); + + if (link->kernel_operstate == IF_OPER_DORMANT) + operstate = LINK_OPERSTATE_DORMANT; + else if (link_has_carrier(link)) { + Address *address; + uint8_t scope = RT_SCOPE_NOWHERE; + Iterator i; + + /* if we have carrier, check what addresses we have */ + SET_FOREACH(address, link->addresses, i) { + if (!address_is_ready(address)) + continue; + + if (address->scope < scope) + scope = address->scope; + } + + /* for operstate we also take foreign addresses into account */ + SET_FOREACH(address, link->addresses_foreign, i) { + if (!address_is_ready(address)) + continue; + + if (address->scope < scope) + scope = address->scope; + } + + if (scope < RT_SCOPE_SITE) + /* universally accessible addresses found */ + operstate = LINK_OPERSTATE_ROUTABLE; + else if (scope < RT_SCOPE_HOST) + /* only link or site local addresses found */ + operstate = LINK_OPERSTATE_DEGRADED; + else + /* no useful addresses found */ + operstate = LINK_OPERSTATE_CARRIER; + } else if (link->flags & IFF_UP) + operstate = LINK_OPERSTATE_NO_CARRIER; + else + operstate = LINK_OPERSTATE_OFF; + + if (link->operstate != operstate) { + link->operstate = operstate; + link_send_changed(link, "OperationalState", NULL); + link_dirty(link); + manager_dirty(link->manager); + } +} + #define FLAG_STRING(string, flag, old, new) \ (((old ^ new) & flag) \ ? ((old & flag) ? (" -" string) : (" +" string)) \ @@ -201,7 +293,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) { link->flags = flags; link->kernel_operstate = operstate; - link_save(link); + link_update_operstate(link); return 0; } @@ -291,10 +383,15 @@ static void link_free(Link *link) { if (!link) return; - while ((address = link->addresses)) { - LIST_REMOVE(addresses, link->addresses, address); - address_free(address); - } + while (!set_isempty(link->addresses)) + address_free(set_first(link->addresses)); + + while (!set_isempty(link->addresses_foreign)) + address_free(set_first(link->addresses_foreign)); + + link->addresses = set_free(link->addresses); + + link->addresses_foreign = set_free(link->addresses_foreign); while ((address = link->pool_addresses)) { LIST_REMOVE(addresses, link->pool_addresses, address); @@ -313,13 +410,14 @@ static void link_free(Link *link) { sd_ipv4ll_unref(link->ipv4ll); sd_dhcp6_client_unref(link->dhcp6_client); - sd_icmp6_nd_unref(link->icmp6_router_discovery); + sd_ndisc_unref(link->ndisc_router_discovery); if (link->manager) hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)); free(link->ifname); + (void)unlink(link->state_file); free(link->state_file); udev_device_unref(link->udev_device); @@ -336,15 +434,28 @@ static void link_free(Link *link) { } Link *link_unref(Link *link) { - if (link && (-- link->n_ref <= 0)) - link_free(link); + if (!link) + return NULL; + + assert(link->n_ref > 0); + + link->n_ref --; + + if (link->n_ref > 0) + return NULL; + + link_free(link); return NULL; } Link *link_ref(Link *link) { - if (link) - assert_se(++ link->n_ref >= 2); + if (!link) + return NULL; + + assert(link->n_ref > 0); + + link->n_ref ++; return link; } @@ -385,7 +496,7 @@ static void link_enter_unmanaged(Link *link) { link_set_state(link, LINK_STATE_UNMANAGED); - link_save(link); + link_dirty(link); } static int link_stop_clients(Link *link) { @@ -395,9 +506,6 @@ static int link_stop_clients(Link *link) { assert(link->manager); assert(link->manager->event); - if (!link->network) - return 0; - if (link->dhcp_client) { k = sd_dhcp_client_stop(link->dhcp_client); if (k < 0) @@ -410,16 +518,16 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m"); } - if(link->icmp6_router_discovery) { - if (link->dhcp6_client) { - k = sd_dhcp6_client_stop(link->dhcp6_client); - if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m"); - } + if (link->dhcp6_client) { + k = sd_dhcp6_client_stop(link->dhcp6_client); + if (k < 0) + r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m"); + } - k = sd_icmp6_nd_stop(link->icmp6_router_discovery); + if (link->ndisc_router_discovery) { + k = sd_ndisc_stop(link->ndisc_router_discovery); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop ICMPv6 router discovery: %m"); + r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m"); } if (link->lldp) { @@ -443,7 +551,7 @@ void link_enter_failed(Link *link) { link_stop_clients(link); - link_save(link); + link_dirty(link); } static Address* link_find_dhcp_server_address(Link *link) { @@ -484,14 +592,19 @@ static int link_enter_configured(Link *link) { link_set_state(link, LINK_STATE_CONFIGURED); - link_save(link); + link_dirty(link); return 0; } -void link_client_handler(Link *link) { +void link_check_ready(Link *link) { + Address *a; + Iterator i; + assert(link); - assert(link->network); + + if (!link->network) + return; if (!link->static_configured) return; @@ -501,6 +614,10 @@ void link_client_handler(Link *link) { !link->ipv4ll_route) return; + if (link_ipv6ll_enabled(link)) + if (!link->ipv6ll_address) + return; + if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && !link->dhcp4_configured) || (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && @@ -509,6 +626,13 @@ void link_client_handler(Link *link) { !link->dhcp4_configured && !link->dhcp6_configured)) return; + if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured) + return; + + SET_FOREACH(a, link->addresses, i) + if (!address_is_ready(a)) + return; + if (link->state != LINK_STATE_CONFIGURED) link_enter_configured(link); @@ -531,12 +655,12 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) - log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not set route: %m"); if (link->link_messages == 0) { log_link_debug(link, "Routes set"); link->static_configured = true; - link_client_handler(link); + link_check_ready(link); } return 1; @@ -565,14 +689,14 @@ static int link_enter_set_routes(Link *link) { if (link->link_messages == 0) { link->static_configured = true; - link_client_handler(link); + link_check_ready(link); } else log_link_debug(link, "Setting routes"); return 0; } -int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { +int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -585,7 +709,7 @@ int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd r = sd_netlink_message_get_errno(m); if (r < 0 && r != -ESRCH) - log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not drop route: %m"); return 1; } @@ -609,9 +733,9 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) - log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "could not set address: %m"); else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); if (link->link_messages == 0) { log_link_debug(link, "Addresses set"); @@ -722,7 +846,7 @@ static int link_enter_set_addresses(Link *link) { link_set_state(link, LINK_STATE_SETTING_ADDRESSES); LIST_FOREACH(addresses, ad, link->network->static_addresses) { - r = address_configure(ad, link, &address_handler); + r = address_configure(ad, link, &address_handler, false); if (r < 0) { log_link_warning_errno(link, r, "Could not set addresses: %m"); link_enter_failed(link); @@ -854,7 +978,7 @@ static int link_enter_set_addresses(Link *link) { return 0; } -int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { +int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -867,7 +991,7 @@ int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *use r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EADDRNOTAVAIL) - log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not drop address: %m"); return 1; } @@ -1019,7 +1143,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda r = sd_netlink_message_get_errno(m); if (r < 0) - log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not set MTU: %m"); return 1; } @@ -1129,6 +1253,34 @@ static void lldp_handler(sd_lldp *lldp, int event, void *userdata) { } } +static int link_acquire_ipv6_conf(Link *link) { + int r; + + assert(link); + + if (link_dhcp6_enabled(link)) { + assert(link->dhcp6_client); + + log_link_debug(link, "Acquiring DHCPv6 lease"); + + r = sd_dhcp6_client_start(link->dhcp6_client); + if (r < 0) + return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m"); + } + + if (link_ipv6_accept_ra_enabled(link)) { + assert(link->ndisc_router_discovery); + + log_link_debug(link, "Discovering IPv6 routers"); + + r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery); + if (r < 0) + return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m"); + } + + return 0; +} + static int link_acquire_conf(Link *link) { int r; @@ -1157,16 +1309,6 @@ static int link_acquire_conf(Link *link) { return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); } - if (link_dhcp6_enabled(link)) { - assert(link->icmp6_router_discovery); - - log_link_debug(link, "Discovering IPv6 routers"); - - r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery); - if (r < 0) - return log_link_warning_errno(link, r, "Could not start IPv6 router discovery: %m"); - } - if (link_lldp_enabled(link)) { assert(link->lldp); @@ -1207,7 +1349,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda if (r < 0) /* we warn but don't fail the link, as it may be brought up later */ - log_link_warning_errno(link, r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not bring up interface: %m"); return 1; } @@ -1294,7 +1436,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user r = sd_netlink_message_get_errno(m); if (r < 0) - log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not bring down interface: %m"); return 1; } @@ -1432,14 +1574,14 @@ static int link_new_bound_by_list(Link *link) { } if (list_updated) - link_save(link); + link_dirty(link); HASHMAP_FOREACH (carrier, link->bound_by_links, i) { r = link_put_carrier(carrier, link, &carrier->bound_to_links); if (r < 0) return r; - link_save(carrier); + link_dirty(carrier); } return 0; @@ -1474,14 +1616,14 @@ static int link_new_bound_to_list(Link *link) { } if (list_updated) - link_save(link); + link_dirty(link); HASHMAP_FOREACH (carrier, link->bound_to_links, i) { r = link_put_carrier(carrier, link, &carrier->bound_by_links); if (r < 0) return r; - link_save(carrier); + link_dirty(carrier); } return 0; @@ -1517,7 +1659,7 @@ static void link_free_bound_to_list(Link *link) { hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex)); if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex))) - link_save(bound_to); + link_dirty(bound_to); } return; @@ -1531,7 +1673,7 @@ static void link_free_bound_by_list(Link *link) { hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex)); if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) { - link_save(bound_by); + link_dirty(bound_by); link_handle_bound_to_list(bound_by); } } @@ -1555,7 +1697,7 @@ static void link_free_carrier_maps(Link *link) { } if (list_updated) - link_save(link); + link_dirty(link); return; } @@ -1570,6 +1712,7 @@ void link_drop(Link *link) { log_link_debug(link, "Link removed"); + (void)unlink(link->state_file); link_unref(link); return; @@ -1616,7 +1759,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname); + log_link_error_errno(link, r, "Could not join netdev: %m"); link_enter_failed(link); return 1; } else @@ -1639,7 +1782,7 @@ static int link_enter_join_netdev(Link *link) { link_set_state(link, LINK_STATE_ENSLAVING); - link_save(link); + link_dirty(link); if (!link->network->bridge && !link->network->bond && @@ -1715,32 +1858,69 @@ static int link_enter_join_netdev(Link *link) { } static int link_set_ipv4_forward(Link *link) { - const char *p = NULL, *v; int r; - if (link->flags & IFF_LOOPBACK) + if (!link_ipv4_forward_enabled(link)) return 0; - if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + /* We propagate the forwarding flag from one interface to the + * global setting one way. This means: as long as at least one + * interface was configured at any time that had IP forwarding + * enabled the setting will stay on for good. We do this + * primarily to keep IPv4 and IPv6 packet forwarding behaviour + * somewhat in sync (see below). */ + + r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m"); + + return 0; +} + +static int link_set_ipv6_forward(Link *link) { + int r; + + if (!link_ipv6_forward_enabled(link)) return 0; - p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/forwarding"); - v = one_zero(link_ipv4_forward_enabled(link)); + /* On Linux, the IPv6 stack does not not know a per-interface + * packet forwarding setting: either packet forwarding is on + * for all, or off for all. We hence don't bother with a + * per-interface setting, but simply propagate the interface + * flag, if it is set, to the global flag, one-way. Note that + * while IPv4 would allow a per-interface flag, we expose the + * same behaviour there and also propagate the setting from + * one to all, to keep things simple (see above). */ - r = write_string_file(p, v, 0); - if (r < 0) { - /* If the right value is set anyway, don't complain */ - if (verify_one_line_file(p, v) > 0) - return 0; + r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m"); - log_link_warning_errno(link, r, "Cannot configure IPv4 forwarding for interface %s: %m", link->ifname); - } + return 0; +} + +static int link_set_ipv6_privacy_extensions(Link *link) { + char buf[DECIMAL_STR_MAX(unsigned) + 1]; + IPv6PrivacyExtensions s; + const char *p = NULL; + int r; + + s = link_ipv6_privacy_extensions(link); + if (s < 0) + return 0; + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr"); + xsprintf(buf, "%u", (unsigned) link->network->ipv6_privacy_extensions); + + r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m"); return 0; } -static int link_set_ipv6_forward(Link *link) { - const char *p = NULL, *v = NULL; +static int link_set_ipv6_accept_ra(Link *link) { + const char *p = NULL; int r; /* Make this a NOP if IPv6 is not available */ @@ -1750,27 +1930,21 @@ static int link_set_ipv6_forward(Link *link) { if (link->flags & IFF_LOOPBACK) return 0; - if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID) + if (!link->network) return 0; - p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/forwarding"); - v = one_zero(link_ipv6_forward_enabled(link)); - - r = write_string_file(p, v, 0); - if (r < 0) { - /* If the right value is set anyway, don't complain */ - if (verify_one_line_file(p, v) > 0) - return 0; + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra"); - log_link_warning_errno(link, r, "Cannot configure IPv6 forwarding for interface: %m"); - } + /* We handle router advertisments ourselves, tell the kernel to GTFO */ + r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m"); return 0; } -static int link_set_ipv6_privacy_extensions(Link *link) { - char buf[DECIMAL_STR_MAX(unsigned) + 1]; - IPv6PrivacyExtensions s; +static int link_set_ipv6_dad_transmits(Link *link) { + char buf[DECIMAL_STR_MAX(int) + 1]; const char *p = NULL; int r; @@ -1778,27 +1952,28 @@ static int link_set_ipv6_privacy_extensions(Link *link) { if (!socket_ipv6_is_supported()) return 0; - s = link_ipv6_privacy_extensions(link); - if (s == _IPV6_PRIVACY_EXTENSIONS_INVALID) + if (link->flags & IFF_LOOPBACK) return 0; - p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr"); - xsprintf(buf, "%u", link->network->ipv6_privacy_extensions); + if (!link->network) + return 0; - r = write_string_file(p, buf, 0); - if (r < 0) { - /* If the right value is set anyway, don't complain */ - if (verify_one_line_file(p, buf) > 0) - return 0; + if (link->network->ipv6_dad_transmits < 0) + return 0; - log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m"); - } + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits"); + xsprintf(buf, "%i", link->network->ipv6_dad_transmits); + + r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m"); return 0; } -static int link_set_ipv6_accept_ra(Link *link) { - const char *p = NULL, *v = NULL; +static int link_set_ipv6_hop_limit(Link *link) { + char buf[DECIMAL_STR_MAX(int) + 1]; + const char *p = NULL; int r; /* Make this a NOP if IPv6 is not available */ @@ -1808,29 +1983,46 @@ static int link_set_ipv6_accept_ra(Link *link) { if (link->flags & IFF_LOOPBACK) return 0; - /* If unset use system default (enabled if local forwarding is disabled. - * disabled if local forwarding is enabled). - * If set, ignore or enforce RA independent of local forwarding state. - */ - if (link->network->ipv6_accept_ra < 0) { - /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */ - v = "1"; - } else if (link->network->ipv6_accept_ra > 0) { - /* "2" means accept RA even if ip_forward is enabled */ - v = "2"; - } else { - /* "0" means ignore RA */ - v = "0"; + if (!link->network) + return 0; + + if (link->network->ipv6_hop_limit < 0) + return 0; + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/hop_limit"); + xsprintf(buf, "%i", link->network->ipv6_hop_limit); + + r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE); + if (r < 0) + log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m"); + + return 0; +} + +static int link_drop_foreign_config(Link *link) { + Address *address; + Route *route; + Iterator i; + int r; + + SET_FOREACH(address, link->addresses_foreign, i) { + /* we consider IPv6LL addresses to be managed by the kernel */ + if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) == 1) + continue; + + r = address_remove(address, link, link_address_remove_handler); + if (r < 0) + return r; } - p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra"); - r = write_string_file(p, v, 0); - if (r < 0) { - /* If the right value is set anyway, don't complain */ - if (verify_one_line_file(p, v) > 0) - return 0; + SET_FOREACH(route, link->routes_foreign, i) { + /* do not touch routes managed by the kernel */ + if (route->protocol == RTPROT_KERNEL) + continue; - log_link_warning_errno(link, r, "Cannot configure IPv6 accept_ra for interface: %m"); + r = route_remove(route, link, link_address_remove_handler); + if (r < 0) + return r; } return 0; @@ -1843,6 +2035,10 @@ static int link_configure(Link *link) { assert(link->network); assert(link->state == LINK_STATE_PENDING); + r = link_drop_foreign_config(link); + if (r < 0) + return r; + r = link_set_bridge_fdb(link); if (r < 0) return r; @@ -1863,6 +2059,14 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = link_set_ipv6_dad_transmits(link); + if (r < 0) + return r; + + r = link_set_ipv6_hop_limit(link); + if (r < 0) + return r; + if (link_ipv4ll_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) @@ -1886,7 +2090,13 @@ static int link_configure(Link *link) { } if (link_dhcp6_enabled(link)) { - r = icmp6_configure(link); + r = dhcp6_configure(link); + if (r < 0) + return r; + } + + if (link_ipv6_accept_ra_enabled(link)) { + r = ndisc_configure(link); if (r < 0) return r; } @@ -1910,6 +2120,12 @@ static int link_configure(Link *link) { r = link_acquire_conf(link); if (r < 0) return r; + + if (link->ipv6ll_address) { + r = link_acquire_ipv6_conf(link); + if (r < 0) + return r; + } } return link_enter_join_netdev(link); @@ -1938,28 +2154,30 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m, if (r < 0) return r; - r = network_get(link->manager, link->udev_device, link->ifname, - &link->mac, &network); - if (r == -ENOENT) { - link_enter_unmanaged(link); - return 1; - } else if (r < 0) - return r; + if (!link->network) { + r = network_get(link->manager, link->udev_device, link->ifname, + &link->mac, &network); + if (r == -ENOENT) { + link_enter_unmanaged(link); + return 1; + } else if (r < 0) + return r; - if (link->flags & IFF_LOOPBACK) { - if (network->link_local != ADDRESS_FAMILY_NO) - log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link"); + if (link->flags & IFF_LOOPBACK) { + if (network->link_local != ADDRESS_FAMILY_NO) + log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link"); - if (network->dhcp != ADDRESS_FAMILY_NO) - log_link_debug(link, "Ignoring DHCP clients for loopback link"); + if (network->dhcp != ADDRESS_FAMILY_NO) + log_link_debug(link, "Ignoring DHCP clients for loopback link"); - if (network->dhcp_server) - log_link_debug(link, "Ignoring DHCP server for loopback link"); - } + if (network->dhcp_server) + log_link_debug(link, "Ignoring DHCP server for loopback link"); + } - r = network_apply(link->manager, network, link); - if (r < 0) - return r; + r = network_apply(link->manager, network, link); + if (r < 0) + return r; + } r = link_new_bound_to_list(link); if (r < 0) @@ -2011,177 +2229,191 @@ int link_initialized(Link *link, struct udev_device *device) { return 0; } -static Address* link_get_equal_address(Link *link, Address *needle) { - Address *i; +static int link_load(Link *link) { + _cleanup_free_ char *network_file = NULL, + *addresses = NULL, + *routes = NULL, + *dhcp4_address = NULL, + *ipv4ll_address = NULL; + union in_addr_union address; + union in_addr_union route_dst; + const char *p; + int r; assert(link); - assert(needle); - - LIST_FOREACH(addresses, i, link->addresses) - if (address_equal(i, needle)) - return i; - return NULL; -} - -int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { - Manager *m = userdata; - Link *link = NULL; - uint16_t type; - _cleanup_address_free_ Address *address = NULL; - unsigned char flags; - Address *existing; - char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX]; - const char *valid_str = NULL; - int r, ifindex; + r = parse_env_file(link->state_file, NEWLINE, + "NETWORK_FILE", &network_file, + "ADDRESSES", &addresses, + "ROUTES", &routes, + "DHCP4_ADDRESS", &dhcp4_address, + "IPV4LL_ADDRESS", &ipv4ll_address, + NULL); + if (r < 0 && r != -ENOENT) + return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file); + + if (network_file) { + Network *network; + char *suffix; + + /* drop suffix */ + suffix = strrchr(network_file, '.'); + if (!suffix) { + log_link_debug(link, "Failed to get network name from %s", network_file); + goto network_file_fail; + } + *suffix = '\0'; - assert(rtnl); - assert(message); - assert(m); + r = network_get_by_name(link->manager, basename(network_file), &network); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file)); + goto network_file_fail; + } - if (sd_netlink_message_is_error(message)) { - r = sd_netlink_message_get_errno(message); + r = network_apply(link->manager, network, link); if (r < 0) - log_warning_errno(r, "rtnl: failed to receive address: %m"); - - return 0; + return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file)); } - r = sd_netlink_message_get_type(message, &type); - if (r < 0) { - log_warning_errno(r, "rtnl: could not get message type: %m"); - return 0; - } else if (type != RTM_NEWADDR && type != RTM_DELADDR) { - log_warning("rtnl: received unexpected message type when processing address"); - return 0; - } - - r = sd_rtnl_message_addr_get_ifindex(message, &ifindex); - if (r < 0) { - log_warning_errno(r, "rtnl: could not get ifindex from address: %m"); - return 0; - } else if (ifindex <= 0) { - log_warning("rtnl: received address message with invalid ifindex: %d", ifindex); - return 0; - } else { - r = link_get(m, ifindex, &link); - if (r < 0 || !link) { - /* when enumerating we might be out of sync, but we will - * get the address again, so just ignore it */ - if (!m->enumerating) - log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex); - return 0; - } - } +network_file_fail: - r = address_new_dynamic(&address); - if (r < 0) - return r; + if (addresses) { + p = addresses; - r = sd_rtnl_message_addr_get_family(message, &address->family); - if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) { - log_link_warning(link, "rtnl: received address with invalid family, ignoring."); - return 0; - } + for (;;) { + _cleanup_free_ char *address_str = NULL; + char *prefixlen_str; + int family; + unsigned char prefixlen; - r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m"); - return 0; - } + r = extract_first_word(&p, &address_str, NULL, 0); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to extract next address string: %m"); + continue; + } if (r == 0) + break; - r = sd_rtnl_message_addr_get_scope(message, &address->scope); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m"); - return 0; - } + prefixlen_str = strchr(address_str, '/'); + if (!prefixlen_str) { + log_link_debug(link, "Failed to parse address and prefix length %s", address_str); + continue; + } - r = sd_rtnl_message_addr_get_flags(message, &flags); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m"); - return 0; - } - address->flags = flags; + *prefixlen_str ++ = '\0'; - switch (address->family) { - case AF_INET: - r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); - return 0; - } + r = sscanf(prefixlen_str, "%hhu", &prefixlen); + if (r != 1) { + log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str); + continue; + } - break; + r = in_addr_from_string_auto(address_str, &family, &address); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str); + continue; + } - case AF_INET6: - r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); - return 0; + r = address_add(link, family, &address, prefixlen, NULL); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add address: %m"); } - - break; - - default: - assert_not_reached("invalid address family"); } - if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) { - log_link_warning(link, "Could not print address"); - return 0; - } + if (routes) { + for (;;) { + Route *route; + _cleanup_free_ char *route_str = NULL; + _cleanup_event_source_unref_ sd_event_source *expire = NULL; + usec_t lifetime; + char *prefixlen_str; + int family; + unsigned char prefixlen, tos, table; + uint32_t priority; - r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo); - if (r >= 0) { - if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME) - valid_str = "ever"; - else - valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, - address->cinfo.ifa_valid * USEC_PER_SEC, - USEC_PER_SEC); - } + r = extract_first_word(&p, &route_str, NULL, 0); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to extract next route string: %m"); + continue; + } if (r == 0) + break; - existing = link_get_equal_address(link, address); + prefixlen_str = strchr(route_str, '/'); + if (!prefixlen_str) { + log_link_debug(link, "Failed to parse route %s", route_str); + continue; + } - switch (type) { - case RTM_NEWADDR: - if (existing) { - log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); + *prefixlen_str ++ = '\0'; + r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime); + if (r != 5) { + log_link_debug(link, + "Failed to parse destination prefix length, tos, priority, table or expiration %s", + prefixlen_str); + continue; + } - existing->scope = address->scope; - existing->flags = address->flags; - existing->cinfo = address->cinfo; + r = in_addr_from_string_auto(route_str, &family, &route_dst); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str); + continue; + } - } else { - log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); + r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add route: %m"); - LIST_PREPEND(addresses, link->addresses, address); - address_establish(address, link); + if (lifetime != USEC_INFINITY) { + r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime, + 0, route_expire_handler, route); + if (r < 0) + log_link_warning_errno(link, r, "Could not arm route expiration handler: %m"); + } - address = NULL; + route->lifetime = lifetime; + sd_event_source_unref(route->expire); + route->expire = expire; + expire = NULL; + } + } - link_save(link); + if (dhcp4_address) { + r = in_addr_from_string(AF_INET, dhcp4_address, &address); + if (r < 0) { + log_link_debug_errno(link, r, "Falied to parse DHCPv4 address %s: %m", dhcp4_address); + goto dhcp4_address_fail; } - break; + r = sd_dhcp_client_new(&link->dhcp_client); + if (r < 0) + return log_link_error_errno(link, r, "Falied to create DHCPv4 client: %m"); - case RTM_DELADDR: + r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in); + if (r < 0) + return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address); + } - if (existing) { - log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); - address_release(existing, link); - LIST_REMOVE(addresses, link->addresses, existing); - address_free(existing); - } else - log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); +dhcp4_address_fail: - break; - default: - assert_not_reached("Received invalid RTNL message type"); + if (ipv4ll_address) { + r = in_addr_from_string(AF_INET, ipv4ll_address, &address); + if (r < 0) { + log_link_debug_errno(link, r, "Falied to parse IPv4LL address %s: %m", ipv4ll_address); + goto ipv4ll_address_fail; + } + + r = sd_ipv4ll_new(&link->ipv4ll); + if (r < 0) + return log_link_error_errno(link, r, "Falied to create IPv4LL client: %m"); + + r = sd_ipv4ll_set_address(link->ipv4ll, &address.in); + if (r < 0) + return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address); } - return 1; +ipv4ll_address_fail: + + return 0; } int link_add(Manager *m, sd_netlink_message *message, Link **ret) { @@ -2203,12 +2435,18 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) { log_link_debug(link, "Link %d added", link->ifindex); + r = link_load(link); + if (r < 0) + return r; + if (detect_container() <= 0) { /* not in a container, udev will be around */ sprintf(ifindex_str, "n%d", link->ifindex); device = udev_device_new_from_device_id(m->udev, ifindex_str); - if (!device) - return log_link_warning_errno(link, errno, "Could not find udev device: %m"); + if (!device) { + r = log_link_warning_errno(link, errno, "Could not find udev device: %m"); + goto failed; + } if (udev_device_get_is_initialized(device) <= 0) { /* not yet ready */ @@ -2218,14 +2456,38 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) { r = link_initialized(link, device); if (r < 0) - return r; + goto failed; } else { /* we are calling a callback directly, so must take a ref */ link_ref(link); r = link_initialized_and_synced(m->rtnl, NULL, link); if (r < 0) + goto failed; + } + + return 0; +failed: + link_enter_failed(link); + return r; +} + +int link_ipv6ll_gained(Link *link) { + int r; + + assert(link); + + log_link_info(link, "Gained IPv6LL"); + + link->ipv6ll_address = true; + link_check_ready(link); + + if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { + r = link_acquire_ipv6_conf(link); + if (r < 0) { + link_enter_failed(link); return r; + } } return 0; @@ -2236,7 +2498,7 @@ static int link_carrier_gained(Link *link) { assert(link); - if (link->network) { + if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { r = link_acquire_conf(link); if (r < 0) { link_enter_failed(link); @@ -2416,49 +2678,13 @@ int link_update(Link *link, sd_netlink_message *m) { return 0; } -static void link_update_operstate(Link *link) { - LinkOperationalState operstate; - assert(link); - - if (link->kernel_operstate == IF_OPER_DORMANT) - operstate = LINK_OPERSTATE_DORMANT; - else if (link_has_carrier(link)) { - Address *address; - uint8_t scope = RT_SCOPE_NOWHERE; - - /* if we have carrier, check what addresses we have */ - LIST_FOREACH(addresses, address, link->addresses) { - if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) - continue; - - if (address->scope < scope) - scope = address->scope; - } - - if (scope < RT_SCOPE_SITE) - /* universally accessible addresses found */ - operstate = LINK_OPERSTATE_ROUTABLE; - else if (scope < RT_SCOPE_HOST) - /* only link or site local addresses found */ - operstate = LINK_OPERSTATE_DEGRADED; - else - /* no useful addresses found */ - operstate = LINK_OPERSTATE_CARRIER; - } else if (link->flags & IFF_UP) - operstate = LINK_OPERSTATE_NO_CARRIER; - else - operstate = LINK_OPERSTATE_OFF; - - if (link->operstate != operstate) { - link->operstate = operstate; - link_send_changed(link, "OperationalState", NULL); - } -} - int link_save(Link *link) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; const char *admin_state, *oper_state; + Address *a; + Route *route; + Iterator i; int r; assert(link); @@ -2466,12 +2692,6 @@ int link_save(Link *link) { assert(link->lease_file); assert(link->manager); - link_update_operstate(link); - - r = manager_save(link->manager); - if (r < 0) - return r; - if (link->state == LINK_STATE_LINGER) { unlink(link->state_file); return 0; @@ -2501,9 +2721,8 @@ int link_save(Link *link) { sd_dhcp6_lease *dhcp6_lease = NULL; if (link->dhcp6_client) { - r = sd_dhcp6_client_get_lease(link->dhcp6_client, - &dhcp6_lease); - if (r < 0) + r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease); + if (r < 0 && r != -ENOMSG) log_link_debug(link, "No DHCPv6 lease"); } @@ -2542,9 +2761,9 @@ int link_save(Link *link) { } } - fputs("\n", f); + fputc('\n', f); - fprintf(f, "NTP="); + fputs("NTP=", f); space = false; STRV_FOREACH(address, link->network->ntp) { if (space) @@ -2591,9 +2810,9 @@ int link_save(Link *link) { } } - fputs("\n", f); + fputc('\n', f); - fprintf(f, "DOMAINS="); + fputs("DOMAINS=", f); space = false; STRV_FOREACH(domain, link->network->domains) { if (space) @@ -2629,18 +2848,48 @@ int link_save(Link *link) { } } - fputs("\n", f); + fputc('\n', f); fprintf(f, "WILDCARD_DOMAIN=%s\n", yes_no(link->network->wildcard_domain)); fprintf(f, "LLMNR=%s\n", resolve_support_to_string(link->network->llmnr)); + + fputs("ADDRESSES=", f); + space = false; + SET_FOREACH(a, link->addresses, i) { + _cleanup_free_ char *address_str = NULL; + + r = in_addr_to_string(a->family, &a->in_addr, &address_str); + if (r < 0) + goto fail; + + fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen); + space = true; + } + + fputc('\n', f); + + fputs("ROUTES=", f); + space = false; + SET_FOREACH(route, link->routes, i) { + _cleanup_free_ char *route_str = NULL; + + r = in_addr_to_string(route->family, &route->dst, &route_str); + if (r < 0) + goto fail; + + fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str, + route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime); + space = true; + } + + fputc('\n', f); } if (!hashmap_isempty(link->bound_to_links)) { Link *carrier; - Iterator i; bool space = false; fputs("CARRIER_BOUND_TO=", f); @@ -2651,12 +2900,11 @@ int link_save(Link *link) { space = true; } - fputs("\n", f); + fputc('\n', f); } if (!hashmap_isempty(link->bound_by_links)) { Link *carrier; - Iterator i; bool space = false; fputs("CARRIER_BOUND_BY=", f); @@ -2667,19 +2915,25 @@ int link_save(Link *link) { space = true; } - fputs("\n", f); + fputc('\n', f); } if (link->dhcp_lease) { + struct in_addr address; const char *tz = NULL; + assert(link->network); + r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); if (r >= 0) fprintf(f, "TIMEZONE=%s\n", tz); - } - if (link->dhcp_lease) { - assert(link->network); + r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); + if (r >= 0) { + fputs("DHCP4_ADDRESS=", f); + serialize_in_addrs(f, &address, 1); + fputc('\n', f); + } r = dhcp_lease_save(link->dhcp_lease, link->lease_file); if (r < 0) @@ -2691,6 +2945,17 @@ int link_save(Link *link) { } else unlink(link->lease_file); + if (link->ipv4ll) { + struct in_addr address; + + r = sd_ipv4ll_get_address(link->ipv4ll, &address); + if (r >= 0) { + fputs("IPV4LL_ADDRESS=", f); + serialize_in_addrs(f, &address, 1); + fputc('\n', f); + } + } + if (link->lldp) { assert(link->network); @@ -2723,6 +2988,34 @@ fail: return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file); } +/* The serialized state in /run is no longer up-to-date. */ +void link_dirty(Link *link) { + int r; + + assert(link); + + r = set_ensure_allocated(&link->manager->dirty_links, NULL); + if (r < 0) + /* allocation errors are ignored */ + return; + + r = set_put(link->manager->dirty_links, link); + if (r < 0) + /* allocation errors are ignored */ + return; + + link_ref(link); +} + +/* The serialized state in /run is up-to-date */ +void link_clean(Link *link) { + assert(link); + assert(link->manager); + + set_remove(link->manager->dirty_links, link); + link_unref(link); +} + static const char* const link_state_table[_LINK_STATE_MAX] = { [LINK_STATE_PENDING] = "pending", [LINK_STATE_ENSLAVING] = "configuring", diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 7b219c6854..b564bcbca0 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -25,10 +25,10 @@ #include "sd-dhcp-client.h" #include "sd-dhcp-server.h" -#include "sd-ipv4ll.h" -#include "sd-icmp6-nd.h" #include "sd-dhcp6-client.h" +#include "sd-ipv4ll.h" #include "sd-lldp.h" +#include "sd-ndisc.h" typedef struct Link Link; @@ -83,7 +83,10 @@ struct Link { unsigned link_messages; unsigned enslaving; - LIST_HEAD(Address, addresses); + Set *addresses; + Set *addresses_foreign; + Set *routes; + Set *routes_foreign; sd_dhcp_client *dhcp_client; sd_dhcp_lease *dhcp_lease; @@ -92,10 +95,13 @@ struct Link { unsigned dhcp4_messages; bool dhcp4_configured; bool dhcp6_configured; + unsigned ndisc_messages; + bool ndisc_configured; sd_ipv4ll *ipv4ll; - bool ipv4ll_address; - bool ipv4ll_route; + bool ipv4ll_address:1; + bool ipv4ll_route:1; + bool ipv6ll_address:1; bool static_configured; @@ -103,7 +109,7 @@ struct Link { sd_dhcp_server *dhcp_server; - sd_icmp6_nd *icmp6_router_discovery; + sd_ndisc *ndisc_router_discovery; sd_dhcp6_client *dhcp6_client; bool rtnl_extended_attrs; @@ -120,29 +126,35 @@ int link_get(Manager *m, int ifindex, Link **ret); int link_add(Manager *manager, sd_netlink_message *message, Link **ret); void link_drop(Link *link); -int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); -int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); +int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); +int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); void link_enter_failed(Link *link); int link_initialized(Link *link, struct udev_device *device); -void link_client_handler(Link *link); +void link_check_ready(Link *link); +void link_update_operstate(Link *link); int link_update(Link *link, sd_netlink_message *message); -int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata); +void link_dirty(Link *link); +void link_clean(Link *link); int link_save(Link *link); int link_carrier_reset(Link *link); bool link_has_carrier(Link *link); +int link_ipv6ll_gained(Link *link); + int link_set_mtu(Link *link, uint32_t mtu); int link_set_hostname(Link *link, const char *hostname); int link_set_timezone(Link *link, const char *timezone); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); -int icmp6_configure(Link *link); +int dhcp6_configure(Link *link); +int dhcp6_request_address(Link *link); +int ndisc_configure(Link *link); bool link_lldp_enabled(Link *link); bool link_ipv4ll_enabled(Link *link); @@ -150,6 +162,7 @@ bool link_ipv6ll_enabled(Link *link); bool link_dhcp4_server_enabled(Link *link); bool link_dhcp4_enabled(Link *link); bool link_dhcp6_enabled(Link *link); +bool link_ipv6_accept_ra_enabled(Link *link); const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_; diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index b281f4fdb6..dafaf2daea 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-util.h" - #include "networkd.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b4259cafef..42f58fed19 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -22,21 +22,23 @@ #include <sys/socket.h> #include <linux/if.h> -#include "sd-netlink.h" #include "sd-daemon.h" +#include "sd-netlink.h" -#include "conf-parser.h" -#include "path-util.h" -#include "libudev-private.h" -#include "udev-util.h" -#include "netlink-util.h" +#include "alloc-util.h" #include "bus-util.h" +#include "conf-parser.h" #include "def.h" -#include "virt.h" -#include "set.h" +#include "fd-util.h" +#include "fileio.h" +#include "libudev-private.h" #include "local-addresses.h" - +#include "netlink-util.h" #include "networkd.h" +#include "path-util.h" +#include "set.h" +#include "udev-util.h" +#include "virt.h" /* use 8 MB for receive socket kernel queue. */ #define RCVBUF_SIZE (8*1024*1024) @@ -277,6 +279,350 @@ static int manager_connect_udev(Manager *m) { return 0; } +int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { + Manager *m = userdata; + Link *link = NULL; + uint16_t type; + uint32_t ifindex, priority = 0; + unsigned char protocol, scope, tos, table; + int family; + unsigned char dst_prefixlen, src_prefixlen; + union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {}; + Route *route = NULL; + int r; + + assert(rtnl); + assert(message); + assert(m); + + if (sd_netlink_message_is_error(message)) { + r = sd_netlink_message_get_errno(message); + if (r < 0) + log_warning_errno(r, "rtnl: failed to receive route: %m"); + + return 0; + } + + r = sd_netlink_message_get_type(message, &type); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get message type: %m"); + return 0; + } else if (type != RTM_NEWROUTE && type != RTM_DELROUTE) { + log_warning("rtnl: received unexpected message type when processing route"); + return 0; + } + + r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex); + if (r == -ENODATA) { + log_debug("rtnl: received route without ifindex, ignoring"); + return 0; + } else if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex); + return 0; + } else { + r = link_get(m, ifindex, &link); + if (r < 0 || !link) { + /* when enumerating we might be out of sync, but we will + * get the route again, so just ignore it */ + if (!m->enumerating) + log_warning("rtnl: received route for nonexistent link (%d), ignoring", ifindex); + return 0; + } + } + + r = sd_rtnl_message_route_get_family(message, &family); + if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) { + log_link_warning(link, "rtnl: received address with invalid family, ignoring."); + return 0; + } + + r = sd_rtnl_message_route_get_protocol(message, &protocol); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get route protocol: %m"); + return 0; + } + + switch (family) { + case AF_INET: + r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m"); + return 0; + } + + break; + + case AF_INET6: + r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m"); + return 0; + } + + break; + + default: + log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family); + return 0; + } + + r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_scope(message, &scope); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_tos(message, &tos); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_table(message, &table); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m"); + return 0; + } + + route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route); + + switch (type) { + case RTM_NEWROUTE: + if (!route) { + /* A route appeared that we did not request */ + r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route); + if (r < 0) + return 0; + } + + route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol); + + break; + + case RTM_DELROUTE: + + if (route) + route_drop(route); + + break; + default: + assert_not_reached("Received invalid RTNL message type"); + } + + return 1; +} + +int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { + Manager *m = userdata; + Link *link = NULL; + uint16_t type; + unsigned char flags; + int family; + unsigned char prefixlen; + unsigned char scope; + union in_addr_union in_addr; + struct ifa_cacheinfo cinfo; + Address *address = NULL; + char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX]; + const char *valid_str = NULL; + int r, ifindex; + + assert(rtnl); + assert(message); + assert(m); + + if (sd_netlink_message_is_error(message)) { + r = sd_netlink_message_get_errno(message); + if (r < 0) + log_warning_errno(r, "rtnl: failed to receive address: %m"); + + return 0; + } + + r = sd_netlink_message_get_type(message, &type); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get message type: %m"); + return 0; + } else if (type != RTM_NEWADDR && type != RTM_DELADDR) { + log_warning("rtnl: received unexpected message type when processing address"); + return 0; + } + + r = sd_rtnl_message_addr_get_ifindex(message, &ifindex); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex from address: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received address message with invalid ifindex: %d", ifindex); + return 0; + } else { + r = link_get(m, ifindex, &link); + if (r < 0 || !link) { + /* when enumerating we might be out of sync, but we will + * get the address again, so just ignore it */ + if (!m->enumerating) + log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex); + return 0; + } + } + + r = sd_rtnl_message_addr_get_family(message, &family); + if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) { + log_link_warning(link, "rtnl: received address with invalid family, ignoring."); + return 0; + } + + r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_addr_get_scope(message, &scope); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_addr_get_flags(message, &flags); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m"); + return 0; + } + + switch (family) { + case AF_INET: + r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); + return 0; + } + + break; + + case AF_INET6: + r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); + return 0; + } + + break; + + default: + log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family); + } + + if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) { + log_link_warning(link, "Could not print address"); + return 0; + } + + r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo); + if (r >= 0) { + if (cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME) + valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, + cinfo.ifa_valid * USEC_PER_SEC, + USEC_PER_SEC); + } + + address_get(link, family, &in_addr, prefixlen, &address); + + switch (type) { + case RTM_NEWADDR: + if (address) + log_link_debug(link, "Updating address: %s/%u (valid %s%s)", buf, prefixlen, + valid_str ? "for " : "forever", valid_str ?: ""); + else { + /* An address appeared that we did not request */ + r = address_add_foreign(link, family, &in_addr, prefixlen, &address); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen); + return 0; + } else + log_link_debug(link, "Adding address: %s/%u (valid %s%s)", buf, prefixlen, + valid_str ? "for " : "forever", valid_str ?: ""); + } + + address_update(address, flags, scope, &cinfo); + + break; + + case RTM_DELADDR: + + if (address) { + log_link_debug(link, "Removing address: %s/%u (valid %s%s)", buf, prefixlen, + valid_str ? "for " : "forever", valid_str ?: ""); + address_drop(address); + } else + log_link_warning(link, "Removing non-existent address: %s/%u (valid %s%s)", buf, prefixlen, + valid_str ? "for " : "forever", valid_str ?: ""); + + break; + default: + assert_not_reached("Received invalid RTNL message type"); + } + + return 1; +} + static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { Manager *m = userdata; Link *link = NULL; @@ -410,17 +756,232 @@ static int manager_connect_rtnl(Manager *m) { if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m); + r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m); + if (r < 0) + return r; + + r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m); + r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m); + if (r < 0) + return r; + + r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m); if (r < 0) return r; return 0; } +static int set_put_in_addr(Set *s, const struct in_addr *address) { + char *p; + int r; + + assert(s); + + r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); + if (r < 0) + return r; + + r = set_consume(s, p); + if (r == -EEXIST) + return 0; + + return r; +} + +static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) { + int r, i, c = 0; + + assert(s); + assert(n <= 0 || addresses); + + for (i = 0; i < n; i++) { + r = set_put_in_addr(s, addresses+i); + if (r < 0) + return r; + + c += r; + } + + return c; +} + +static void print_string_set(FILE *f, const char *field, Set *s) { + bool space = false; + Iterator i; + char *p; + + if (set_isempty(s)) + return; + + fputs(field, f); + + SET_FOREACH(p, s, i) { + if (space) + fputc(' ', f); + fputs(p, f); + space = true; + } + fputc('\n', f); +} + +static int manager_save(Manager *m) { + _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL; + Link *link; + Iterator i; + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + LinkOperationalState operstate = LINK_OPERSTATE_OFF; + const char *operstate_str; + int r; + + assert(m); + assert(m->state_file); + + /* We add all NTP and DNS server to a set, to filter out duplicates */ + dns = set_new(&string_hash_ops); + if (!dns) + return -ENOMEM; + + ntp = set_new(&string_hash_ops); + if (!ntp) + return -ENOMEM; + + domains = set_new(&string_hash_ops); + if (!domains) + return -ENOMEM; + + HASHMAP_FOREACH(link, m->links, i) { + if (link->flags & IFF_LOOPBACK) + continue; + + if (link->operstate > operstate) + operstate = link->operstate; + + if (!link->network) + continue; + + /* First add the static configured entries */ + r = set_put_strdupv(dns, link->network->dns); + if (r < 0) + return r; + + r = set_put_strdupv(ntp, link->network->ntp); + if (r < 0) + return r; + + r = set_put_strdupv(domains, link->network->domains); + if (r < 0) + return r; + + if (!link->dhcp_lease) + continue; + + /* Secondly, add the entries acquired via DHCP */ + if (link->network->dhcp_dns) { + const struct in_addr *addresses; + + r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); + if (r > 0) { + r = set_put_in_addrv(dns, addresses, r); + if (r < 0) + return r; + } else if (r < 0 && r != -ENODATA) + return r; + } + + if (link->network->dhcp_ntp) { + const struct in_addr *addresses; + + r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); + if (r > 0) { + r = set_put_in_addrv(ntp, addresses, r); + if (r < 0) + return r; + } else if (r < 0 && r != -ENODATA) + return r; + } + + if (link->network->dhcp_domains) { + const char *domainname; + + r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); + if (r >= 0) { + r = set_put_strdup(domains, domainname); + if (r < 0) + return r; + } else if (r != -ENODATA) + return r; + } + } + + operstate_str = link_operstate_to_string(operstate); + assert(operstate_str); + + r = fopen_temporary(m->state_file, &f, &temp_path); + if (r < 0) + return r; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "OPER_STATE=%s\n", operstate_str); + + print_string_set(f, "DNS=", dns); + print_string_set(f, "NTP=", ntp); + print_string_set(f, "DOMAINS=", domains); + + r = fflush_and_check(f); + if (r < 0) + goto fail; + + if (rename(temp_path, m->state_file) < 0) { + r = -errno; + goto fail; + } + + if (m->operational_state != operstate) { + m->operational_state = operstate; + r = manager_send_changed(m, "OperationalState", NULL); + if (r < 0) + log_error_errno(r, "Could not emit changed OperationalState: %m"); + } + + m->dirty = false; + + return 0; + +fail: + (void) unlink(m->state_file); + (void) unlink(temp_path); + + return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); +} + +static int manager_dirty_handler(sd_event_source *s, void *userdata) { + Manager *m = userdata; + Link *link; + Iterator i; + int r; + + assert(m); + + if (m->dirty) + manager_save(m); + + SET_FOREACH(link, m->dirty_links, i) { + r = link_save(link); + if (r >= 0) + link_clean(link); + } + + return 1; +} + int manager_new(Manager **ret) { _cleanup_manager_free_ Manager *m = NULL; int r; @@ -442,6 +1003,10 @@ int manager_new(Manager **ret) { sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL); sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL); + r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m); + if (r < 0) + return r; + r = manager_connect_rtnl(m); if (r < 0) return r; @@ -477,14 +1042,6 @@ void manager_free(Manager *m) { free(m->state_file); - sd_event_source_unref(m->udev_event_source); - udev_monitor_unref(m->udev_monitor); - udev_unref(m->udev); - - sd_bus_unref(m->bus); - sd_bus_slot_unref(m->prepare_for_sleep_slot); - sd_event_source_unref(m->bus_retry_event_source); - while ((link = hashmap_first(m->links))) link_unref(link); hashmap_free(m->links); @@ -504,6 +1061,14 @@ void manager_free(Manager *m) { sd_netlink_unref(m->rtnl); sd_event_unref(m->event); + sd_event_source_unref(m->udev_event_source); + udev_monitor_unref(m->udev_monitor); + udev_unref(m->udev); + + sd_bus_unref(m->bus); + sd_bus_slot_unref(m->prepare_for_sleep_slot); + sd_event_source_unref(m->bus_retry_event_source); + free(m); } @@ -528,7 +1093,8 @@ static bool manager_check_idle(void *userdata) { link_ipv4ll_enabled(link) || link_dhcp4_server_enabled(link) || link_dhcp4_enabled(link) || - link_dhcp6_enabled(link)) + link_dhcp6_enabled(link) || + link_ipv6_accept_ra_enabled(link)) return false; } @@ -536,8 +1102,19 @@ static bool manager_check_idle(void *userdata) { } int manager_run(Manager *m) { + Link *link; + Iterator i; + assert(m); + /* The dirty handler will deal with future serialization, but the first one + must be done explicitly. */ + + manager_save(m); + + HASHMAP_FOREACH(link, m->links, i) + link_save(link); + if (m->bus) return bus_event_loop_with_idle( m->event, @@ -633,7 +1210,7 @@ int manager_rtnl_enumerate_addresses(Manager *m) { m->enumerating = true; - k = link_rtnl_process_address(m->rtnl, addr, m); + k = manager_rtnl_process_address(m->rtnl, addr, m); if (k < 0) r = k; @@ -643,189 +1220,39 @@ int manager_rtnl_enumerate_addresses(Manager *m) { return r; } -static int set_put_in_addr(Set *s, const struct in_addr *address) { - char *p; +int manager_rtnl_enumerate_routes(Manager *m) { + _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + sd_netlink_message *route; int r; - assert(s); + assert(m); + assert(m->rtnl); - r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); + r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); if (r < 0) return r; - r = set_consume(s, p); - if (r == -EEXIST) - return 0; - - return r; -} - -static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) { - int r, i, c = 0; - - assert(s); - assert(n <= 0 || addresses); - - for (i = 0; i < n; i++) { - r = set_put_in_addr(s, addresses+i); - if (r < 0) - return r; - - c += r; - } - - return c; -} - -static void print_string_set(FILE *f, const char *field, Set *s) { - bool space = false; - Iterator i; - char *p; - - if (set_isempty(s)) - return; - - fputs(field, f); - - SET_FOREACH(p, s, i) { - if (space) - fputc(' ', f); - fputs(p, f); - space = true; - } - fputc('\n', f); -} - -int manager_save(Manager *m) { - _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL; - Link *link; - Iterator i; - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - LinkOperationalState operstate = LINK_OPERSTATE_OFF; - const char *operstate_str; - int r; - - assert(m); - assert(m->state_file); - - /* We add all NTP and DNS server to a set, to filter out duplicates */ - dns = set_new(&string_hash_ops); - if (!dns) - return -ENOMEM; - - ntp = set_new(&string_hash_ops); - if (!ntp) - return -ENOMEM; - - domains = set_new(&string_hash_ops); - if (!domains) - return -ENOMEM; - - HASHMAP_FOREACH(link, m->links, i) { - if (link->flags & IFF_LOOPBACK) - continue; - - if (link->operstate > operstate) - operstate = link->operstate; - - if (!link->network) - continue; - - /* First add the static configured entries */ - r = set_put_strdupv(dns, link->network->dns); - if (r < 0) - return r; - - r = set_put_strdupv(ntp, link->network->ntp); - if (r < 0) - return r; - - r = set_put_strdupv(domains, link->network->domains); - if (r < 0) - return r; - - if (!link->dhcp_lease) - continue; - - /* Secondly, add the entries acquired via DHCP */ - if (link->network->dhcp_dns) { - const struct in_addr *addresses; - - r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); - if (r > 0) { - r = set_put_in_addrv(dns, addresses, r); - if (r < 0) - return r; - } else if (r < 0 && r != -ENODATA) - return r; - } - - if (link->network->dhcp_ntp) { - const struct in_addr *addresses; - - r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); - if (r > 0) { - r = set_put_in_addrv(ntp, addresses, r); - if (r < 0) - return r; - } else if (r < 0 && r != -ENODATA) - return r; - } - - if (link->network->dhcp_domains) { - const char *domainname; - - r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); - if (r >= 0) { - r = set_put_strdup(domains, domainname); - if (r < 0) - return r; - } else if (r != -ENODATA) - return r; - } - } - - operstate_str = link_operstate_to_string(operstate); - assert(operstate_str); - - r = fopen_temporary(m->state_file, &f, &temp_path); + r = sd_netlink_message_request_dump(req, true); if (r < 0) return r; - fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n" - "OPER_STATE=%s\n", operstate_str); - - print_string_set(f, "DNS=", dns); - print_string_set(f, "NTP=", ntp); - print_string_set(f, "DOMAINS=", domains); - - r = fflush_and_check(f); + r = sd_netlink_call(m->rtnl, req, 0, &reply); if (r < 0) - goto fail; + return r; - if (rename(temp_path, m->state_file) < 0) { - r = -errno; - goto fail; - } + for (route = reply; route; route = sd_netlink_message_next(route)) { + int k; - if (m->operational_state != operstate) { - m->operational_state = operstate; - r = manager_send_changed(m, "OperationalState", NULL); - if (r < 0) - log_error_errno(r, "Could not emit changed OperationalState: %m"); - } + m->enumerating = true; - return 0; + k = manager_rtnl_process_route(m->rtnl, route, m); + if (k < 0) + r = k; -fail: - (void) unlink(m->state_file); - (void) unlink(temp_path); + m->enumerating = false; + } - return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); + return r; } int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) { @@ -884,3 +1311,10 @@ Link* manager_find_uplink(Manager *m, Link *exclude) { return NULL; } + +void manager_dirty(Manager *manager) { + assert(manager); + + /* the serialized state in /run is no longer up-to-date */ + manager->dirty = true; +} diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c new file mode 100644 index 0000000000..126f9c0fe9 --- /dev/null +++ b/src/network/networkd-ndisc.c @@ -0,0 +1,247 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <netinet/ether.h> +#include <netinet/icmp6.h> +#include <linux/if.h> + +#include "sd-ndisc.h" + +#include "networkd-link.h" + +static int ndisc_netlink_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { + _cleanup_link_unref_ Link *link = userdata; + int r; + + assert(link); + assert(link->ndisc_messages > 0); + + link->ndisc_messages --; + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EEXIST) { + log_link_error_errno(link, r, "Could not set NDisc route or address: %m"); + link_enter_failed(link); + } + + if (link->ndisc_messages == 0) { + link->ndisc_configured = true; + link_check_ready(link); + } + + return 1; +} + +static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, + unsigned lifetime_preferred, unsigned lifetime_valid, void *userdata) { + _cleanup_address_free_ Address *address = NULL; + Link *link = userdata; + usec_t time_now; + int r; + + assert(nd); + assert(link); + assert(link->network); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + + r = address_new(&address); + if (r < 0) { + log_link_error_errno(link, r, "Could not allocate address: %m"); + return; + } + + assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); + + address->family = AF_INET6; + address->in_addr.in6 = *prefix; + if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0) + memcpy(&address->in_addr.in6 + 8, &link->network->ipv6_token + 8, 8); + else { + /* see RFC4291 section 2.5.1 */ + address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0]; + address->in_addr.in6.__in6_u.__u6_addr8[8] ^= 1 << 1; + address->in_addr.in6.__in6_u.__u6_addr8[9] = link->mac.ether_addr_octet[1]; + address->in_addr.in6.__in6_u.__u6_addr8[10] = link->mac.ether_addr_octet[2]; + address->in_addr.in6.__in6_u.__u6_addr8[11] = 0xff; + address->in_addr.in6.__in6_u.__u6_addr8[12] = 0xfe; + address->in_addr.in6.__in6_u.__u6_addr8[13] = link->mac.ether_addr_octet[3]; + address->in_addr.in6.__in6_u.__u6_addr8[14] = link->mac.ether_addr_octet[4]; + address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5]; + } + address->prefixlen = prefixlen; + address->flags = IFA_F_NOPREFIXROUTE; + address->cinfo.ifa_prefered = lifetime_preferred; + address->cinfo.ifa_valid = lifetime_valid; + + r = address_configure(address, link, ndisc_netlink_handler, true); + if (r < 0) { + log_link_warning_errno(link, r, "Could not set SLAAC address: %m"); + link_enter_failed(link); + return; + } + + link->ndisc_messages ++; +} + +static void ndisc_prefix_onlink_handler(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, unsigned lifetime, void *userdata) { + _cleanup_route_free_ Route *route = NULL; + Link *link = userdata; + usec_t time_now; + int r; + + assert(nd); + assert(link); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + + r = route_new(&route); + if (r < 0) { + log_link_error_errno(link, r, "Could not allocate route: %m"); + return; + } + + assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); + + route->family = AF_INET6; + route->table = RT_TABLE_MAIN; + route->protocol = RTPROT_RA; + route->flags = RTM_F_PREFIX; + route->dst.in6 = *prefix; + route->dst_prefixlen = prefixlen; + route->lifetime = time_now + lifetime * USEC_PER_SEC; + + r = route_configure(route, link, ndisc_netlink_handler); + if (r < 0) { + log_link_warning_errno(link, r, "Could not set prefix route: %m"); + link_enter_failed(link); + return; + } + + link->ndisc_messages ++; +} + +static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata) { + _cleanup_route_free_ Route *route = NULL; + Link *link = userdata; + usec_t time_now; + int r; + + assert(link); + assert(link->network); + assert(link->manager); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + + if (flags & (ND_RA_FLAG_MANAGED | ND_RA_FLAG_OTHER)) { + if (flags & ND_RA_FLAG_MANAGED) + dhcp6_request_address(link); + + r = sd_dhcp6_client_start(link->dhcp6_client); + if (r < 0 && r != -EALREADY) + log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m"); + } + + if (!gateway) + return; + + r = route_new(&route); + if (r < 0) { + log_link_error_errno(link, r, "Could not allocate route: %m"); + return; + } + + assert_se(sd_event_now(link->manager->event, clock_boottime_or_monotonic(), &time_now) >= 0); + + route->family = AF_INET6; + route->table = RT_TABLE_MAIN; + route->protocol = RTPROT_RA; + route->pref = pref; + route->gw.in6 = *gateway; + route->lifetime = time_now + lifetime * USEC_PER_SEC; + + r = route_configure(route, link, ndisc_netlink_handler); + if (r < 0) { + log_link_warning_errno(link, r, "Could not set default route: %m"); + link_enter_failed(link); + return; + } + + link->ndisc_messages ++; +} + +static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { + Link *link = userdata; + int r; + + assert(link); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + + switch (event) { + case SD_NDISC_EVENT_TIMEOUT: + dhcp6_request_address(link); + + r = sd_dhcp6_client_start(link->dhcp6_client); + if (r < 0 && r != -EALREADY) + log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m"); + break; + case SD_NDISC_EVENT_STOP: + break; + default: + log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event); + } +} + +int ndisc_configure(Link *link) { + int r; + + assert_return(link, -EINVAL); + + r = sd_ndisc_new(&link->ndisc_router_discovery); + if (r < 0) + return r; + + r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0); + if (r < 0) + return r; + + r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac); + if (r < 0) + return r; + + r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex); + if (r < 0) + return r; + + r = sd_ndisc_set_callback(link->ndisc_router_discovery, + ndisc_router_handler, + ndisc_prefix_onlink_handler, + ndisc_prefix_autonomous_handler, + ndisc_handler, + link); + + return r; +} diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index bcaba57937..4e4755f86f 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -23,10 +23,14 @@ #include <netinet/ether.h> #include <linux/if_bonding.h> -#include "conf-parser.h" #include "sd-netlink.h" -#include "networkd-netdev-bond.h" + +#include "alloc-util.h" +#include "conf-parser.h" #include "missing.h" +#include "networkd-netdev-bond.h" +#include "string-util.h" +#include "string-table.h" /* * Number of seconds between instances where the bonding @@ -178,15 +182,18 @@ static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) { } static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { - Bond *b = BOND(netdev); + Bond *b; ArpIpTarget *target = NULL; int r, i = 0; assert(netdev); assert(!link); - assert(b); assert(m); + b = BOND(netdev); + + assert(b); + if (b->mode != _NETDEV_BOND_MODE_INVALID) { r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, bond_mode_to_kernel(b->mode)); @@ -333,8 +340,6 @@ int config_parse_arp_ip_target_address(const char *unit, void *data, void *userdata) { Bond *b = userdata; - const char *word, *state; - size_t l; int r; assert(filename); @@ -342,14 +347,19 @@ int config_parse_arp_ip_target_address(const char *unit, assert(rvalue); assert(data); - FOREACH_WORD_QUOTED(word, l, rvalue, state) { + for (;;) { _cleanup_free_ ArpIpTarget *buffer = NULL; _cleanup_free_ char *n = NULL; int f; - n = strndup(word, l); - if (!n) - return -ENOMEM; + r = extract_first_word(&rvalue, &n, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue); + return 0; + } + + if (r == 0) + break; buffer = new0(ArpIpTarget, 1); if (!buffer) @@ -373,16 +383,21 @@ int config_parse_arp_ip_target_address(const char *unit, } if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX) - log_syntax(unit, LOG_WARNING, filename, line, 0, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX); + log_syntax(unit, LOG_WARNING, filename, line, 0, + "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", + b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX); return 0; } static void bond_done(NetDev *netdev) { ArpIpTarget *t = NULL, *n = NULL; - Bond *b = BOND(netdev); + Bond *b; assert(netdev); + + b = BOND(netdev); + assert(b); LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets) @@ -392,9 +407,12 @@ static void bond_done(NetDev *netdev) { } static void bond_init(NetDev *netdev) { - Bond *b = BOND(netdev); + Bond *b; assert(netdev); + + b = BOND(netdev); + assert(b); b->mode = _NETDEV_BOND_MODE_INVALID; diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index 2eeb86a683..57c58d83b4 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -72,20 +72,21 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); + /* convert to jiffes */ if (b->forward_delay > 0) { - r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, b->forward_delay / USEC_PER_SEC); + r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, usec_to_jiffies(b->forward_delay)); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m"); } if (b->hello_time > 0) { - r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, b->hello_time / USEC_PER_SEC ); + r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, usec_to_jiffies(b->hello_time)); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_HELLO_TIME attribute: %m"); } if (b->max_age > 0) { - r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, b->max_age / USEC_PER_SEC); + r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, usec_to_jiffies(b->max_age)); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m"); } diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 4aac239850..4a4b400e41 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -56,6 +56,7 @@ VXLAN.UDP6ZeroCheckSumRx, config_parse_bool, 0, VXLAN.UDP6ZeroCheckSumTx, config_parse_bool, 0, offsetof(VxLan, udp6zerocsumtx) VXLAN.FDBAgeingSec, config_parse_sec, 0, offsetof(VxLan, fdb_ageing) VXLAN.GroupPolicyExtension, config_parse_bool, 0, offsetof(VxLan, group_policy) +VXLAN.MaximumFDBEntries, config_parse_unsigned, 0, offsetof(VxLan, max_fdb) Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue) Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue) Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info) diff --git a/src/network/networkd-netdev-ipvlan.c b/src/network/networkd-netdev-ipvlan.c index 5eb4a1eb36..27cb7d1bf0 100644 --- a/src/network/networkd-netdev-ipvlan.c +++ b/src/network/networkd-netdev-ipvlan.c @@ -21,8 +21,9 @@ #include <net/if.h> -#include "networkd-netdev-ipvlan.h" #include "conf-parser.h" +#include "networkd-netdev-ipvlan.h" +#include "string-table.h" static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = { [NETDEV_IPVLAN_MODE_L2] = "L2", @@ -33,14 +34,17 @@ DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode); DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode"); static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { - IPVlan *m = IPVLAN(netdev); + IPVlan *m; int r; assert(netdev); - assert(m); assert(link); assert(netdev->ifname); + m = IPVLAN(netdev); + + assert(m); + if (m->mode != _NETDEV_IPVLAN_MODE_INVALID) { r = sd_netlink_message_append_u16(req, IFLA_IPVLAN_MODE, m->mode); if (r < 0) @@ -51,9 +55,12 @@ static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netl } static void ipvlan_init(NetDev *n) { - IPVlan *m = IPVLAN(n); + IPVlan *m; assert(n); + + m = IPVLAN(n); + assert(m); m->mode = _NETDEV_IPVLAN_MODE_INVALID; diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c index e17de793ce..7144823b2d 100644 --- a/src/network/networkd-netdev-macvlan.c +++ b/src/network/networkd-netdev-macvlan.c @@ -21,8 +21,9 @@ #include <net/if.h> -#include "networkd-netdev-macvlan.h" #include "conf-parser.h" +#include "networkd-netdev-macvlan.h" +#include "string-table.h" static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = { [NETDEV_MACVLAN_MODE_PRIVATE] = "private", diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index c9b7fa96e2..385338849f 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -26,11 +26,15 @@ #include <linux/ip6_tunnel.h> #include "sd-netlink.h" -#include "networkd-netdev-tunnel.h" + +#include "conf-parser.h" +#include "missing.h" #include "networkd-link.h" +#include "networkd-netdev-tunnel.h" +#include "parse-util.h" +#include "string-table.h" +#include "string-util.h" #include "util.h" -#include "missing.h" -#include "conf-parser.h" #define DEFAULT_TNL_HOP_LIMIT 64 #define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF) diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index 6a808b6205..851e83537e 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -23,7 +23,10 @@ #include <net/if.h> #include <linux/if_tun.h> +#include "alloc-util.h" +#include "fd-util.h" #include "networkd-netdev-tuntap.h" +#include "user-util.h" #define TUN_DEV "/dev/net/tun" diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c index e20f9f74e2..bee1a16726 100644 --- a/src/network/networkd-netdev-veth.c +++ b/src/network/networkd-netdev-veth.c @@ -26,14 +26,17 @@ #include "networkd-netdev-veth.h" static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { - Veth *v = VETH(netdev); + Veth *v; int r; assert(netdev); assert(!link); - assert(v); assert(m); + v = VETH(netdev); + + assert(v); + r = sd_netlink_message_open_container(m, VETH_INFO_PEER); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append VETH_INFO_PEER attribute: %m"); @@ -58,13 +61,16 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlin } static int netdev_veth_verify(NetDev *netdev, const char *filename) { - Veth *v = VETH(netdev); + Veth *v; int r; assert(netdev); - assert(v); assert(filename); + v = VETH(netdev); + + assert(v); + if (!v->ifname_peer) { log_warning("Veth NetDev without peer name configured in %s. Ignoring", filename); @@ -84,9 +90,12 @@ static int netdev_veth_verify(NetDev *netdev, const char *filename) { } static void veth_done(NetDev *n) { - Veth *v = VETH(n); + Veth *v; assert(n); + + v = VETH(n); + assert(v); free(v->ifname_peer); diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c index 195d1a944e..75fbdd355e 100644 --- a/src/network/networkd-netdev-vlan.c +++ b/src/network/networkd-netdev-vlan.c @@ -24,14 +24,17 @@ #include "networkd-netdev-vlan.h" static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { - VLan *v = VLAN(netdev); + VLan *v; int r; assert(netdev); - assert(v); assert(link); assert(req); + v = VLAN(netdev); + + assert(v); + if (v->id <= VLANID_MAX) { r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id); if (r < 0) @@ -42,12 +45,15 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin } static int netdev_vlan_verify(NetDev *netdev, const char *filename) { - VLan *v = VLAN(netdev); + VLan *v; assert(netdev); - assert(v); assert(filename); + v = VLAN(netdev); + + assert(v); + if (v->id > VLANID_MAX) { log_warning("VLAN without valid Id (%"PRIu64") configured in %s. Ignoring", v->id, filename); return -EINVAL; diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index 03a599c0d4..755ad2f934 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -28,14 +28,16 @@ #include "missing.h" static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { - VxLan *v = VXLAN(netdev); + VxLan *v; int r; assert(netdev); - assert(v); assert(link); assert(m); + v = VXLAN(netdev); + + assert(v); if (v->id <= VXLAN_VID_MAX) { r = sd_netlink_message_append_u32(m, IFLA_VXLAN_ID, v->id); @@ -89,6 +91,12 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_AGEING attribute: %m"); } + if (v->max_fdb) { + r = sd_netlink_message_append_u32(m, IFLA_VXLAN_LIMIT, v->max_fdb); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LIMIT attribute: %m"); + } + r = sd_netlink_message_append_u8(m, IFLA_VXLAN_UDP_CSUM, v->udpcsum); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_CSUM attribute: %m"); @@ -162,9 +170,12 @@ static int netdev_vxlan_verify(NetDev *netdev, const char *filename) { } static void vxlan_init(NetDev *netdev) { - VxLan *v = VXLAN(netdev); + VxLan *v; assert(netdev); + + v = VXLAN(netdev); + assert(v); v->id = VXLAN_VID_MAX + 1; diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index 4ec33946cc..d21f355f5d 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -39,6 +39,7 @@ struct VxLan { unsigned tos; unsigned ttl; + unsigned max_fdb; usec_t fdb_ageing; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index 3d4865a780..dd0b400c6a 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -21,15 +21,19 @@ #include <net/if.h> +#include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" +#include "fd-util.h" #include "list.h" -#include "siphash24.h" #include "netlink-util.h" #include "network-internal.h" - -#include "networkd.h" #include "networkd-netdev.h" +#include "networkd.h" +#include "siphash24.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c index 5717a15327..120760a986 100644 --- a/src/network/networkd-network-bus.c +++ b/src/network/networkd-network-bus.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" - +#include "alloc-util.h" #include "networkd.h" +#include "string-util.h" +#include "strv.h" static int property_get_ether_addrs( sd_bus *bus, diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index b6f70e191d..de2c66d153 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -51,6 +51,8 @@ Network.IPForward, config_parse_address_family_boolean_with Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) +Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits) +Network.IPv6HopLimit, config_parse_int, 0, offsetof(Network, ipv6_hop_limit) Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) Address.Address, config_parse_address, 0, 0 Address.Peer, config_parse_address, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 5d22598fc0..29723a852f 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -22,15 +22,20 @@ #include <ctype.h> #include <net/if.h> +#include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" -#include "util.h" -#include "hostname-util.h" #include "dns-domain.h" +#include "fd-util.h" +#include "hostname-util.h" #include "network-internal.h" - -#include "networkd.h" #include "networkd-network.h" +#include "networkd.h" +#include "parse-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" static int network_load_one(Manager *manager, const char *filename) { _cleanup_network_free_ Network *network = NULL; @@ -121,6 +126,8 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; network->ipv6_accept_ra = -1; + network->ipv6_dad_transmits = -1; + network->ipv6_hop_limit = -1; r = config_parse(NULL, filename, file, "Match\0" @@ -326,12 +333,12 @@ int network_get(Manager *manager, struct udev_device *device, (void) safe_atou8(attr, &name_assign_type); if (name_assign_type == NET_NAME_ENUM) - log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname", - IFNAMSIZ, ifname, network->filename); + log_warning("%s: found matching network '%s', based on potentially unpredictable ifname", + ifname, network->filename); else - log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename); + log_debug("%s: found matching network '%s'", ifname, network->filename); } else - log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename); + log_debug("%s: found matching network '%s'", ifname, network->filename); *ret = network; return 0; @@ -346,6 +353,10 @@ int network_get(Manager *manager, struct udev_device *device, int network_apply(Manager *manager, Network *network, Link *link) { int r; + assert(manager); + assert(network); + assert(link); + link->network = network; if (network->ipv4ll_route) { @@ -355,7 +366,7 @@ int network_apply(Manager *manager, Network *network, Link *link) { if (r < 0) return r; - r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in); + r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in); if (r == 0) return -EINVAL; if (r < 0) @@ -364,14 +375,13 @@ int network_apply(Manager *manager, Network *network, Link *link) { route->family = AF_INET; route->dst_prefixlen = 16; route->scope = RT_SCOPE_LINK; - route->metrics = IPV4LL_ROUTE_METRIC; + route->priority = IPV4LL_ROUTE_METRIC; route->protocol = RTPROT_STATIC; } - if (network->dns || network->ntp) { - r = link_save(link); - if (r < 0) - return r; + if (network->dns || network->ntp || network->domains) { + manager_dirty(manager); + link_dirty(link); } return 0; diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 2a43b6b347..a27c67eea5 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -121,6 +121,8 @@ struct Network { bool ip_masquerade; int ipv6_accept_ra; + int ipv6_dad_transmits; + int ipv6_hop_limit; union in_addr_union ipv6_token; IPv6PrivacyExtensions ipv6_privacy_extensions; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index ee1ddd81fe..ed06c21160 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -19,15 +19,40 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" #include "conf-parser.h" +#include "event-util.h" +#include "in-addr-util.h" #include "netlink-util.h" - -#include "networkd.h" #include "networkd-route.h" +#include "networkd.h" +#include "parse-util.h" +#include "set.h" +#include "string-util.h" +#include "util.h" + +int route_new(Route **ret) { + _cleanup_route_free_ Route *route = NULL; + + route = new0(Route, 1); + if (!route) + return -ENOMEM; + + route->family = AF_UNSPEC; + route->scope = RT_SCOPE_UNIVERSE; + route->protocol = RTPROT_UNSPEC; + route->table = RT_TABLE_DEFAULT; + route->lifetime = USEC_INFINITY; + + *ret = route; + route = NULL; + + return 0; +} int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; + int r; if (section) { route = hashmap_get(network->routes_by_section, @@ -40,14 +65,11 @@ int route_new_static(Network *network, unsigned section, Route **ret) { } } - route = new0(Route, 1); - if (!route) - return -ENOMEM; + r = route_new(&route); + if (r < 0) + return r; - route->family = AF_UNSPEC; - route->scope = RT_SCOPE_UNIVERSE; route->protocol = RTPROT_STATIC; - route->network = network; LIST_PREPEND(routes, network->static_routes, route); @@ -64,23 +86,6 @@ int route_new_static(Network *network, unsigned section, Route **ret) { return 0; } -int route_new_dynamic(Route **ret, unsigned char rtm_protocol) { - _cleanup_route_free_ Route *route = NULL; - - route = new0(Route, 1); - if (!route) - return -ENOMEM; - - route->family = AF_UNSPEC; - route->scope = RT_SCOPE_UNIVERSE; - route->protocol = rtm_protocol; - - *ret = route; - route = NULL; - - return 0; -} - void route_free(Route *route) { if (!route) return; @@ -93,10 +98,241 @@ void route_free(Route *route) { UINT_TO_PTR(route->section)); } + if (route->link) { + set_remove(route->link->routes, route); + set_remove(route->link->routes_foreign, route); + } + + sd_event_source_unref(route->expire); + free(route); } -int route_drop(Route *route, Link *link, +static void route_hash_func(const void *b, struct siphash *state) { + const Route *route = b; + + assert(route); + + siphash24_compress(&route->family, sizeof(route->family), state); + + switch (route->family) { + case AF_INET: + case AF_INET6: + /* Equality of routes are given by the 4-touple + (dst_prefix,dst_prefixlen,tos,priority,table) */ + siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state); + siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state); + siphash24_compress(&route->tos, sizeof(route->tos), state); + siphash24_compress(&route->priority, sizeof(route->priority), state); + siphash24_compress(&route->table, sizeof(route->table), state); + + break; + default: + /* treat any other address family as AF_UNSPEC */ + break; + } +} + +static int route_compare_func(const void *_a, const void *_b) { + const Route *a = _a, *b = _b; + + if (a->family < b->family) + return -1; + if (a->family > b->family) + return 1; + + switch (a->family) { + case AF_INET: + case AF_INET6: + if (a->dst_prefixlen < b->dst_prefixlen) + return -1; + if (a->dst_prefixlen > b->dst_prefixlen) + return 1; + + if (a->tos < b->tos) + return -1; + if (a->tos > b->tos) + return 1; + + if (a->priority < b->priority) + return -1; + if (a->priority > b->priority) + return 1; + + if (a->table < b->table) + return -1; + if (a->table > b->table) + return 1; + + return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family)); + default: + /* treat any other address family as AF_UNSPEC */ + return 0; + } +} + +static const struct hash_ops route_hash_ops = { + .hash = route_hash_func, + .compare = route_compare_func +}; + +int route_get(Link *link, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, + Route **ret) { + Route route = { + .family = family, + .dst_prefixlen = dst_prefixlen, + .tos = tos, + .priority = priority, + .table = table, + }, *existing; + + assert(link); + assert(dst); + assert(ret); + + route.dst = *dst; + + existing = set_get(link->routes, &route); + if (existing) { + *ret = existing; + return 1; + } else { + existing = set_get(link->routes_foreign, &route); + if (!existing) + return -ENOENT; + } + + *ret = existing; + + return 0; +} + +static int route_add_internal(Link *link, Set **routes, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, Route **ret) { + _cleanup_route_free_ Route *route = NULL; + int r; + + assert(link); + assert(routes); + assert(dst); + + r = route_new(&route); + if (r < 0) + return r; + + route->family = family; + route->dst = *dst; + route->dst_prefixlen = dst_prefixlen; + route->tos = tos; + route->priority = priority; + route->table = table; + + r = set_ensure_allocated(routes, &route_hash_ops); + if (r < 0) + return r; + + r = set_put(*routes, route); + if (r < 0) + return r; + + route->link = link; + + if (ret) + *ret = route; + + route = NULL; + + return 0; +} + +int route_add_foreign(Link *link, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, Route **ret) { + return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret); +} + +int route_add(Link *link, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, Route **ret) { + Route *route; + int r; + + r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route); + if (r == -ENOENT) { + /* Route does not exist, create a new one */ + r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route); + if (r < 0) + return r; + } else if (r == 0) { + /* Take over a foreign route */ + r = set_ensure_allocated(&link->routes, &route_hash_ops); + if (r < 0) + return r; + + r = set_put(link->routes, route); + if (r < 0) + return r; + + set_remove(link->routes_foreign, route); + } else if (r == 1) { + /* Route exists, do nothing */ + ; + } else + return r; + + *ret = route; + + return 0; +} + +int route_update(Route *route, + union in_addr_union *src, + unsigned char src_prefixlen, + union in_addr_union *gw, + union in_addr_union *prefsrc, + unsigned char scope, + unsigned char protocol) { + assert(route); + assert(src); + assert(gw); + assert(prefsrc); + + route->src = *src; + route->src_prefixlen = src_prefixlen; + route->gw = *gw; + route->prefsrc = *prefsrc; + route->scope = scope; + route->protocol = protocol; + + return 0; +} + +void route_drop(Route *route) { + assert(route); + + route_free(route); +} + +int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; int r; @@ -113,20 +349,20 @@ int route_drop(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not create RTM_DELROUTE message: %m"); - if (!in_addr_is_null(route->family, &route->in_addr)) { + if (!in_addr_is_null(route->family, &route->gw)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); } if (route->dst_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST attribute: %m"); @@ -137,9 +373,9 @@ int route_drop(Route *route, Link *link, if (route->src_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST attribute: %m"); @@ -148,11 +384,11 @@ int route_drop(Route *route, Link *link, return log_error_errno(r, "Could not set source prefix length: %m"); } - if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { + if (!in_addr_is_null(route->family, &route->prefsrc)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m"); } @@ -161,7 +397,7 @@ int route_drop(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not set scope: %m"); - r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics); + r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); @@ -178,9 +414,24 @@ int route_drop(Route *route, Link *link, return 0; } +int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) { + Route *route = userdata; + int r; + + assert(route); + + r = route_remove(route, route->link, NULL); + if (r < 0) + log_warning_errno(r, "Could not remove route: %m"); + + return 1; +} + int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_event_source_unref_ sd_event_source *expire = NULL; + usec_t lifetime; int r; assert(link); @@ -195,20 +446,20 @@ int route_configure(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m"); - if (!in_addr_is_null(route->family, &route->in_addr)) { + if (!in_addr_is_null(route->family, &route->gw)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); } if (route->dst_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST attribute: %m"); @@ -219,9 +470,9 @@ int route_configure(Route *route, Link *link, if (route->src_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_SRC attribute: %m"); @@ -230,11 +481,11 @@ int route_configure(Route *route, Link *link, return log_error_errno(r, "Could not set source prefix length: %m"); } - if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { + if (!in_addr_is_null(route->family, &route->prefsrc)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m"); } @@ -243,10 +494,18 @@ int route_configure(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not set scope: %m"); - r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics); + r = sd_rtnl_message_route_set_flags(req, route->flags); + if (r < 0) + return log_error_errno(r, "Colud not set flags: %m"); + + r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); + r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref); + if (r < 0) + return log_error_errno(r, "Could not append RTA_PREF attribute: %m"); + r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex); if (r < 0) return log_error_errno(r, "Could not append RTA_OIF attribute: %m"); @@ -257,6 +516,26 @@ int route_configure(Route *route, Link *link, link_ref(link); + lifetime = route->lifetime; + + r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route); + if (r < 0) + return log_error_errno(r, "Could not add route: %m"); + + /* TODO: drop expiration handling once it can be pushed into the kernel */ + route->lifetime = lifetime; + + if (route->lifetime != USEC_INFINITY) { + r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), + route->lifetime, 0, route_expire_handler, route); + if (r < 0) + return log_error_errno(r, "Could not arm expiration timer: %m"); + } + + sd_event_source_unref(route->expire); + route->expire = expire; + expire = NULL; + return 0; } @@ -299,7 +578,7 @@ int config_parse_gateway(const char *unit, } n->family = f; - n->in_addr = buffer; + n->gw = buffer; n = NULL; return 0; @@ -339,7 +618,7 @@ int config_parse_preferred_src(const char *unit, } n->family = f; - n->prefsrc_addr = buffer; + n->prefsrc = buffer; n = NULL; return 0; @@ -413,10 +692,10 @@ int config_parse_destination(const char *unit, n->family = f; if (streq(lvalue, "Destination")) { - n->dst_addr = buffer; + n->dst = buffer; n->dst_prefixlen = prefixlen; } else if (streq(lvalue, "Source")) { - n->src_addr = buffer; + n->src = buffer; n->src_prefixlen = prefixlen; } else assert_not_reached(lvalue); @@ -450,9 +729,9 @@ int config_parse_route_priority(const char *unit, if (r < 0) return r; - r = config_parse_unsigned(unit, filename, line, section, - section_line, lvalue, ltype, - rvalue, &n->metrics, userdata); + r = config_parse_uint32(unit, filename, line, section, + section_line, lvalue, ltype, + rvalue, &n->priority, userdata); if (r < 0) return r; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index 11e94d44fb..b276756674 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -30,26 +30,43 @@ struct Route { Network *network; unsigned section; + Link *link; + int family; unsigned char dst_prefixlen; unsigned char src_prefixlen; unsigned char scope; - uint32_t metrics; unsigned char protocol; /* RTPROT_* */ + unsigned char tos; + uint32_t priority; /* note that ip(8) calls this 'metric' */ + unsigned char table; + unsigned char pref; + unsigned flags; + + union in_addr_union gw; + union in_addr_union dst; + union in_addr_union src; + union in_addr_union prefsrc; - union in_addr_union in_addr; - union in_addr_union dst_addr; - union in_addr_union src_addr; - union in_addr_union prefsrc_addr; + usec_t lifetime; + sd_event_source *expire; LIST_FIELDS(Route, routes); }; int route_new_static(Network *network, unsigned section, Route **ret); -int route_new_dynamic(Route **ret, unsigned char rtm_protocol); +int route_new(Route **ret); void route_free(Route *route); int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback); -int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback); +int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback); + +int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol); +void route_drop(Route *route); + +int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata); DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free); #define _cleanup_route_free_ _cleanup_(route_freep) diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index dde6b327ed..2545621a93 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -19,10 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "conf-parser.h" - #include "networkd-util.h" +#include "parse-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" const char *address_family_boolean_to_string(AddressFamilyBoolean b) { if (b == ADDRESS_FAMILY_YES || @@ -77,12 +79,20 @@ int config_parse_address_family_boolean_with_kernel( assert(rvalue); assert(data); + /* This function is mostly obsolete now. It simply redirects + * "kernel" to "no". In older networkd versions we used to + * distuingish IPForward=off from IPForward=kernel, where the + * former would explicitly turn off forwarding while the + * latter would simply not touch the setting. But that logic + * is gone, hence silently accept the old setting, but turn it + * to "no". */ + s = address_family_boolean_from_string(rvalue); if (s < 0) { if (streq(rvalue, "kernel")) - s = _ADDRESS_FAMILY_BOOLEAN_INVALID; + s = ADDRESS_FAMILY_NO; else { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForwarding= option, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForward= option, ignoring: %s", rvalue); return 0; } } diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c index cacb4c257e..c2779ff773 100644 --- a/src/network/networkd-wait-online-link.c +++ b/src/network/networkd-wait-online-link.c @@ -20,10 +20,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - #include "sd-network.h" +#include "alloc-util.h" #include "networkd-wait-online-link.h" +#include "string-util.h" int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) { _cleanup_(link_freep) Link *l = NULL; diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c index 112d92a568..0c40ab2bb8 100644 --- a/src/network/networkd-wait-online-manager.c +++ b/src/network/networkd-wait-online-manager.c @@ -23,14 +23,13 @@ #include <linux/if.h> #include <fnmatch.h> +#include "alloc-util.h" #include "netlink-util.h" - #include "network-internal.h" #include "networkd-wait-online-link.h" #include "networkd-wait-online.h" - -#include "util.h" #include "time-util.h" +#include "util.h" bool manager_ignore_link(Manager *m, Link *link) { char **ignore; diff --git a/src/network/networkd.c b/src/network/networkd.c index e6259043fa..ef394e0c04 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -20,9 +20,11 @@ ***/ #include "sd-daemon.h" -#include "capability.h" -#include "signal-util.h" + +#include "capability-util.h" #include "networkd.h" +#include "signal-util.h" +#include "user-util.h" int main(int argc, char *argv[]) { _cleanup_manager_free_ Manager *m = NULL; @@ -107,6 +109,12 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_rtnl_enumerate_routes(m); + if (r < 0) { + log_error_errno(r, "Could not enumerate routes: %m"); + goto out; + } + log_info("Enumeration completed"); sd_notify(false, diff --git a/src/network/networkd.h b/src/network/networkd.h index eea57ac158..97665fac7a 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -48,7 +48,10 @@ struct Manager { struct udev_monitor *udev_monitor; sd_event_source *udev_event_source; - bool enumerating; + bool enumerating:1; + bool dirty:1; + + Set *dirty_links; char *state_file; LinkOperationalState operational_state; @@ -79,9 +82,13 @@ bool manager_should_reload(Manager *m); int manager_rtnl_enumerate_links(Manager *m); int manager_rtnl_enumerate_addresses(Manager *m); +int manager_rtnl_enumerate_routes(Manager *m); + +int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata); +int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata); int manager_send_changed(Manager *m, const char *property, ...) _sentinel_; -int manager_save(Manager *m); +void manager_dirty(Manager *m); int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found); diff --git a/src/network/test-network.c b/src/network/test-network.c index 5909cc790e..dbed3795e3 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "networkd.h" #include "network-internal.h" #include "dhcp-lease-internal.h" @@ -143,8 +144,8 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) { static void test_address_equality(void) { _cleanup_address_free_ Address *a1 = NULL, *a2 = NULL; - assert_se(address_new_dynamic(&a1) >= 0); - assert_se(address_new_dynamic(&a2) >= 0); + assert_se(address_new(&a1) >= 0); + assert_se(address_new(&a2) >= 0); assert_se(address_equal(NULL, NULL)); assert_se(!address_equal(a1, NULL)); @@ -158,17 +159,18 @@ static void test_address_equality(void) { assert_se(address_equal(a1, a2)); assert_se(inet_pton(AF_INET, "192.168.3.9", &a1->in_addr.in)); - assert_se(address_equal(a1, a2)); + assert_se(!address_equal(a1, a2)); assert_se(inet_pton(AF_INET, "192.168.3.9", &a2->in_addr.in)); assert_se(address_equal(a1, a2)); + assert_se(inet_pton(AF_INET, "192.168.3.10", &a1->in_addr_peer.in)); + assert_se(address_equal(a1, a2)); + assert_se(inet_pton(AF_INET, "192.168.3.11", &a2->in_addr_peer.in)); + assert_se(address_equal(a1, a2)); a1->prefixlen = 10; assert_se(!address_equal(a1, a2)); a2->prefixlen = 10; assert_se(address_equal(a1, a2)); - assert_se(inet_pton(AF_INET, "192.168.3.10", &a2->in_addr.in)); - assert_se(address_equal(a1, a2)); - a1->family = AF_INET6; assert_se(!address_equal(a1, a2)); diff --git a/src/notify/notify.c b/src/notify/notify.c index 805ea1a627..b144554702 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -27,9 +27,12 @@ #include "sd-daemon.h" +#include "alloc-util.h" #include "env-util.h" #include "formats-util.h" #include "log.h" +#include "parse-util.h" +#include "string-util.h" #include "strv.h" #include "util.h" diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index c0e9ccd7a4..270bcf010f 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -21,13 +21,15 @@ #include <sys/mount.h> -#include "util.h" -#include "strv.h" -#include "mkdir.h" -#include "fileio.h" +#include "alloc-util.h" #include "cgroup-util.h" - +#include "fd-util.h" +#include "fileio.h" +#include "mkdir.h" #include "nspawn-cgroup.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" int chown_cgroup(pid_t pid, uid_t uid_shift) { _cleanup_free_ char *path = NULL, *fs = NULL; diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c index 3658f45381..38245434da 100644 --- a/src/nspawn/nspawn-expose-ports.c +++ b/src/nspawn/nspawn-expose-ports.c @@ -21,13 +21,17 @@ #include "sd-netlink.h" -#include "util.h" -#include "in-addr-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "firewall-util.h" +#include "in-addr-util.h" #include "local-addresses.h" #include "netlink-util.h" - #include "nspawn-expose-ports.h" +#include "parse-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" int expose_port_parse(ExposePort **l, const char *s) { diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index b5127a387c..58f9f4c635 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -15,24 +15,25 @@ struct ConfigPerfItem; %struct-type %includes %% -Exec.Boot, config_parse_tristate, 0, offsetof(Settings, boot) -Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters) -Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment) -Exec.User, config_parse_string, 0, offsetof(Settings, user) -Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability) -Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability) -Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal) -Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality) -Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id) -Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only) -Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode) -Files.Bind, config_parse_bind, 0, 0 -Files.BindReadOnly, config_parse_bind, 1, 0 -Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0 -Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network) -Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces) -Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan) -Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan) -Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth) -Network.Bridge, config_parse_string, 0, offsetof(Settings, network_bridge) -Network.Port, config_parse_expose_port, 0, 0 +Exec.Boot, config_parse_tristate, 0, offsetof(Settings, boot) +Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters) +Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment) +Exec.User, config_parse_string, 0, offsetof(Settings, user) +Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability) +Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability) +Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal) +Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality) +Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id) +Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only) +Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode) +Files.Bind, config_parse_bind, 0, 0 +Files.BindReadOnly, config_parse_bind, 1, 0 +Files.TemporaryFileSystem, config_parse_tmpfs, 0, 0 +Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network) +Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces) +Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan) +Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan) +Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth) +Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0 +Network.Bridge, config_parse_string, 0, offsetof(Settings, network_bridge) +Network.Port, config_parse_expose_port, 0, 0 diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 6c8b1d7a26..c8e627ac78 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -20,17 +20,25 @@ ***/ #include <sys/mount.h> +#include <linux/magic.h> -#include "util.h" -#include "rm-rf.h" -#include "strv.h" -#include "path-util.h" -#include "mkdir.h" -#include "label.h" -#include "set.h" +#include "alloc-util.h" #include "cgroup-util.h" - +#include "escape.h" +#include "fs-util.h" +#include "label.h" +#include "mkdir.h" +#include "mount-util.h" #include "nspawn-mount.h" +#include "parse-util.h" +#include "path-util.h" +#include "rm-rf.h" +#include "set.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t) { CustomMount *c, *ret; @@ -218,8 +226,19 @@ static int tmpfs_patch_options( int mount_sysfs(const char *dest) { const char *full, *top, *x; + int r; top = prefix_roota(dest, "/sys"); + r = path_check_fstype(top, SYSFS_MAGIC); + if (r < 0) + return log_error_errno(r, "Failed to determine filesystem type of %s: %m", top); + /* /sys might already be mounted as sysfs by the outer child in the + * !netns case. In this case, it's all good. Don't touch it because we + * don't have the right to do so, see https://github.com/systemd/systemd/issues/1555. + */ + if (r > 0) + return 0; + full = prefix_roota(top, "/full"); (void) mkdir(full, 0755); @@ -264,6 +283,7 @@ int mount_sysfs(const char *dest) { int mount_all(const char *dest, bool use_userns, bool in_userns, + bool use_netns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context) { @@ -274,21 +294,23 @@ int mount_all(const char *dest, const char *options; unsigned long flags; bool fatal; - bool userns; + bool in_userns; + bool use_netns; } MountPoint; static const MountPoint mount_table[] = { - { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true }, - { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true }, /* Bind mount first */ - { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true }, /* Then, make it r/o */ - { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false }, - { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false }, - { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false }, - { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false }, - { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false }, + { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true, false }, + { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true, false }, /* Bind mount first */ + { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true, false }, /* Then, make it r/o */ + { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, true }, + { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, false }, + { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false, false }, #ifdef HAVE_SELINUX - { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false }, /* Bind mount first */ - { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false }, /* Then, make it r/o */ + { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false, false }, /* Bind mount first */ + { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false, false }, /* Then, make it r/o */ #endif }; @@ -299,7 +321,10 @@ int mount_all(const char *dest, _cleanup_free_ char *where = NULL, *options = NULL; const char *o; - if (in_userns != mount_table[k].userns) + if (in_userns != mount_table[k].in_userns) + continue; + + if (!use_netns && mount_table[k].use_netns) continue; where = prefix_root(dest, mount_table[k].where); @@ -416,8 +441,7 @@ static int mount_bind(const char *dest, CustomMount *m) { if (r < 0) return log_error_errno(r, "Failed to make parents of %s: %m", where); } else { - log_error_errno(errno, "Failed to stat %s: %m", where); - return -errno; + return log_error_errno(errno, "Failed to stat %s: %m", where); } /* Create the mount point. Any non-directory file can be diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h index 54cab87665..bdab23bcca 100644 --- a/src/nspawn/nspawn-mount.h +++ b/src/nspawn/nspawn-mount.h @@ -57,7 +57,7 @@ int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s); int custom_mount_compare(const void *a, const void *b); -int mount_all(const char *dest, bool use_userns, bool in_userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); +int mount_all(const char *dest, bool use_userns, bool in_userns, bool use_netns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); int mount_sysfs(const char *dest); int mount_cgroups(const char *dest, bool unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 74abe5379a..c71552879d 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -22,20 +22,23 @@ #include <linux/veth.h> #include <net/if.h> +#include "libudev.h" #include "sd-id128.h" #include "sd-netlink.h" -#include "libudev.h" -#include "util.h" +#include "alloc-util.h" #include "ether-addr-util.h" -#include "siphash24.h" #include "netlink-util.h" +#include "siphash24.h" +#include "string-util.h" #include "udev-util.h" - +#include "util.h" #include "nspawn-network.h" #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1) #define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2) +#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66) +#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59) #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f) static int generate_mac( @@ -83,42 +86,32 @@ static int generate_mac( return 0; } -int setup_veth(const char *machine_name, - pid_t pid, - char iface_name[IFNAMSIZ], - bool bridge) { +static int add_veth( + sd_netlink *rtnl, + pid_t pid, + const char *ifname_host, + const struct ether_addr *mac_host, + const char *ifname_container, + const struct ether_addr *mac_container) { _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - struct ether_addr mac_host, mac_container; - int r, i; - - /* Use two different interface name prefixes depending whether - * we are in bridge mode or not. */ - snprintf(iface_name, IFNAMSIZ - 1, "%s-%s", - bridge ? "vb" : "ve", machine_name); - - r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0); - if (r < 0) - return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m"); - - r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0); - if (r < 0) - return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m"); + int r; - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); + assert(rtnl); + assert(ifname_host); + assert(mac_host); + assert(ifname_container); + assert(mac_container); r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0); if (r < 0) return log_error_errno(r, "Failed to allocate netlink message: %m"); - r = sd_netlink_message_append_string(m, IFLA_IFNAME, iface_name); + r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host); if (r < 0) return log_error_errno(r, "Failed to add netlink interface name: %m"); - r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_host); + r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host); if (r < 0) return log_error_errno(r, "Failed to add netlink MAC address: %m"); @@ -134,11 +127,11 @@ int setup_veth(const char *machine_name, if (r < 0) return log_error_errno(r, "Failed to open netlink container: %m"); - r = sd_netlink_message_append_string(m, IFLA_IFNAME, "host0"); + r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container); if (r < 0) return log_error_errno(r, "Failed to add netlink interface name: %m"); - r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_container); + r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container); if (r < 0) return log_error_errno(r, "Failed to add netlink MAC address: %m"); @@ -160,7 +153,44 @@ int setup_veth(const char *machine_name, r = sd_netlink_call(rtnl, m, 0, NULL); if (r < 0) - return log_error_errno(r, "Failed to add new veth interfaces (host0, %s): %m", iface_name); + return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container); + + return 0; +} + +int setup_veth(const char *machine_name, + pid_t pid, + char iface_name[IFNAMSIZ], + bool bridge) { + + _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + struct ether_addr mac_host, mac_container; + int r, i; + + assert(machine_name); + assert(pid > 0); + assert(iface_name); + + /* Use two different interface name prefixes depending whether + * we are in bridge mode or not. */ + snprintf(iface_name, IFNAMSIZ - 1, "%s-%s", + bridge ? "vb" : "ve", machine_name); + + r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m"); + + r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m"); + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container); + if (r < 0) + return r; i = (int) if_nametoindex(iface_name); if (i <= 0) @@ -169,6 +199,47 @@ int setup_veth(const char *machine_name, return i; } +int setup_veth_extra( + const char *machine_name, + pid_t pid, + char **pairs) { + + _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + uint64_t idx = 0; + char **a, **b; + int r; + + assert(machine_name); + assert(pid > 0); + + if (strv_isempty(pairs)) + return 0; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + STRV_FOREACH_PAIR(a, b, pairs) { + struct ether_addr mac_host, mac_container; + + r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m"); + + r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m"); + + r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container); + if (r < 0) + return r; + + idx ++; + } + + return 0; +} + int setup_bridge(const char *veth_name, const char *bridge_name) { _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; @@ -438,3 +509,34 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { return 0; } + +int veth_extra_parse(char ***l, const char *p) { + _cleanup_free_ char *a = NULL, *b = NULL; + int r; + + r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0 || isempty(a)) + return -EINVAL; + + r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0 || isempty(b)) { + free(b); + b = strdup(a); + if (!b) + return -ENOMEM; + } + + if (p) + return -EINVAL; + + r = strv_push_pair(l, a, b); + if (r < 0) + return -ENOMEM; + + a = b = NULL; + return 0; +} diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index 311e6d06cb..b86effef47 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -27,6 +27,7 @@ #include <stdbool.h> int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge); +int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs); int setup_bridge(const char *veth_name, const char *bridge_name); @@ -34,3 +35,5 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces); int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces); int move_network_interfaces(pid_t pid, char **ifaces); + +int veth_extra_parse(char ***l, const char *p); diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index b2776a61c2..374f958c20 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -21,12 +21,12 @@ #include "sd-bus.h" -#include "util.h" -#include "strv.h" -#include "bus-util.h" #include "bus-error.h" - +#include "bus-util.h" #include "nspawn-register.h" +#include "stat-util.h" +#include "strv.h" +#include "util.h" int register_machine( const char *machine_name, @@ -39,7 +39,8 @@ int register_machine( unsigned n_mounts, int kill_signal, char **properties, - bool keep_unit) { + bool keep_unit, + const char *service) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; @@ -61,7 +62,7 @@ int register_machine( "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), - "nspawn", + service, "container", (uint32_t) pid, strempty(directory), @@ -86,7 +87,7 @@ int register_machine( "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), - "nspawn", + service, "container", (uint32_t) pid, strempty(directory), diff --git a/src/nspawn/nspawn-register.h b/src/nspawn/nspawn-register.h index b27841ff59..d3bfd84e5e 100644 --- a/src/nspawn/nspawn-register.h +++ b/src/nspawn/nspawn-register.h @@ -27,5 +27,5 @@ #include "nspawn-mount.h" -int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit); +int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit, const char *service); int terminate_machine(pid_t pid); diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index b920391b38..d6b64d8d5a 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "conf-parser.h" -#include "strv.h" +#include "alloc-util.h" #include "cap-list.h" - +#include "conf-parser.h" +#include "nspawn-network.h" #include "nspawn-settings.h" +#include "process-util.h" +#include "strv.h" +#include "util.h" int settings_load(FILE *f, const char *path, Settings **ret) { _cleanup_(settings_freep) Settings *s = NULL; @@ -76,6 +78,7 @@ Settings* settings_free(Settings *s) { strv_free(s->network_interfaces); strv_free(s->network_macvlan); strv_free(s->network_ipvlan); + strv_free(s->network_veth_extra); free(s->network_bridge); expose_port_free_all(s->expose_ports); @@ -85,6 +88,27 @@ Settings* settings_free(Settings *s) { return NULL; } +bool settings_private_network(Settings *s) { + assert(s); + + return + s->private_network > 0 || + s->network_veth > 0 || + s->network_bridge || + s->network_interfaces || + s->network_macvlan || + s->network_ipvlan || + s->network_veth_extra; +} + +bool settings_network_veth(Settings *s) { + assert(s); + + return + s->network_veth > 0 || + s->network_bridge; +} + DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode"); int config_parse_expose_port( @@ -248,15 +272,33 @@ int config_parse_tmpfs( return 0; } - if (settings->network_bridge) - settings->network_veth = true; + return 0; +} - if (settings->network_interfaces || - settings->network_macvlan || - settings->network_ipvlan || - settings->network_bridge || - settings->network_veth) - settings->private_network = true; +int config_parse_veth_extra( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Settings *settings = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = veth_extra_parse(&settings->network_veth_extra, rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid extra virtual Ethernet link specification %s: %m", rvalue); + return 0; + } return 0; } diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 4cec40c1b7..dde0d8bd45 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -69,12 +69,16 @@ typedef struct Settings { char **network_interfaces; char **network_macvlan; char **network_ipvlan; + char **network_veth_extra; ExposePort *expose_ports; } Settings; int settings_load(FILE *f, const char *path, Settings **ret); Settings* settings_free(Settings *s); +bool settings_network_veth(Settings *s); +bool settings_private_network(Settings *s); + DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free); const struct ConfigPerfItem* nspawn_gperf_lookup(const char *key, unsigned length); @@ -85,3 +89,4 @@ int config_parse_expose_port(const char *unit, const char *filename, unsigned li int config_parse_volatile_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_tmpfs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_veth_extra(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn-setuid.c b/src/nspawn/nspawn-setuid.c index eda7f62900..aa6a16309c 100644 --- a/src/nspawn/nspawn-setuid.c +++ b/src/nspawn/nspawn-setuid.c @@ -19,16 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <grp.h> #include <sys/types.h> #include <unistd.h> -#include <grp.h> -#include "util.h" -#include "signal-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "mkdir.h" -#include "process-util.h" - #include "nspawn-setuid.h" +#include "process-util.h" +#include "signal-util.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" static int spawn_getent(const char *database, const char *key, pid_t *rpid) { int pipe_fds[2]; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index ab93f98df4..d2ce731c72 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -46,20 +46,23 @@ #include "sd-daemon.h" #include "sd-id128.h" +#include "alloc-util.h" #include "barrier.h" #include "base-filesystem.h" #include "blkid-util.h" #include "btrfs-util.h" #include "cap-list.h" -#include "capability.h" +#include "capability-util.h" #include "cgroup-util.h" #include "copy.h" #include "dev-setup.h" #include "env-util.h" #include "event-util.h" +#include "fd-util.h" #include "fdset.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" #include "gpt.h" #include "hostname-util.h" #include "log.h" @@ -68,7 +71,16 @@ #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" #include "netlink-util.h" +#include "nspawn-cgroup.h" +#include "nspawn-expose-ports.h" +#include "nspawn-mount.h" +#include "nspawn-network.h" +#include "nspawn-register.h" +#include "nspawn-settings.h" +#include "nspawn-setuid.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "ptyfwd.h" @@ -78,19 +90,17 @@ #include "seccomp-util.h" #endif #include "signal-util.h" +#include "socket-util.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "udev-util.h" +#include "umask-util.h" +#include "user-util.h" #include "util.h" -#include "nspawn-cgroup.h" -#include "nspawn-expose-ports.h" -#include "nspawn-mount.h" -#include "nspawn-network.h" -#include "nspawn-register.h" -#include "nspawn-settings.h" -#include "nspawn-setuid.h" - typedef enum ContainerStatus { CONTAINER_TERMINATED, CONTAINER_REBOOTED @@ -155,6 +165,7 @@ static char **arg_network_interfaces = NULL; static char **arg_network_macvlan = NULL; static char **arg_network_ipvlan = NULL; static bool arg_network_veth = false; +static char **arg_network_veth_extra = NULL; static char *arg_network_bridge = NULL; static unsigned long arg_personality = PERSONALITY_INVALID; static char *arg_image = NULL; @@ -168,6 +179,7 @@ static bool arg_unified_cgroup_hierarchy = false; static SettingsMask arg_settings_mask = 0; static int arg_settings_trusted = -1; static char **arg_parameters = NULL; +static const char *arg_container_service_name = "systemd-nspawn"; static void help(void) { printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" @@ -199,10 +211,13 @@ static void help(void) { " --network-ipvlan=INTERFACE\n" " Create a ipvlan network interface based on an\n" " existing network interface to the container\n" - " -n --network-veth Add a virtual ethernet connection between host\n" + " -n --network-veth Add a virtual Ethernet connection between host\n" " and container\n" + " --network-veth-extra=HOSTIF[:CONTAINERIF]\n" + " Add an additional virtual Ethernet link between\n" + " host and container\n" " --network-bridge=INTERFACE\n" - " Add a virtual ethernet connection between host\n" + " Add a virtual Ethernet connection between host\n" " and container and add it to an existing bridge on\n" " the host\n" " -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n" @@ -276,27 +291,6 @@ static int custom_mounts_prepare(void) { return 0; } -static int set_sanitized_path(char **b, const char *path) { - char *p; - - assert(b); - assert(path); - - p = canonicalize_file_name(path); - if (!p) { - if (errno != ENOENT) - return -errno; - - p = path_make_absolute_cwd(path); - if (!p) - return -ENOMEM; - } - - free(*b); - *b = path_kill_slashes(p); - return 0; -} - static int detect_unified_cgroup_hierarchy(void) { const char *e; int r; @@ -344,6 +338,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_NETWORK_MACVLAN, ARG_NETWORK_IPVLAN, ARG_NETWORK_BRIDGE, + ARG_NETWORK_VETH_EXTRA, ARG_PERSONALITY, ARG_VOLATILE, ARG_TEMPLATE, @@ -385,6 +380,7 @@ static int parse_argv(int argc, char *argv[]) { { "network-macvlan", required_argument, NULL, ARG_NETWORK_MACVLAN }, { "network-ipvlan", required_argument, NULL, ARG_NETWORK_IPVLAN }, { "network-veth", no_argument, NULL, 'n' }, + { "network-veth-extra", required_argument, NULL, ARG_NETWORK_VETH_EXTRA}, { "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE }, { "personality", required_argument, NULL, ARG_PERSONALITY }, { "image", required_argument, NULL, 'i' }, @@ -398,6 +394,7 @@ static int parse_argv(int argc, char *argv[]) { }; int c, r; + const char *p, *e; uint64_t plus = 0, minus = 0; bool mask_all_settings = false, mask_no_settings = false; @@ -416,24 +413,21 @@ static int parse_argv(int argc, char *argv[]) { return version(); case 'D': - r = set_sanitized_path(&arg_directory, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_directory); if (r < 0) - return log_error_errno(r, "Invalid root directory: %m"); - + return r; break; case ARG_TEMPLATE: - r = set_sanitized_path(&arg_template, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_template); if (r < 0) - return log_error_errno(r, "Invalid template directory: %m"); - + return r; break; case 'i': - r = set_sanitized_path(&arg_image, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_image); if (r < 0) - return log_error_errno(r, "Invalid image path: %m"); - + return r; break; case 'x': @@ -461,6 +455,15 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_NETWORK; break; + case ARG_NETWORK_VETH_EXTRA: + r = veth_extra_parse(&arg_network_veth_extra, optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --network-veth-extra= parameter: %s", optarg); + + arg_private_network = true; + arg_settings_mask |= SETTING_NETWORK; + break; + case ARG_NETWORK_INTERFACE: if (strv_extend(&arg_network_interfaces, optarg) < 0) return log_oom(); @@ -538,15 +541,16 @@ static int parse_argv(int argc, char *argv[]) { case ARG_CAPABILITY: case ARG_DROP_CAPABILITY: { - const char *state, *word; - size_t length; + p = optarg; + for(;;) { + _cleanup_free_ char *t = NULL; - FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) { - _cleanup_free_ char *t; + r = extract_first_word(&p, &t, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse capability %s.", t); - t = strndup(word, length); - if (!t) - return log_oom(); + if (r == 0) + break; if (streq(t, "all")) { if (c == ARG_CAPABILITY) @@ -921,6 +925,10 @@ static int parse_argv(int argc, char *argv[]) { if (r < 0) return r; + e = getenv("SYSTEMD_NSPAWN_CONTAINER_SERVICE"); + if (e) + arg_container_service_name = e; + return 1; } @@ -1189,6 +1197,7 @@ static int copy_devnodes(const char *dest) { static int setup_pts(const char *dest) { _cleanup_free_ char *options = NULL; const char *p; + int r; #ifdef HAVE_SELINUX if (arg_selinux_apifs_context) @@ -1211,20 +1220,23 @@ static int setup_pts(const char *dest) { return log_error_errno(errno, "Failed to create /dev/pts: %m"); if (mount("devpts", p, "devpts", MS_NOSUID|MS_NOEXEC, options) < 0) return log_error_errno(errno, "Failed to mount /dev/pts: %m"); - if (userns_lchown(p, 0, 0) < 0) - return log_error_errno(errno, "Failed to chown /dev/pts: %m"); + r = userns_lchown(p, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to chown /dev/pts: %m"); /* Create /dev/ptmx symlink */ p = prefix_roota(dest, "/dev/ptmx"); if (symlink("pts/ptmx", p) < 0) return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m"); - if (userns_lchown(p, 0, 0) < 0) - return log_error_errno(errno, "Failed to chown /dev/ptmx: %m"); + r = userns_lchown(p, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to chown /dev/ptmx: %m"); /* And fix /dev/pts/ptmx ownership */ p = prefix_roota(dest, "/dev/pts/ptmx"); - if (userns_lchown(p, 0, 0) < 0) - return log_error_errno(errno, "Failed to chown /dev/pts/ptmx: %m"); + r = userns_lchown(p, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to chown /dev/pts/ptmx: %m"); return 0; } @@ -1406,7 +1418,7 @@ static int setup_journal(const char *directory) { r = userns_mkdir(directory, p, 0755, 0, 0); if (r < 0) - log_warning_errno(errno, "Failed to create directory %s: %m", q); + log_warning_errno(r, "Failed to create directory %s: %m", q); return 0; } @@ -1420,15 +1432,11 @@ static int setup_journal(const char *directory) { if (errno == ENOTDIR) { log_error("%s already exists and is neither a symlink nor a directory", p); return r; - } else { - log_error_errno(errno, "Failed to remove %s: %m", p); - return -errno; - } + } else + return log_error_errno(errno, "Failed to remove %s: %m", p); } - } else if (r != -ENOENT) { - log_error_errno(errno, "readlink(%s) failed: %m", p); - return r; - } + } else if (r != -ENOENT) + return log_error_errno(r, "readlink(%s) failed: %m", p); if (arg_link_journal == LINK_GUEST) { @@ -1436,15 +1444,13 @@ static int setup_journal(const char *directory) { if (arg_link_journal_try) { log_debug_errno(errno, "Failed to symlink %s to %s, skipping journal setup: %m", q, p); return 0; - } else { - log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p); - return -errno; - } + } else + return log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p); } r = userns_mkdir(directory, p, 0755, 0, 0); if (r < 0) - log_warning_errno(errno, "Failed to create directory %s: %m", q); + log_warning_errno(r, "Failed to create directory %s: %m", q); return 0; } @@ -1456,10 +1462,8 @@ static int setup_journal(const char *directory) { if (arg_link_journal_try) { log_debug_errno(errno, "Failed to create %s, skipping journal setup: %m", p); return 0; - } else { - log_error_errno(errno, "Failed to create %s: %m", p); - return r; - } + } else + return log_error_errno(errno, "Failed to create %s: %m", p); } } else if (access(p, F_OK) < 0) @@ -1469,10 +1473,8 @@ static int setup_journal(const char *directory) { log_warning("%s is not empty, proceeding anyway.", q); r = userns_mkdir(directory, p, 0755, 0, 0); - if (r < 0) { - log_error_errno(errno, "Failed to create %s: %m", q); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to create %s: %m", q); if (mount(p, q, NULL, MS_BIND, NULL) < 0) return log_error_errno(errno, "Failed to bind mount journal from host into guest: %m"); @@ -1613,20 +1615,24 @@ finish: static int setup_propagate(const char *root) { const char *p, *q; + int r; (void) mkdir_p("/run/systemd/nspawn/", 0755); (void) mkdir_p("/run/systemd/nspawn/propagate", 0600); p = strjoina("/run/systemd/nspawn/propagate/", arg_machine); (void) mkdir_p(p, 0600); - if (userns_mkdir(root, "/run/systemd", 0755, 0, 0) < 0) - return log_error_errno(errno, "Failed to create /run/systemd: %m"); + r = userns_mkdir(root, "/run/systemd", 0755, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd: %m"); - if (userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0) < 0) - return log_error_errno(errno, "Failed to create /run/systemd/nspawn: %m"); + r = userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd/nspawn: %m"); - if (userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0) < 0) - return log_error_errno(errno, "Failed to create /run/systemd/nspawn/incoming: %m"); + r = userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd/nspawn/incoming: %m"); q = prefix_roota(root, "/run/systemd/nspawn/incoming"); if (mount(p, q, NULL, MS_BIND, NULL) < 0) @@ -1676,7 +1682,7 @@ static int setup_image(char **device_path, int *loop_nr) { } if (!S_ISREG(st.st_mode)) { - log_error_errno(errno, "%s is not a regular file or block device: %m", arg_image); + log_error("%s is not a regular file or block device.", arg_image); return -EINVAL; } @@ -1768,8 +1774,7 @@ static int dissect_image( if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to set device on blkid probe: %m"); - return -errno; + return log_error_errno(errno, "Failed to set device on blkid probe: %m"); } blkid_probe_enable_partitions(b, 1); @@ -1785,8 +1790,7 @@ static int dissect_image( } else if (r != 0) { if (errno == 0) errno = EIO; - log_error_errno(errno, "Failed to probe: %m"); - return -errno; + return log_error_errno(errno, "Failed to probe: %m"); } (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); @@ -1909,8 +1913,7 @@ static int dissect_image( if (!errno) errno = ENOMEM; - log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image); - return -errno; + return log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image); } qn = udev_device_get_devnum(q); @@ -2117,8 +2120,7 @@ static int mount_device(const char *what, const char *where, const char *directo if (!b) { if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to allocate prober for %s: %m", what); - return -errno; + return log_error_errno(errno, "Failed to allocate prober for %s: %m", what); } blkid_probe_enable_superblocks(b, 1); @@ -2132,8 +2134,7 @@ static int mount_device(const char *what, const char *where, const char *directo } else if (r != 0) { if (errno == 0) errno = EIO; - log_error_errno(errno, "Failed to probe %s: %m", what); - return -errno; + return log_error_errno(errno, "Failed to probe %s: %m", what); } errno = 0; @@ -2322,9 +2323,9 @@ static int determine_names(void) { } if (i->type == IMAGE_RAW) - r = set_sanitized_path(&arg_image, i->path); + r = free_and_strdup(&arg_image, i->path); else - r = set_sanitized_path(&arg_directory, i->path); + r = free_and_strdup(&arg_directory, i->path); if (r < 0) return log_error_errno(r, "Invalid image directory: %m"); @@ -2416,10 +2417,10 @@ static int inner_child( FDSet *fds) { _cleanup_free_ char *home = NULL; - unsigned n_env = 2; + unsigned n_env = 1; const char *envp[] = { "PATH=" DEFAULT_PATH_SPLIT_USR, - "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */ + NULL, /* container */ NULL, /* TERM */ NULL, /* HOME */ NULL, /* USER */ @@ -2450,7 +2451,7 @@ static int inner_child( } } - r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context); if (r < 0) return r; @@ -2497,8 +2498,9 @@ static int inner_child( rtnl_socket = safe_close(rtnl_socket); } - if (drop_capabilities() < 0) - return log_error_errno(errno, "drop_capabilities() failed: %m"); + r = drop_capabilities(); + if (r < 0) + return log_error_errno(r, "drop_capabilities() failed: %m"); setup_hostname(); @@ -2520,6 +2522,9 @@ static int inner_child( if (r < 0) return r; + /* LXC sets container=lxc, so follow the scheme here */ + envp[n_env++] = strjoina("container=", arg_container_service_name); + envp[n_env] = strv_find_prefix(environ, "TERM="); if (envp[n_env]) n_env ++; @@ -2598,8 +2603,9 @@ static int inner_child( execle("/bin/sh", "-sh", NULL, env_use); } + r = -errno; (void) log_open(); - return log_error_errno(errno, "execv() failed: %m"); + return log_error_errno(r, "execv() failed: %m"); } static int outer_child( @@ -2705,7 +2711,7 @@ static int outer_child( return log_error_errno(r, "Failed to make tree read-only: %m"); } - r = mount_all(directory, arg_userns, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); if (r < 0) return r; @@ -2840,7 +2846,7 @@ static int load_settings(void) { p = j; j = NULL; - /* By default we trust configuration from /etc and /run */ + /* By default, we trust configuration from /etc and /run */ if (arg_settings_trusted < 0) arg_settings_trusted = true; @@ -2870,7 +2876,7 @@ static int load_settings(void) { if (!f && errno != ENOENT) return log_error_errno(errno, "Failed to open %s: %m", p); - /* By default we do not trust configuration from /var/lib/machines */ + /* By default, we do not trust configuration from /var/lib/machines */ if (arg_settings_trusted < 0) arg_settings_trusted = false; } @@ -2912,11 +2918,17 @@ static int load_settings(void) { } if ((arg_settings_mask & SETTING_CAPABILITY) == 0) { + uint64_t plus; - if (!arg_settings_trusted && settings->capability != 0) - log_warning("Ignoring Capability= setting, file %s is not trusted.", p); - else - arg_retain |= settings->capability; + plus = settings->capability; + if (settings_private_network(settings)) + plus |= (1ULL << CAP_NET_ADMIN); + + if (!arg_settings_trusted && plus != 0) { + if (settings->capability != 0) + log_warning("Ignoring Capability= setting, file %s is not trusted.", p); + } else + arg_retain |= plus; arg_retain &= ~settings->drop_capability; } @@ -2967,11 +2979,15 @@ static int load_settings(void) { settings->network_bridge || settings->network_interfaces || settings->network_macvlan || - settings->network_ipvlan)) { + settings->network_ipvlan || + settings->network_veth_extra)) { if (!arg_settings_trusted) log_warning("Ignoring network settings, file %s is not trusted.", p); else { + arg_network_veth = settings_network_veth(settings); + arg_private_network = settings_private_network(settings); + strv_free(arg_network_interfaces); arg_network_interfaces = settings->network_interfaces; settings->network_interfaces = NULL; @@ -2984,13 +3000,13 @@ static int load_settings(void) { arg_network_ipvlan = settings->network_ipvlan; settings->network_ipvlan = NULL; + strv_free(arg_network_veth_extra); + arg_network_veth_extra = settings->network_veth_extra; + settings->network_veth_extra = NULL; + free(arg_network_bridge); arg_network_bridge = settings->network_bridge; settings->network_bridge = NULL; - - arg_network_veth = settings->network_veth > 0 || settings->network_bridge; - - arg_private_network = true; /* all these settings imply private networking */ } } @@ -3096,7 +3112,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); if (r < 0) { log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory); goto finish; @@ -3120,7 +3136,7 @@ int main(int argc, char *argv[]) { } if (arg_template) { - r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); if (r == -EEXIST) { if (!arg_quiet) log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template); @@ -3143,10 +3159,9 @@ int main(int argc, char *argv[]) { } else { const char *p; - p = strjoina(arg_directory, - argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/"); - if (access(p, F_OK) < 0) { - log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory); + p = strjoina(arg_directory, "/usr/"); + if (laccess(p, F_OK) < 0) { + log_error("Directory %s doesn't look like it has an OS tree. Refusing.", arg_directory); r = -EINVAL; goto finish; } @@ -3235,8 +3250,7 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, - uid_shift_socket_pair[2] = { -1, -1 }; + _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }; ContainerStatus container_status; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; static const struct sigaction sa = { @@ -3415,6 +3429,10 @@ int main(int argc, char *argv[]) { } } + r = setup_veth_extra(arg_machine, pid, arg_network_veth_extra); + if (r < 0) + goto finish; + r = setup_macvlan(arg_machine, pid, arg_network_macvlan); if (r < 0) goto finish; @@ -3435,7 +3453,8 @@ int main(int argc, char *argv[]) { arg_custom_mounts, arg_n_custom_mounts, arg_kill_signal, arg_property, - arg_keep_unit); + arg_keep_unit, + arg_container_service_name); if (r < 0) goto finish; } @@ -3591,7 +3610,7 @@ finish: if (remove_subvol && arg_directory) { int k; - k = btrfs_subvol_remove(arg_directory, true); + k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (k < 0) log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory); } @@ -3615,6 +3634,7 @@ finish: strv_free(arg_network_interfaces); strv_free(arg_network_macvlan); strv_free(arg_network_ipvlan); + strv_free(arg_network_veth_extra); strv_free(arg_parameters); custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts); expose_port_free_all(arg_expose_ports); diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 0dca891447..ee10b105ea 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -19,17 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <nss.h> -#include <netdb.h> #include <errno.h> -#include <string.h> #include <net/if.h> +#include <netdb.h> +#include <nss.h> #include <stdlib.h> +#include <string.h> +#include "alloc-util.h" +#include "hostname-util.h" #include "local-addresses.h" #include "macro.h" #include "nss-util.h" -#include "hostname-util.h" +#include "string-util.h" #include "util.h" /* We use 127.0.0.2 as IPv4 address. This has the advantage over diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 604130ed25..969fa9619e 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -19,18 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <nss.h> #include <netdb.h> +#include <nss.h> #include "sd-bus.h" #include "sd-login.h" -#include "macro.h" -#include "util.h" -#include "nss-util.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-common-errors.h" -#include "in-addr-util.h" +#include "bus-util.h" #include "hostname-util.h" +#include "in-addr-util.h" +#include "macro.h" +#include "nss-util.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); NSS_GETPW_PROTOTYPES(mymachines); diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index ef5eb7b4cf..ed59a71e3d 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -19,20 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <nss.h> -#include <netdb.h> +#include <dlfcn.h> #include <errno.h> -#include <string.h> +#include <netdb.h> +#include <nss.h> #include <stdlib.h> -#include <dlfcn.h> +#include <string.h> #include "sd-bus.h" -#include "bus-util.h" + #include "bus-common-errors.h" +#include "bus-util.h" +#include "in-addr-util.h" #include "macro.h" #include "nss-util.h" +#include "string-util.h" #include "util.h" -#include "in-addr-util.h" NSS_GETHOSTBYNAME_PROTOTYPES(resolve); NSS_GETHOSTBYADDR_PROTOTYPES(resolve); diff --git a/src/path/path.c b/src/path/path.c index 73b7bd2c01..0ece72f6fe 100644 --- a/src/path/path.c +++ b/src/path/path.c @@ -26,8 +26,10 @@ #include "sd-path.h" +#include "alloc-util.h" #include "log.h" #include "macro.h" +#include "string-util.h" #include "util.h" static const char *arg_suffix = NULL; diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index cf6a239402..dc2911e4e8 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -19,15 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdbool.h> #include <errno.h> -#include <unistd.h> +#include <stdbool.h> +#include <stdio.h> #include <sys/prctl.h> +#include <unistd.h> -#include "util.h" #include "process-util.h" #include "signal-util.h" +#include "string-util.h" +#include "util.h" +#include "proc-cmdline.h" static bool arg_skip = false; static bool arg_force = false; diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c index f4778fc16a..d857ade36a 100644 --- a/src/random-seed/random-seed.c +++ b/src/random-seed/random-seed.c @@ -19,15 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <fcntl.h> #include <errno.h> +#include <fcntl.h> #include <string.h> #include <sys/stat.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "log.h" -#include "util.h" #include "mkdir.h" +#include "string-util.h" +#include "util.h" #define POOL_SIZE_MIN 512 diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c index d4e6ba4bf9..6ecadbf3e5 100644 --- a/src/rc-local-generator/rc-local-generator.c +++ b/src/rc-local-generator/rc-local-generator.c @@ -24,9 +24,11 @@ #include <stdio.h> #include <unistd.h> +#include "alloc-util.h" #include "log.h" -#include "util.h" #include "mkdir.h" +#include "string-util.h" +#include "util.h" #ifndef RC_LOCAL_SCRIPT_PATH_START #define RC_LOCAL_SCRIPT_PATH_START "/etc/rc.d/rc.local" @@ -60,8 +62,7 @@ static int add_symlink(const char *service, const char *where) { if (errno == EEXIST) return 0; - log_error_errno(errno, "Failed to create symlink %s: %m", to); - return -errno; + return log_error_errno(errno, "Failed to create symlink %s: %m", to); } return 1; diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index f904e48e75..57f99c9ef0 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -26,12 +26,13 @@ #include <sys/wait.h> #include <mntent.h> +#include "exit-status.h" #include "log.h" -#include "util.h" +#include "mount-setup.h" +#include "mount-util.h" #include "path-util.h" #include "signal-util.h" -#include "mount-setup.h" -#include "exit-status.h" +#include "util.h" /* Goes through /etc/fstab and remounts all API file systems, applying * options that are in /etc/fstab that systemd might not have diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c index d0d61b98ed..166ab470ed 100644 --- a/src/reply-password/reply-password.c +++ b/src/reply-password/reply-password.c @@ -19,14 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <string.h> #include <errno.h> -#include <sys/un.h> #include <stddef.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "fd-util.h" #include "log.h" #include "macro.h" +#include "string-util.h" #include "util.h" static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) { @@ -50,9 +52,10 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s } int main(int argc, char *argv[]) { - int fd = -1, r = EXIT_FAILURE; + _cleanup_close_ int fd = -1; char packet[LINE_MAX]; size_t length; + int r; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); @@ -60,14 +63,14 @@ int main(int argc, char *argv[]) { if (argc != 3) { log_error("Wrong number of arguments."); - goto finish; + return EXIT_FAILURE; } if (streq(argv[1], "1")) { packet[0] = '+'; if (!fgets(packet+1, sizeof(packet)-1, stdin)) { - log_error_errno(errno, "Failed to read password: %m"); + r = log_error_errno(errno, "Failed to read password: %m"); goto finish; } @@ -78,22 +81,20 @@ int main(int argc, char *argv[]) { length = 1; } else { log_error("Invalid first argument %s", argv[1]); + r = -EINVAL; goto finish; } fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (fd < 0) { - log_error_errno(errno, "socket() failed: %m"); + r = log_error_errno(errno, "socket() failed: %m"); goto finish; } - if (send_on_socket(fd, argv[2], packet, length) < 0) - goto finish; - - r = EXIT_SUCCESS; + r = send_on_socket(fd, argv[2], packet, length); finish: - safe_close(fd); + memory_erase(packet, sizeof(packet)); - return r; + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c index 97516a87a8..432e62dd9f 100644 --- a/src/resolve-host/resolve-host.c +++ b/src/resolve-host/resolve-host.c @@ -25,9 +25,11 @@ #include "sd-bus.h" #include "af-list.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "in-addr-util.h" +#include "parse-util.h" #include "resolved-def.h" #include "resolved-dns-packet.h" @@ -298,8 +300,7 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres percent = strchr(s, '%'); if (percent) { - r = safe_atoi(percent+1, &ifi); - if (r < 0 || ifi <= 0) { + if (parse_ifindex(percent+1, &ifi) < 0) { ifi = if_nametoindex(percent+1); if (ifi <= 0) return -EINVAL; @@ -519,7 +520,7 @@ static int parse_argv(int argc, char *argv[]) { case 'i': { int ifi; - if (safe_atoi(optarg, &ifi) >= 0 && ifi > 0) + if (parse_ifindex(optarg, &ifi) >= 0) arg_ifindex = ifi; else { ifi = if_nametoindex(optarg); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index bf1b7c8ab4..f0a3b607d4 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-util.h" - #include "dns-domain.h" #include "resolved-bus.h" #include "resolved-def.h" diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index cc8d5fa76a..9207719551 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -19,13 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "conf-parser.h" - +#include "def.h" +#include "extract-word.h" +#include "parse-util.h" #include "resolved-conf.h" +#include "string-util.h" int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) { - const char *word, *state; - size_t length; DnsServer *first; int r; @@ -34,19 +36,22 @@ int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers; - FOREACH_WORD_QUOTED(word, length, string, state) { - char buffer[length+1]; - int family; + for(;;) { + _cleanup_free_ char *word = NULL; union in_addr_union addr; bool found = false; DnsServer *s; + int family; - memcpy(buffer, word, length); - buffer[length] = 0; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse resolved dns server syntax \"%s\": %m", string); + if (r == 0) + break; - r = in_addr_from_string_auto(buffer, &family, &addr); + r = in_addr_from_string_auto(word, &family, &addr); if (r < 0) { - log_warning("Ignoring invalid DNS address '%s'", buffer); + log_warning("Ignoring invalid DNS address '%s'", word); continue; } @@ -92,7 +97,7 @@ int config_parse_dnsv( /* Empty assignment means clear the list */ manager_flush_dns_servers(m, ltype); else { - /* Otherwise add to the list */ + /* Otherwise, add to the list */ r = manager_parse_dns_server(m, ltype, rvalue); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue); @@ -145,8 +150,8 @@ int config_parse_support( int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many("/etc/systemd/resolved.conf", - CONF_DIRS_NULSTR("systemd/resolved.conf"), + return config_parse_many(PKGSYSCONFDIR "/resolved.conf", + CONF_PATHS_NULSTR("systemd/resolved.conf.d"), "Resolve\0", config_item_perf_lookup, resolved_gperf_lookup, false, m); diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 89b9b0e1ea..3cf9c68074 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "resolved-dns-answer.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "resolved-dns-answer.h" +#include "string-util.h" DnsAnswer *dns_answer_new(unsigned n) { DnsAnswer *a; diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index ab13636bc1..04f64022e0 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "resolved-dns-cache.h" #include "resolved-dns-packet.h" diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index bebd1ee4a6..f23b3cf893 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "utf8.h" -#include "util.h" -#include "strv.h" -#include "unaligned.h" +#include "alloc-util.h" #include "dns-domain.h" #include "resolved-dns-packet.h" +#include "string-table.h" +#include "strv.h" +#include "unaligned.h" +#include "utf8.h" +#include "util.h" int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 4b1d18b2ef..f7cb84e2a6 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "hostname-util.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "hostname-util.h" #include "local-addresses.h" - #include "resolved-dns-query.h" /* How long to wait for the query in total */ diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c index 1507f22da0..48951221dc 100644 --- a/src/resolve/resolved-dns-question.c +++ b/src/resolve/resolved-dns-question.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "resolved-dns-question.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "resolved-dns-question.h" DnsQuestion *dns_question_new(unsigned n) { DnsQuestion *q; diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 2bc8cc1639..ba2ea686f3 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -21,12 +21,14 @@ #include <math.h> -#include "strv.h" - +#include "alloc-util.h" #include "dns-domain.h" -#include "resolved-dns-rr.h" -#include "resolved-dns-packet.h" #include "dns-type.h" +#include "hexdecoct.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" +#include "string-util.h" +#include "strv.h" DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) { DnsResourceKey *k; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 9e6f595a1b..b15370b017 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -21,15 +21,17 @@ #include <netinet/tcp.h> -#include "missing.h" -#include "strv.h" -#include "socket-util.h" #include "af-list.h" -#include "random-util.h" -#include "hostname-util.h" +#include "alloc-util.h" #include "dns-domain.h" -#include "resolved-llmnr.h" +#include "fd-util.h" +#include "hostname-util.h" +#include "missing.h" +#include "random-util.h" #include "resolved-dns-scope.h" +#include "resolved-llmnr.h" +#include "socket-util.h" +#include "strv.h" #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC) #define MULTICAST_RATELIMIT_BURST 1000 diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 8693911e65..e803f635ab 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "siphash24.h" - +#include "alloc-util.h" #include "resolved-dns-server.h" +#include "siphash24.h" /* After how much time to repeat classic DNS requests */ #define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC) diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index 7f47e7223a..1c501182fb 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -21,6 +21,9 @@ #include <netinet/tcp.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "missing.h" #include "resolved-dns-stream.h" diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index b30473dd7e..6545f6cd8a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -20,11 +20,13 @@ ***/ #include "af-list.h" - -#include "resolved-llmnr.h" -#include "resolved-dns-transaction.h" -#include "random-util.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "fd-util.h" +#include "random-util.h" +#include "resolved-dns-transaction.h" +#include "resolved-llmnr.h" +#include "string-table.h" DnsTransaction* dns_transaction_free(DnsTransaction *t) { DnsQuery *q; diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 8a59bd1c3c..48dcf76daa 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "list.h" - -#include "resolved-dns-zone.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "list.h" #include "resolved-dns-packet.h" +#include "resolved-dns-zone.h" +#include "string-util.h" /* Never allow more than 1K entries */ #define ZONE_MAX 1024 diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index b9fd8e3dbc..2892641075 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -22,9 +22,13 @@ #include <net/if.h> #include "sd-network.h" -#include "strv.h" + +#include "alloc-util.h" #include "missing.h" +#include "parse-util.h" #include "resolved-link.h" +#include "string-util.h" +#include "strv.h" int link_new(Manager *m, Link **ret, int ifindex) { _cleanup_(link_freep) Link *l = NULL; diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 8afaf8db6e..5c3a4a00c3 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -22,8 +22,9 @@ #include <resolv.h> #include <netinet/in.h> -#include "resolved-manager.h" +#include "fd-util.h" #include "resolved-llmnr.h" +#include "resolved-manager.h" void manager_llmnr_stop(Manager *m) { assert(m); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index de924e3ed9..a588538b52 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -19,26 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <netinet/in.h> +#include <poll.h> #include <resolv.h> #include <sys/ioctl.h> -#include <poll.h> -#include <netinet/in.h> -#include "netlink-util.h" -#include "network-internal.h" -#include "socket-util.h" #include "af-list.h" -#include "utf8.h" +#include "alloc-util.h" +#include "dns-domain.h" +#include "fd-util.h" #include "fileio-label.h" +#include "hostname-util.h" +#include "io-util.h" +#include "netlink-util.h" +#include "network-internal.h" #include "ordered-set.h" +#include "parse-util.h" #include "random-util.h" -#include "hostname-util.h" - -#include "dns-domain.h" -#include "resolved-conf.h" #include "resolved-bus.h" -#include "resolved-manager.h" +#include "resolved-conf.h" #include "resolved-llmnr.h" +#include "resolved-manager.h" +#include "socket-util.h" +#include "string-table.h" +#include "string-util.h" +#include "utf8.h" #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC) diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 32e61af925..7ba0546f4a 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -19,15 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-event.h" #include "sd-daemon.h" +#include "sd-event.h" + +#include "capability-util.h" #include "mkdir.h" -#include "capability.h" +#include "resolved-conf.h" +#include "resolved-manager.h" #include "selinux-util.h" #include "signal-util.h" - -#include "resolved-manager.h" -#include "resolved-conf.h" +#include "user-util.h" int main(int argc, char *argv[]) { _cleanup_(manager_freep) Manager *m = NULL; diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index d8a2f3694e..5c45a3ae6c 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -25,8 +25,16 @@ #include "libudev.h" #include "sd-daemon.h" +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" #include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "string-table.h" +#include "string-util.h" #include "udev-util.h" #include "util.h" @@ -40,8 +48,8 @@ static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = { [RFKILL_TYPE_WIMAX] = "wimax", [RFKILL_TYPE_WWAN] = "wwan", [RFKILL_TYPE_GPS] = "gps", - [RFKILL_TYPE_FM] "fm", - [RFKILL_TYPE_NFC] "nfc", + [RFKILL_TYPE_FM] = "fm", + [RFKILL_TYPE_NFC] = "nfc", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int); @@ -204,7 +212,7 @@ static int load_state( assert(udev); assert(event); - if (!shall_restore_state()) + if (shall_restore_state() == 0) return 0; r = find_device(udev, event, &device); diff --git a/src/run/run.c b/src/run/run.c index 93d8cd1d08..38a482bb11 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -25,11 +25,13 @@ #include "sd-bus.h" #include "sd-event.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" #include "calendarspec.h" #include "env-util.h" #include "event-util.h" +#include "fd-util.h" #include "formats-util.h" #include "path-util.h" #include "ptyfwd.h" @@ -38,6 +40,8 @@ #include "strv.h" #include "terminal-util.h" #include "unit-name.h" +#include "user-util.h" +#include "parse-util.h" static bool arg_ask_password = true; static bool arg_scope = false; @@ -1153,14 +1157,15 @@ int main(int argc, char* argv[]) { if (r <= 0) goto finish; - if (argc > optind) { - r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command); + if (argc > optind && arg_transport == BUS_TRANSPORT_LOCAL) { + /* Patch in an absolute path */ + + r = find_binary(argv[optind], &command); if (r < 0) { - log_error_errno(r, "Failed to find executable %s%s: %m", - argv[optind], - arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system"); + log_error_errno(r, "Failed to find executable %s: %m", argv[optind]); goto finish; } + argv[optind] = command; } diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index bd8c988751..79f5a60579 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -22,9 +22,12 @@ #include <errno.h> #include <stdbool.h> +#include "alloc-util.h" #include "acl-util.h" -#include "util.h" +#include "string-util.h" #include "strv.h" +#include "user-util.h" +#include "util.h" int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { acl_entry_t i; diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 64e50401b9..8e36067f74 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -19,16 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <fcntl.h> #include <stdint.h> +#include <stdio.h> #include <string.h> #include <unistd.h> -#include <fcntl.h> -#include <util.h> -#include <fileio.h> -#include <time-util.h> -#include <acpi-fpdt.h> +#include "alloc-util.h" +#include "acpi-fpdt.h" +#include "fd-util.h" +#include "fileio.h" +#include "time-util.h" +#include "util.h" struct acpi_table_header { char signature[4]; diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c index c2bbd330bd..f6ac43adfe 100644 --- a/src/shared/apparmor-util.c +++ b/src/shared/apparmor-util.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "util.h" -#include "fileio.h" +#include "alloc-util.h" #include "apparmor-util.h" +#include "fileio.h" +#include "parse-util.h" +#include "util.h" bool mac_apparmor_use(void) { static int cached_use = -1; diff --git a/src/shared/architecture.c b/src/shared/architecture.c index 8e72e7a36a..e2efa4272b 100644 --- a/src/shared/architecture.c +++ b/src/shared/architecture.c @@ -21,6 +21,8 @@ #include <sys/utsname.h> +#include "string-table.h" +#include "string-util.h" #include "architecture.h" int uname_architecture(void) { diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index f8cf11b297..fbe2b6fecb 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -32,16 +32,22 @@ #include <termios.h> #include <unistd.h> +#include "alloc-util.h" +#include "ask-password-api.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "io-util.h" #include "missing.h" #include "mkdir.h" #include "random-util.h" #include "signal-util.h" #include "socket-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" +#include "umask-util.h" #include "util.h" -#include "ask-password-api.h" #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2) @@ -78,6 +84,7 @@ static int retrieve_key(key_serial_t serial, char ***ret) { if (n < m) break; + memory_erase(p, n); free(p); m *= 2; } @@ -86,12 +93,14 @@ static int retrieve_key(key_serial_t serial, char ***ret) { if (!l) return -ENOMEM; + memory_erase(p, n); + *ret = l; return 0; } static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) { - _cleanup_strv_free_ char **l = NULL; + _cleanup_strv_free_erase_ char **l = NULL; _cleanup_free_ char *p = NULL; key_serial_t serial; size_t n; @@ -124,6 +133,7 @@ static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **pa assert(p[n-1] == 0); serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING); + memory_erase(p, n); if (serial == -1) return -errno; @@ -361,9 +371,12 @@ int ask_password_tty( dirty = true; } + + c = 'x'; } x = strndup(passphrase, p); + memory_erase(passphrase, p); if (!x) { r = -ENOMEM; goto finish; @@ -459,7 +472,7 @@ int ask_password_agent( fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC); if (fd < 0) { - r = -errno; + r = fd; goto finish; } @@ -620,6 +633,7 @@ int ask_password_agent( l = strv_new("", NULL); else l = strv_parse_nulstr(passphrase+1, n-1); + memory_erase(passphrase, n); if (!l) { r = -ENOMEM; goto finish; @@ -688,9 +702,12 @@ int ask_password_auto( if (r < 0) return r; - r = strv_consume(&l, s); - if (r < 0) + r = strv_push(&l, s); + if (r < 0) { + string_erase(s); + free(s); return -ENOMEM; + } *ret = l; return 0; diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c index 48492ed13d..e605490c32 100644 --- a/src/shared/base-filesystem.c +++ b/src/shared/base-filesystem.c @@ -20,13 +20,18 @@ ***/ #include <errno.h> -#include <sys/stat.h> #include <stdlib.h> +#include <sys/stat.h> #include <unistd.h> +#include "alloc-util.h" #include "base-filesystem.h" +#include "fd-util.h" #include "log.h" #include "macro.h" +#include "string-util.h" +#include "umask-util.h" +#include "user-util.h" #include "util.h" typedef struct BaseFilesystem { diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 52ec7eee7f..73ceeba18f 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -21,27 +21,39 @@ #include <sys/socket.h> +#include "sd-bus.h" #include "sd-daemon.h" #include "sd-event.h" -#include "sd-bus.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-internal.h" #include "bus-label.h" #include "bus-message.h" +#include "bus-util.h" #include "cgroup-util.h" #include "def.h" +#include "env-util.h" +#include "escape.h" +#include "fd-util.h" #include "macro.h" #include "missing.h" +#include "parse-util.h" #include "path-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "rlimit-util.h" #include "set.h" #include "signal-util.h" +#include "stdio-util.h" +#include "string-util.h" #include "strv.h" +#include "syslog-util.h" #include "unit-name.h" +#include "user-util.h" +#include "utf8.h" #include "util.h" -#include "bus-util.h" - static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { sd_event *e = userdata; @@ -1416,6 +1428,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return bus_log_create_error(r); return 0; + } else if (streq(field, "EnvironmentFile")) { + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "EnvironmentFiles"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "v", "a(sb)", 1, + eq[0] == '-' ? eq + 1 : eq, + eq[0] == '-'); + if (r < 0) + return r; + return 0; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); @@ -1427,7 +1450,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", - "SyslogLevelPrefix")) { + "SyslogLevelPrefix", "Delegate")) { r = parse_boolean(eq); if (r < 0) { @@ -1494,10 +1517,33 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath", "StandardInput", "StandardOutput", "StandardError", "Description", "Slice", "Type", "WorkingDirectory", - "RootDirectory", "SyslogIdentifier")) + "RootDirectory", "SyslogIdentifier", "ProtectSystem", + "ProtectHome")) r = sd_bus_message_append(m, "v", "s", eq); - else if (streq(field, "DeviceAllow")) { + else if (streq(field, "SyslogLevel")) { + int level; + + level = log_level_from_string(eq); + if (level < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", level); + + } else if (streq(field, "SyslogFacility")) { + int facility; + + facility = log_facility_unshifted_from_string(eq); + if (facility < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", facility); + + } else if (streq(field, "DeviceAllow")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(ss)", 0); @@ -1608,9 +1654,52 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "i", i); - } else if (streq(field, "Environment")) { + } else if (STR_IN_SET(field, "Environment", "PassEnvironment")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; - r = sd_bus_message_append(m, "v", "as", 1, eq); + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); + if (r < 0) { + log_error("Failed to parse Environment value %s", eq); + return -EINVAL; + } + if (r == 0) + break; + + if (streq(field, "Environment")) { + if (!env_assignment_is_valid(word)) { + log_error("Invalid environment assignment: %s", word); + return -EINVAL; + } + } else { /* PassEnvironment */ + if (!env_name_is_valid(word)) { + log_error("Invalid environment variable name: %s", word); + return -EINVAL; + } + } + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); } else if (streq(field, "KillSignal")) { int sig; @@ -1633,6 +1722,113 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } r = sd_bus_message_append(m, "v", "t", u); + } else if (streq(field, "TimerSlackNSec")) { + nsec_t n; + + r = parse_nsec(eq, &n); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", n); + } else if (streq(field, "OOMScoreAdjust")) { + int oa; + + r = safe_atoi(eq, &oa); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + if (!oom_score_adjust_is_valid(oa)) { + log_error("OOM score adjust value out of range"); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", oa); + } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + int offset; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + if (r == 0) + break; + + if (!utf8_is_valid(word)) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + offset = word[0] == '-'; + if (!path_is_absolute(word + offset)) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + path_kill_slashes(word + offset); + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + + } else if (streq(field, "RuntimeDirectory")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s", field, eq); + + if (r == 0) + break; + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); } else { log_error("Unknown assignment %s.", assignment); @@ -2138,3 +2334,42 @@ bool is_kdbus_available(void) { return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0; } + +int bus_property_get_rlimit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + struct rlimit *rl; + uint64_t u; + rlim_t x; + + assert(bus); + assert(reply); + assert(userdata); + + rl = *(struct rlimit**) userdata; + if (rl) + x = rl->rlim_max; + else { + struct rlimit buf = {}; + int z; + + z = rlimit_from_string(strstr(property, "Limit")); + assert(z >= 0); + + getrlimit(z, &buf); + x = buf.rlim_max; + } + + /* rlim_t might have different sizes, let's map + * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on + * all archs */ + u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x; + + return sd_bus_message_append(reply, "t", u); +} diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index f03f951dc7..3925c10fde 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -21,10 +21,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-event.h" #include "sd-bus.h" +#include "sd-event.h" + #include "hashmap.h" #include "install.h" +#include "string-util.h" #include "time-util.h" typedef enum BusTransport { @@ -200,3 +202,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send bool is_kdbus_wanted(void); bool is_kdbus_available(void); + +int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 31b4f6c684..129ffc7056 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -19,19 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <string.h> #include <dirent.h> #include <errno.h> +#include <stdio.h> +#include <string.h> -#include "util.h" +#include "alloc-util.h" +#include "cgroup-show.h" +#include "cgroup-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "process-util.h" +#include "locale-util.h" #include "macro.h" #include "path-util.h" -#include "cgroup-util.h" -#include "cgroup-show.h" +#include "process-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" static int compare(const void *a, const void *b) { const pid_t *p = a, *q = b; diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c index d1cdb151b2..835fe52423 100644 --- a/src/shared/clean-ipc.c +++ b/src/shared/clean-ipc.c @@ -19,19 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <dirent.h> +#include <fcntl.h> +#include <mqueue.h> #include <sys/ipc.h> -#include <sys/shm.h> -#include <sys/sem.h> #include <sys/msg.h> +#include <sys/sem.h> +#include <sys/shm.h> #include <sys/stat.h> -#include <fcntl.h> -#include <dirent.h> -#include <mqueue.h> -#include "util.h" +#include "clean-ipc.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "string-util.h" #include "strv.h" -#include "clean-ipc.h" +#include "util.h" +#include "dirent-util.h" static int clean_sysvipc_shm(uid_t delete_uid) { _cleanup_fclose_ FILE *f = NULL; @@ -44,8 +48,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m"); } FOREACH_LINE(line, f, goto fail) { @@ -87,8 +90,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m"); } static int clean_sysvipc_sem(uid_t delete_uid) { @@ -102,8 +104,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m"); } FOREACH_LINE(line, f, goto fail) { @@ -140,8 +141,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m"); } static int clean_sysvipc_msg(uid_t delete_uid) { @@ -155,8 +155,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m"); } FOREACH_LINE(line, f, goto fail) { @@ -194,8 +193,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m"); } static int clean_posix_shm_internal(DIR *dir, uid_t uid) { @@ -273,8 +271,7 @@ static int clean_posix_shm(uid_t uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /dev/shm: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /dev/shm: %m"); } return clean_posix_shm_internal(dir, uid); @@ -290,8 +287,7 @@ static int clean_posix_mq(uid_t uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /dev/mqueue: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /dev/mqueue: %m"); } FOREACH_DIRENT(de, dir, goto fail) { @@ -330,8 +326,7 @@ static int clean_posix_mq(uid_t uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /dev/mqueue: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /dev/mqueue: %m"); } int clean_ipc(uid_t uid) { diff --git a/src/shared/condition.c b/src/shared/condition.c index 1d7dd49e04..a69719116c 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -19,25 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> +#include <fnmatch.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> -#include <fnmatch.h> #include "sd-id128.h" -#include "util.h" -#include "virt.h" -#include "path-util.h" -#include "architecture.h" -#include "smack-util.h" + +#include "alloc-util.h" #include "apparmor-util.h" -#include "ima-util.h" -#include "selinux-util.h" -#include "audit.h" +#include "architecture.h" +#include "audit-util.h" #include "cap-list.h" -#include "hostname-util.h" #include "condition.h" +#include "extract-word.h" +#include "fd-util.h" +#include "glob-util.h" +#include "hostname-util.h" +#include "ima-util.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" +#include "selinux-util.h" +#include "smack-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" +#include "virt.h" Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { Condition *c; diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index c282fb1231..486122b0fd 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -19,21 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <stdio.h> #include <errno.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> #include "sd-messages.h" + +#include "alloc-util.h" #include "conf-files.h" -#include "util.h" -#include "macro.h" -#include "strv.h" +#include "conf-parser.h" +#include "fd-util.h" +#include "fs-util.h" #include "log.h" -#include "utf8.h" +#include "macro.h" +#include "parse-util.h" #include "path-util.h" +#include "process-util.h" #include "signal-util.h" -#include "conf-parser.h" +#include "string-util.h" +#include "strv.h" +#include "syslog-util.h" +#include "utf8.h" +#include "util.h" int config_item_table_lookup( const void *table, @@ -694,9 +702,6 @@ int config_parse_strv(const char *unit, void *userdata) { char ***sv = data; - const char *word, *state; - size_t l; - int r; assert(filename); assert(lvalue); @@ -719,25 +724,28 @@ int config_parse_strv(const char *unit, return 0; } - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - char *n; - - n = strndup(word, l); - if (!n) + for (;;) { + char *word = NULL; + int r; + r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); + break; + } - if (!utf8_is_valid(n)) { + if (!utf8_is_valid(word)) { log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); - free(n); + free(word); continue; } - - r = strv_consume(sv, n); + r = strv_consume(sv, word); if (r < 0) return log_oom(); } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index 25ad918b85..ad3c17d5bd 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -23,10 +23,12 @@ #include <stdlib.h> #include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "dev-setup.h" #include "label.h" #include "path-util.h" -#include "dev-setup.h" +#include "user-util.h" +#include "util.h" int dev_setup(const char *prefix, uid_t uid, gid_t gid) { static const char symlinks[] = diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 5680f01bd9..7af15e0098 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -24,7 +24,11 @@ #include <stringprep.h> #endif +#include "alloc-util.h" #include "dns-domain.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "string-util.h" int dns_label_unescape(const char **name, char *dest, size_t sz) { const char *n; diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 1845068adb..0d44401cc2 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -19,12 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "conf-files.h" #include "dropin.h" -#include "util.h" -#include "strv.h" -#include "mkdir.h" +#include "escape.h" +#include "fd-util.h" #include "fileio-label.h" -#include "conf-files.h" +#include "mkdir.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" int drop_in_file(const char *dir, const char *unit, unsigned level, const char *name, char **_p, char **_q) { diff --git a/src/shared/efivars.c b/src/shared/efivars.c index f087c2a566..86bb0b57c3 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -23,10 +23,16 @@ #include <string.h> #include <fcntl.h> -#include "util.h" +#include "alloc-util.h" +#include "dirent-util.h" +#include "efivars.h" +#include "fd-util.h" +#include "io-util.h" +#include "parse-util.h" +#include "stdio-util.h" #include "utf8.h" +#include "util.h" #include "virt.h" -#include "efivars.h" #ifdef ENABLE_EFI diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index effc6e8e70..e178287872 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -27,8 +27,9 @@ #include <linux/netfilter/xt_addrtype.h> #include <libiptc/libiptc.h> -#include "util.h" +#include "alloc-util.h" #include "firewall-util.h" +#include "util.h" DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free); diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index db2146f8c1..eb2845cddf 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -19,13 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "device-nodes.h" #include "fstab-util.h" +#include "mount-util.h" +#include "parse-util.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" #include "util.h" bool fstab_is_mount_point(const char *mount) { - _cleanup_free_ char *device = NULL; _cleanup_endmntent_ FILE *f = NULL; struct mntent *m; @@ -195,3 +199,60 @@ int fstab_find_pri(const char *options, int *ret) { *ret = (int) pri; return 1; } + +static char *unquote(const char *s, const char* quotes) { + size_t l; + assert(s); + + /* This is rather stupid, simply removes the heading and + * trailing quotes if there is one. Doesn't care about + * escaping or anything. + * + * DON'T USE THIS FOR NEW CODE ANYMORE!*/ + + l = strlen(s); + if (l < 2) + return strdup(s); + + if (strchr(quotes, s[0]) && s[l-1] == s[0]) + return strndup(s+1, l-2); + + return strdup(s); +} + +static char *tag_to_udev_node(const char *tagvalue, const char *by) { + _cleanup_free_ char *t = NULL, *u = NULL; + size_t enc_len; + + u = unquote(tagvalue, QUOTES); + if (!u) + return NULL; + + enc_len = strlen(u) * 4 + 1; + t = new(char, enc_len); + if (!t) + return NULL; + + if (encode_devnode_name(u, t, enc_len) < 0) + return NULL; + + return strjoin("/dev/disk/by-", by, "/", t, NULL); +} + +char *fstab_node_to_udev_node(const char *p) { + assert(p); + + if (startswith(p, "LABEL=")) + return tag_to_udev_node(p+6, "label"); + + if (startswith(p, "UUID=")) + return tag_to_udev_node(p+5, "uuid"); + + if (startswith(p, "PARTUUID=")) + return tag_to_udev_node(p+9, "partuuid"); + + if (startswith(p, "PARTLABEL=")) + return tag_to_udev_node(p+10, "partlabel"); + + return strdup(p); +} diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h index 872b2363cd..5ebea44019 100644 --- a/src/shared/fstab-util.h +++ b/src/shared/fstab-util.h @@ -23,11 +23,12 @@ #include <stdbool.h> #include <stddef.h> + #include "macro.h" bool fstab_is_mount_point(const char *mount); -int fstab_filter_options(const char *opts, const char *names, - const char **namefound, char **value, char **filtered); + +int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered); int fstab_extract_values(const char *opts, const char *name, char ***values); @@ -49,3 +50,5 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no return opt == yes_no; } + +char *fstab_node_to_udev_node(const char *p); diff --git a/src/shared/generator.c b/src/shared/generator.c index e58bbea77c..9998c64416 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -21,21 +21,25 @@ #include <unistd.h> -#include "util.h" -#include "special.h" -#include "mkdir.h" -#include "unit-name.h" +#include "alloc-util.h" +#include "dropin.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "fstab-util.h" #include "generator.h" +#include "mkdir.h" +#include "mount-util.h" #include "path-util.h" -#include "fstab-util.h" -#include "fileio.h" -#include "dropin.h" +#include "special.h" +#include "string-util.h" +#include "unit-name.h" +#include "util.h" static int write_fsck_sysroot_service(const char *dir, const char *what) { - const char *unit; - _cleanup_free_ char *device = NULL; - _cleanup_free_ char *escaped; + _cleanup_free_ char *device = NULL, *escaped = NULL; _cleanup_fclose_ FILE *f = NULL; + const char *unit; int r; escaped = cescape(what); @@ -60,7 +64,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) { "Description=File System Check on %2$s\n" "DefaultDependencies=no\n" "BindsTo=%3$s\n" - "After=%3$s\n" + "After=%3$s local-fs-pre.target\n" "Before=shutdown.target\n" "\n" "[Service]\n" @@ -101,16 +105,17 @@ int generator_write_fsck_deps( if (!isempty(fstype) && !streq(fstype, "auto")) { r = fsck_exists(fstype); - if (r == -ENOENT) { + if (r < 0) + log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype); + else if (r == 0) { /* treat missing check as essentially OK */ - log_debug_errno(r, "Checking was requested for %s, but fsck.%s does not exist: %m", what, fstype); + log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype); return 0; - } else if (r < 0) - return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype); + } } if (path_equal(where, "/")) { - char *lnk; + const char *lnk; lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service"); @@ -137,7 +142,7 @@ int generator_write_fsck_deps( } fprintf(f, - "RequiresOverridable=%1$s\n" + "Requires=%1$s\n" "After=%1$s\n", fsck); } diff --git a/src/shared/import-util.c b/src/shared/import-util.c index 001a8a37e8..ddc8c00a2d 100644 --- a/src/shared/import-util.c +++ b/src/shared/import-util.c @@ -19,8 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" +#include "btrfs-util.h" #include "import-util.h" +#include "path-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" int import_url_last_component(const char *url, char **ret) { const char *e, *p; @@ -201,3 +206,29 @@ bool dkr_id_is_valid(const char *id) { return true; } + +int import_assign_pool_quota_and_warn(const char *path) { + int r; + + r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true); + if (r == -ENOTTY) { + log_debug_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, as directory is not on btrfs or not a subvolume. Ignoring."); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines: %m"); + if (r > 0) + log_info("Set up default quota hierarchy for /var/lib/machines."); + + r = btrfs_subvol_auto_qgroup(path, 0, true); + if (r == -ENOTTY) { + log_debug_errno(r, "Failed to set up quota hierarchy for %s, as directory is not on btrfs or not a subvolume. Ignoring.", path); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path); + if (r > 0) + log_info("Set up default quota hierarchy for %s.", path); + + return 0; +} diff --git a/src/shared/import-util.h b/src/shared/import-util.h index 7bf7d4ca40..9120a5119f 100644 --- a/src/shared/import-util.h +++ b/src/shared/import-util.h @@ -47,3 +47,5 @@ bool dkr_id_is_valid(const char *id); bool dkr_ref_is_valid(const char *ref); bool dkr_digest_is_valid(const char *digest); #define dkr_tag_is_valid(tag) filename_is_valid(tag) + +int import_assign_pool_quota_and_warn(const char *path); diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index cbe984d2fb..74b909d34d 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -21,11 +21,13 @@ #include <stdlib.h> +#include "alloc-util.h" +#include "formats-util.h" +#include "install-printf.h" #include "specifier.h" #include "unit-name.h" +#include "user-util.h" #include "util.h" -#include "install-printf.h" -#include "formats-util.h" static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { UnitFileInstallInfo *i = userdata; @@ -65,42 +67,28 @@ static int specifier_instance(char specifier, void *data, void *userdata, char * } static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) { - UnitFileInstallInfo *i = userdata; - const char *username; - _cleanup_free_ char *tmp = NULL; - char *printed = NULL; - - assert(i); + char *t; - if (i->user) - username = i->user; - else - /* get USER env from env or our own uid */ - username = tmp = getusername_malloc(); - - switch (specifier) { - case 'u': - printed = strdup(username); - break; - case 'U': { - /* fish username from passwd */ - uid_t uid; - int r; - - r = get_user_creds(&username, &uid, NULL, NULL, NULL); - if (r < 0) - return r; - - if (asprintf(&printed, UID_FMT, uid) < 0) - return -ENOMEM; - break; - }} + /* If we are UID 0 (root), this will not result in NSS, + * otherwise it might. This is good, as we want to be able to + * run this in PID 1, where our user ID is 0, but where NSS + * lookups are not allowed. */ + t = getusername_malloc(); + if (!t) + return -ENOMEM; - *ret = printed; + *ret = t; return 0; } +static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) { + + if (asprintf(ret, UID_FMT, getuid()) < 0) + return -ENOMEM; + + return 0; +} int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) { @@ -112,8 +100,8 @@ int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) * %p: the prefix (foo) * %i: the instance (bar) - * %U the UID of the configured user or running user - * %u the username of the configured user or running user + * %U the UID of the running user + * %u the username of running user * %m the machine ID of the running system * %H the host name of the running system * %b the boot ID of the running system @@ -126,7 +114,7 @@ int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) { 'p', specifier_prefix, NULL }, { 'i', specifier_instance, NULL }, - { 'U', specifier_user_name, NULL }, + { 'U', specifier_user_id, NULL }, { 'u', specifier_user_name, NULL }, { 'm', specifier_machine_id, NULL }, diff --git a/src/shared/install.c b/src/shared/install.c index 238433c808..9b6464ba9d 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -21,40 +21,59 @@ #include <errno.h> #include <fcntl.h> -#include <unistd.h> -#include <string.h> #include <fnmatch.h> +#include <string.h> +#include <unistd.h> -#include "util.h" -#include "mkdir.h" +#include "alloc-util.h" +#include "conf-files.h" +#include "conf-parser.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "hashmap.h" -#include "set.h" -#include "path-util.h" +#include "install-printf.h" +#include "install.h" +#include "mkdir.h" #include "path-lookup.h" +#include "path-util.h" +#include "set.h" +#include "special.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" -#include "install.h" -#include "conf-parser.h" -#include "conf-files.h" -#include "install-printf.h" -#include "special.h" +#include "util.h" + +#define UNIT_FILE_FOLLOW_SYMLINK_MAX 64 + +typedef enum SearchFlags { + SEARCH_LOAD = 1, + SEARCH_FOLLOW_CONFIG_SYMLINKS = 2, +} SearchFlags; typedef struct { - OrderedHashmap *will_install; - OrderedHashmap *have_installed; + OrderedHashmap *will_process; + OrderedHashmap *have_processed; } InstallContext; static int in_search_path(const char *path, char **search) { _cleanup_free_ char *parent = NULL; - int r; + char **i; assert(path); - r = path_get_parent(path, &parent); - if (r < 0) - return r; + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; - return strv_contains(search, parent); + STRV_FOREACH(i, search) + if (path_equal(parent, *i)) + return true; + + return false; } static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) { @@ -65,6 +84,9 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d assert(scope < _UNIT_FILE_SCOPE_MAX); assert(ret); + /* This determines where we shall create or remove our + * installation ("configuration") symlinks */ + switch (scope) { case UNIT_FILE_SYSTEM: @@ -95,9 +117,10 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d r = user_runtime_dir(&p); else r = user_config_home(&p); - - if (r <= 0) - return r < 0 ? r : -ENOENT; + if (r < 0) + return r; + if (r == 0) + return -ENOENT; break; @@ -112,6 +135,185 @@ static int get_config_path(UnitFileScope scope, bool runtime, const char *root_d return 0; } +static bool is_config_path(UnitFileScope scope, const char *path) { + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(path); + + /* Checks whether the specified path is intended for + * configuration or is outside of it */ + + switch (scope) { + + case UNIT_FILE_SYSTEM: + case UNIT_FILE_GLOBAL: + return path_startswith(path, "/etc") || + path_startswith(path, SYSTEM_CONFIG_UNIT_PATH) || + path_startswith(path, "/run"); + + + case UNIT_FILE_USER: { + _cleanup_free_ char *p = NULL; + + r = user_config_home(&p); + if (r < 0) + return r; + if (r > 0 && path_startswith(path, p)) + return true; + + p = mfree(p); + + r = user_runtime_dir(&p); + if (r < 0) + return r; + if (r > 0 && path_startswith(path, p)) + return true; + + return false; + } + + default: + assert_not_reached("Bad scope"); + } +} + + +static int verify_root_dir(UnitFileScope scope, const char **root_dir) { + int r; + + assert(root_dir); + + /* Verifies that the specified root directory to operate on + * makes sense. Reset it to NULL if it is the root directory + * or set to empty */ + + if (isempty(*root_dir) || path_equal(*root_dir, "/")) { + *root_dir = NULL; + return 0; + } + + if (scope != UNIT_FILE_SYSTEM) + return -EINVAL; + + r = is_dir(*root_dir, true); + if (r < 0) + return r; + if (r == 0) + return -ENOTDIR; + + return 0; +} + +int unit_file_changes_add( + UnitFileChange **changes, + unsigned *n_changes, + UnitFileChangeType type, + const char *path, + const char *source) { + + UnitFileChange *c; + unsigned i; + + assert(path); + assert(!changes == !n_changes); + + if (!changes) + return 0; + + c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); + if (!c) + return -ENOMEM; + + *changes = c; + i = *n_changes; + + c[i].type = type; + c[i].path = strdup(path); + if (!c[i].path) + return -ENOMEM; + + path_kill_slashes(c[i].path); + + if (source) { + c[i].source = strdup(source); + if (!c[i].source) { + free(c[i].path); + return -ENOMEM; + } + + path_kill_slashes(c[i].path); + } else + c[i].source = NULL; + + *n_changes = i+1; + return 0; +} + +void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { + unsigned i; + + assert(changes || n_changes == 0); + + if (!changes) + return; + + for (i = 0; i < n_changes; i++) { + free(changes[i].path); + free(changes[i].source); + } + + free(changes); +} + +static int create_symlink( + const char *old_path, + const char *new_path, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_free_ char *dest = NULL; + int r; + + assert(old_path); + assert(new_path); + + /* Actually create a symlink, and remember that we did. Is + * smart enough to check if there's already a valid symlink in + * place. */ + + mkdir_parents_label(new_path, 0755); + + if (symlink(old_path, new_path) >= 0) { + unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); + return 0; + } + + if (errno != EEXIST) + return -errno; + + r = readlink_malloc(new_path, &dest); + if (r < 0) + return r; + + if (path_equal(dest, old_path)) + return 0; + + if (!force) + return -EEXIST; + + r = symlink_atomic(old_path, new_path); + if (r < 0) + return r; + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); + unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); + + return 0; +} + static int mark_symlink_for_removal( Set **remove_symlinks_to, const char *p) { @@ -132,10 +334,12 @@ static int mark_symlink_for_removal( path_kill_slashes(n); r = set_consume(*remove_symlinks_to, n); + if (r == -EEXIST) + return 0; if (r < 0) - return r == -EEXIST ? 0 : r; + return r; - return 0; + return 1; } static int remove_marked_symlinks_fd( @@ -143,19 +347,19 @@ static int remove_marked_symlinks_fd( int fd, const char *path, const char *config_path, - bool *deleted, + bool *restart, UnitFileChange **changes, - unsigned *n_changes, - char** instance_whitelist) { + unsigned *n_changes) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; int r = 0; assert(remove_symlinks_to); assert(fd >= 0); assert(path); assert(config_path); - assert(deleted); + assert(restart); d = fdopendir(fd); if (!d) { @@ -165,27 +369,13 @@ static int remove_marked_symlinks_fd( rewinddir(d); - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) { - r = -errno; - break; - } - - if (!de) - break; - - if (hidden_file(de->d_name)) - continue; + FOREACH_DIRENT(de, d, return -errno) { dirent_ensure_type(d, de); if (de->d_type == DT_DIR) { - int nfd, q; _cleanup_free_ char *p = NULL; + int nfd, q; nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); if (nfd < 0) { @@ -204,42 +394,23 @@ static int remove_marked_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, deleted, changes, n_changes, instance_whitelist); + q = remove_marked_symlinks_fd(remove_symlinks_to, nfd, p, config_path, restart, changes, n_changes); if (q < 0 && r == 0) r = q; } else if (de->d_type == DT_LNK) { _cleanup_free_ char *p = NULL, *dest = NULL; - int q; bool found; + int q; if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) continue; - if (unit_name_is_valid(de->d_name, UNIT_NAME_INSTANCE) && - instance_whitelist && - !strv_contains(instance_whitelist, de->d_name)) { - - _cleanup_free_ char *w = NULL; - - /* OK, the file is not listed directly - * in the whitelist, so let's check if - * the template of it might be - * listed. */ - - r = unit_name_template(de->d_name, &w); - if (r < 0) - return r; - - if (!strv_contains(instance_whitelist, w)) - continue; - } - p = path_make_absolute(de->d_name, path); if (!p) return -ENOMEM; - q = readlink_and_canonicalize(p, &dest); + q = readlink_malloc(p, &dest); if (q < 0) { if (q == -ENOENT) continue; @@ -249,9 +420,15 @@ static int remove_marked_symlinks_fd( continue; } + /* We remove all links pointing to a file or + * path that is marked, as well as all files + * sharing the same name as a file that is + * marked. */ + found = - set_get(remove_symlinks_to, dest) || - set_get(remove_symlinks_to, basename(dest)); + set_contains(remove_symlinks_to, dest) || + set_contains(remove_symlinks_to, basename(dest)) || + set_contains(remove_symlinks_to, de->d_name); if (!found) continue; @@ -263,18 +440,15 @@ static int remove_marked_symlinks_fd( } path_kill_slashes(p); - rmdir_parents(p, config_path); - unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); + (void) rmdir_parents(p, config_path); - if (!set_get(remove_symlinks_to, p)) { + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, p, NULL); - q = mark_symlink_for_removal(&remove_symlinks_to, p); - if (q < 0) { - if (r == 0) - r = q; - } else - *deleted = true; - } + q = mark_symlink_for_removal(&remove_symlinks_to, p); + if (q < 0) + return q; + if (q > 0) + *restart = true; } } @@ -285,12 +459,11 @@ static int remove_marked_symlinks( Set *remove_symlinks_to, const char *config_path, UnitFileChange **changes, - unsigned *n_changes, - char** instance_whitelist) { + unsigned *n_changes) { _cleanup_close_ int fd = -1; + bool restart; int r = 0; - bool deleted; assert(config_path); @@ -303,32 +476,32 @@ static int remove_marked_symlinks( do { int q, cfd; - deleted = false; + restart = false; cfd = fcntl(fd, F_DUPFD_CLOEXEC, 3); - if (cfd < 0) { - r = -errno; - break; - } + if (cfd < 0) + return -errno; /* This takes possession of cfd and closes it */ - q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &deleted, changes, n_changes, instance_whitelist); + q = remove_marked_symlinks_fd(remove_symlinks_to, cfd, config_path, config_path, &restart, changes, n_changes); if (r == 0) r = q; - } while (deleted); + } while (restart); return r; } static int find_symlinks_fd( + const char *root_dir, const char *name, int fd, const char *path, const char *config_path, bool *same_name_link) { - int r = 0; _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; assert(name); assert(fd >= 0); @@ -342,25 +515,13 @@ static int find_symlinks_fd( return -errno; } - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - - if (!de) - return r; - - if (hidden_file(de->d_name)) - continue; + FOREACH_DIRENT(de, d, return -errno) { dirent_ensure_type(d, de); if (de->d_type == DT_DIR) { - int nfd, q; _cleanup_free_ char *p = NULL; + int nfd, q; nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); if (nfd < 0) { @@ -379,7 +540,7 @@ static int find_symlinks_fd( } /* This will close nfd, regardless whether it succeeds or not */ - q = find_symlinks_fd(name, nfd, p, config_path, same_name_link); + q = find_symlinks_fd(root_dir, name, nfd, p, config_path, same_name_link); if (q > 0) return 1; if (r == 0) @@ -396,16 +557,27 @@ static int find_symlinks_fd( return -ENOMEM; /* Acquire symlink destination */ - q = readlink_and_canonicalize(p, &dest); + q = readlink_malloc(p, &dest); + if (q == -ENOENT) + continue; if (q < 0) { - if (q == -ENOENT) - continue; - if (r == 0) r = q; continue; } + /* Make absolute */ + if (!path_is_absolute(dest)) { + char *x; + + x = prefix_root(root_dir, dest); + if (!x) + return -ENOMEM; + + free(dest); + dest = x; + } + /* Check if the symlink itself matches what we * are looking for */ if (path_is_absolute(name)) @@ -438,9 +610,12 @@ static int find_symlinks_fd( return 1; } } + + return r; } static int find_symlinks( + const char *root_dir, const char *name, const char *config_path, bool *same_name_link) { @@ -459,7 +634,7 @@ static int find_symlinks( } /* This takes possession of fd and closes it */ - return find_symlinks_fd(name, fd, config_path, config_path, same_name_link); + return find_symlinks_fd(root_dir, name, fd, config_path, config_path, same_name_link); } static int find_symlinks_in_scope( @@ -468,350 +643,59 @@ static int find_symlinks_in_scope( const char *name, UnitFileState *state) { - int r; _cleanup_free_ char *normal_path = NULL, *runtime_path = NULL; bool same_name_link_runtime = false, same_name_link = false; + int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - /* First look in runtime config path */ - r = get_config_path(scope, true, root_dir, &normal_path); + /* First look in the normal config path */ + r = get_config_path(scope, false, root_dir, &normal_path); if (r < 0) return r; - r = find_symlinks(name, normal_path, &same_name_link_runtime); + r = find_symlinks(root_dir, name, normal_path, &same_name_link); if (r < 0) return r; - else if (r > 0) { - *state = UNIT_FILE_ENABLED_RUNTIME; + if (r > 0) { + *state = UNIT_FILE_ENABLED; return r; } - /* Then look in the normal config path */ - r = get_config_path(scope, false, root_dir, &runtime_path); + /* Then look in runtime config path */ + r = get_config_path(scope, true, root_dir, &runtime_path); if (r < 0) return r; - r = find_symlinks(name, runtime_path, &same_name_link); + r = find_symlinks(root_dir, name, runtime_path, &same_name_link_runtime); if (r < 0) return r; - else if (r > 0) { - *state = UNIT_FILE_ENABLED; + if (r > 0) { + *state = UNIT_FILE_ENABLED_RUNTIME; return r; } /* Hmm, we didn't find it, but maybe we found the same name * link? */ - if (same_name_link_runtime) { - *state = UNIT_FILE_LINKED_RUNTIME; - return 1; - } else if (same_name_link) { + if (same_name_link) { *state = UNIT_FILE_LINKED; return 1; } - - return 0; -} - -int unit_file_mask( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char **files, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - char **i; - _cleanup_free_ char *prefix = NULL; - int r; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = get_config_path(scope, runtime, root_dir, &prefix); - if (r < 0) - return r; - - STRV_FOREACH(i, files) { - _cleanup_free_ char *path = NULL; - - if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) { - if (r == 0) - r = -EINVAL; - continue; - } - - path = path_make_absolute(*i, prefix); - if (!path) { - r = -ENOMEM; - break; - } - - if (symlink("/dev/null", path) >= 0) { - unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); - continue; - } - - if (errno == EEXIST) { - - if (null_or_empty_path(path) > 0) - continue; - - if (force) { - if (symlink_atomic("/dev/null", path) >= 0) { - unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, "/dev/null"); - continue; - } - } - - if (r == 0) - r = -EEXIST; - } else { - if (r == 0) - r = -errno; - } - } - - return r; -} - -int unit_file_unmask( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char **files, - UnitFileChange **changes, - unsigned *n_changes) { - - char **i, *config_path = NULL; - int r, q; - Set *remove_symlinks_to = NULL; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - goto finish; - - STRV_FOREACH(i, files) { - _cleanup_free_ char *path = NULL; - - if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) { - if (r == 0) - r = -EINVAL; - continue; - } - - path = path_make_absolute(*i, config_path); - if (!path) { - r = -ENOMEM; - break; - } - - q = null_or_empty_path(path); - if (q > 0) { - if (unlink(path) < 0) - q = -errno; - else { - q = mark_symlink_for_removal(&remove_symlinks_to, path); - unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - } - } - - if (q != -ENOENT && r == 0) - r = q; - } - - -finish: - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); - if (r == 0) - r = q; - - set_free_free(remove_symlinks_to); - free(config_path); - - return r; -} - -int unit_file_link( - UnitFileScope scope, - bool runtime, - const char *root_dir, - char **files, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { - - _cleanup_lookup_paths_free_ LookupPaths paths = {}; - char **i; - _cleanup_free_ char *config_path = NULL; - int r, q; - - assert(scope >= 0); - assert(scope < _UNIT_FILE_SCOPE_MAX); - - r = lookup_paths_init_from_scope(&paths, scope, root_dir); - if (r < 0) - return r; - - r = get_config_path(scope, runtime, root_dir, &config_path); - if (r < 0) - return r; - - STRV_FOREACH(i, files) { - _cleanup_free_ char *path = NULL; - char *fn; - struct stat st; - - fn = basename(*i); - - if (!path_is_absolute(*i) || - !unit_name_is_valid(fn, UNIT_NAME_ANY)) { - if (r == 0) - r = -EINVAL; - continue; - } - - if (lstat(*i, &st) < 0) { - if (r == 0) - r = -errno; - continue; - } - - if (!S_ISREG(st.st_mode)) { - r = -ENOENT; - continue; - } - - q = in_search_path(*i, paths.unit_path); - if (q < 0) - return q; - - if (q > 0) - continue; - - path = path_make_absolute(fn, config_path); - if (!path) - return -ENOMEM; - - if (symlink(*i, path) >= 0) { - unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); - continue; - } - - if (errno == EEXIST) { - _cleanup_free_ char *dest = NULL; - - q = readlink_and_make_absolute(path, &dest); - if (q < 0 && errno != ENOENT) { - if (r == 0) - r = q; - continue; - } - - if (q >= 0 && path_equal(dest, *i)) - continue; - - if (force) { - if (symlink_atomic(*i, path) >= 0) { - unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); - unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, path, *i); - continue; - } - } - - if (r == 0) - r = -EEXIST; - } else { - if (r == 0) - r = -errno; - } - } - - return r; -} - -void unit_file_list_free(Hashmap *h) { - UnitFileList *i; - - while ((i = hashmap_steal_first(h))) { - free(i->path); - free(i); + if (same_name_link_runtime) { + *state = UNIT_FILE_LINKED_RUNTIME; + return 1; } - hashmap_free(h); -} - -int unit_file_changes_add( - UnitFileChange **changes, - unsigned *n_changes, - UnitFileChangeType type, - const char *path, - const char *source) { - - UnitFileChange *c; - unsigned i; - - assert(path); - assert(!changes == !n_changes); - - if (!changes) - return 0; - - c = realloc(*changes, (*n_changes + 1) * sizeof(UnitFileChange)); - if (!c) - return -ENOMEM; - - *changes = c; - i = *n_changes; - - c[i].type = type; - c[i].path = strdup(path); - if (!c[i].path) - return -ENOMEM; - - path_kill_slashes(c[i].path); - - if (source) { - c[i].source = strdup(source); - if (!c[i].source) { - free(c[i].path); - return -ENOMEM; - } - - path_kill_slashes(c[i].path); - } else - c[i].source = NULL; - - *n_changes = i+1; return 0; } -void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes) { - unsigned i; - - assert(changes || n_changes == 0); +static void install_info_free(UnitFileInstallInfo *i) { - if (!changes) + if (!i) return; - for (i = 0; i < n_changes; i++) { - free(changes[i].path); - free(changes[i].source); - } - - free(changes); -} - -static void install_info_free(UnitFileInstallInfo *i) { - assert(i); - free(i->name); free(i->path); strv_free(i->aliases); @@ -819,34 +703,45 @@ static void install_info_free(UnitFileInstallInfo *i) { strv_free(i->required_by); strv_free(i->also); free(i->default_instance); + free(i->symlink_target); free(i); } -static void install_info_hashmap_free(OrderedHashmap *m) { +static OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) { UnitFileInstallInfo *i; if (!m) - return; + return NULL; while ((i = ordered_hashmap_steal_first(m))) install_info_free(i); - ordered_hashmap_free(m); + return ordered_hashmap_free(m); } static void install_context_done(InstallContext *c) { assert(c); - install_info_hashmap_free(c->will_install); - install_info_hashmap_free(c->have_installed); + c->will_process = install_info_hashmap_free(c->will_process); + c->have_processed = install_info_hashmap_free(c->have_processed); +} - c->will_install = c->have_installed = NULL; +static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) { + UnitFileInstallInfo *i; + + i = ordered_hashmap_get(c->have_processed, name); + if (i) + return i; + + return ordered_hashmap_get(c->will_process, name); } static int install_info_add( InstallContext *c, const char *name, - const char *path) { + const char *path, + UnitFileInstallInfo **ret) { + UnitFileInstallInfo *i = NULL; int r; @@ -859,17 +754,21 @@ static int install_info_add( if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; - if (ordered_hashmap_get(c->have_installed, name) || - ordered_hashmap_get(c->will_install, name)) + i = install_info_find(c, name); + if (i) { + if (ret) + *ret = i; return 0; + } - r = ordered_hashmap_ensure_allocated(&c->will_install, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops); if (r < 0) return r; i = new0(UnitFileInstallInfo, 1); if (!i) return -ENOMEM; + i->type = _UNIT_FILE_TYPE_INVALID; i->name = strdup(name); if (!i->name) { @@ -885,30 +784,32 @@ static int install_info_add( } } - r = ordered_hashmap_put(c->will_install, i->name, i); + r = ordered_hashmap_put(c->will_process, i->name, i); if (r < 0) goto fail; + if (ret) + *ret = i; + return 0; fail: - if (i) - install_info_free(i); - + install_info_free(i); return r; } static int install_info_add_auto( InstallContext *c, - const char *name_or_path) { + const char *name_or_path, + UnitFileInstallInfo **ret) { assert(c); assert(name_or_path); if (path_is_absolute(name_or_path)) - return install_info_add(c, NULL, name_or_path); + return install_info_add(c, NULL, name_or_path, ret); else - return install_info_add(c, name_or_path, NULL); + return install_info_add(c, name_or_path, NULL, ret); } static int config_parse_also( @@ -923,63 +824,33 @@ static int config_parse_also( void *data, void *userdata) { - size_t l; - const char *word, *state; - InstallContext *c = data; UnitFileInstallInfo *i = userdata; + InstallContext *c = data; + int r; assert(filename); assert(lvalue); assert(rvalue); - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *n; - int r; - - n = strndup(word, l); - if (!n) - return -ENOMEM; + for (;;) { + _cleanup_free_ char *word = NULL; - r = install_info_add(c, n, NULL); + r = extract_first_word(&rvalue, &word, NULL, 0); if (r < 0) return r; + if (r == 0) + break; - r = strv_extend(&i->also, n); + r = install_info_add(c, word, NULL, NULL); if (r < 0) return r; - } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); - - return 0; -} -static int config_parse_user( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - UnitFileInstallInfo *i = data; - char *printed; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - - r = install_full_printf(i, rvalue, &printed); - if (r < 0) - return r; + r = strv_push(&i->also, word); + if (r < 0) + return r; - free(i->user); - i->user = printed; + word = NULL; + } return 0; } @@ -1024,9 +895,7 @@ static int unit_file_load( UnitFileInstallInfo *info, const char *path, const char *root_dir, - bool allow_symlink, - bool load, - bool *also) { + SearchFlags flags) { const ConfigTableItem items[] = { { "Install", "Alias", config_parse_strv, 0, &info->aliases }, @@ -1034,34 +903,57 @@ static int unit_file_load( { "Install", "RequiredBy", config_parse_strv, 0, &info->required_by }, { "Install", "DefaultInstance", config_parse_default_instance, 0, info }, { "Install", "Also", config_parse_also, 0, c }, - { "Exec", "User", config_parse_user, 0, info }, {} }; _cleanup_fclose_ FILE *f = NULL; - int fd, r; + _cleanup_close_ int fd = -1; + struct stat st; + int r; assert(c); assert(info); assert(path); - if (!isempty(root_dir)) - path = strjoina(root_dir, "/", path); + path = prefix_roota(root_dir, path); - if (!load) { - r = access(path, F_OK) ? -errno : 0; - return r; + if (!(flags & SEARCH_LOAD)) { + r = lstat(path, &st); + if (r < 0) + return -errno; + + if (null_or_empty(&st)) + info->type = UNIT_FILE_TYPE_MASKED; + else if (S_ISREG(st.st_mode)) + info->type = UNIT_FILE_TYPE_REGULAR; + else if (S_ISLNK(st.st_mode)) + return -ELOOP; + else if (S_ISDIR(st.st_mode)) + return -EISDIR; + else + return -ENOTTY; + + return 0; } - fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|(allow_symlink ? 0 : O_NOFOLLOW)); + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fd < 0) return -errno; + if (fstat(fd, &st) < 0) + return -errno; + if (null_or_empty(&st)) { + info->type = UNIT_FILE_MASKED; + return 0; + } + if (S_ISDIR(st.st_mode)) + return -EISDIR; + if (!S_ISREG(st.st_mode)) + return -ENOTTY; f = fdopen(fd, "re"); - if (!f) { - safe_close(fd); - return -ENOMEM; - } + if (!f) + return -errno; + fd = -1; r = config_parse(NULL, path, f, NULL, @@ -1070,8 +962,7 @@ static int unit_file_load( if (r < 0) return r; - if (also) - *also = !strv_isempty(info->also); + info->type = UNIT_FILE_TYPE_REGULAR; return (int) strv_length(info->aliases) + @@ -1079,14 +970,73 @@ static int unit_file_load( (int) strv_length(info->required_by); } +static int unit_file_load_or_readlink( + InstallContext *c, + UnitFileInstallInfo *info, + const char *path, + const char *root_dir, + SearchFlags flags) { + + _cleanup_free_ char *np = NULL; + int r; + + r = unit_file_load(c, info, path, root_dir, flags); + if (r != -ELOOP) + return r; + + /* This is a symlink, let's read it. */ + + r = readlink_and_make_absolute_root(root_dir, path, &np); + if (r < 0) + return r; + + if (path_equal(np, "/dev/null")) + info->type = UNIT_FILE_TYPE_MASKED; + else { + const char *bn; + UnitType a, b; + + bn = basename(np); + + if (unit_name_is_valid(info->name, UNIT_NAME_PLAIN)) { + + if (!unit_name_is_valid(bn, UNIT_NAME_PLAIN)) + return -EINVAL; + + } else if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { + + if (!unit_name_is_valid(bn, UNIT_NAME_INSTANCE|UNIT_NAME_TEMPLATE)) + return -EINVAL; + + } else if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE)) { + + if (!unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) + return -EINVAL; + } else + return -EINVAL; + + /* Enforce that the symlink destination does not + * change the unit file type. */ + + a = unit_name_to_type(info->name); + b = unit_name_to_type(bn); + if (a < 0 || b < 0 || a != b) + return -EINVAL; + + info->type = UNIT_FILE_TYPE_SYMLINK; + info->symlink_target = np; + np = NULL; + } + + return 0; +} + static int unit_file_search( InstallContext *c, UnitFileInstallInfo *info, const LookupPaths *paths, const char *root_dir, - bool allow_symlink, - bool load, - bool *also) { + SearchFlags flags) { char **p; int r; @@ -1095,8 +1045,12 @@ static int unit_file_search( assert(info); assert(paths); + /* Was this unit already loaded? */ + if (info->type != _UNIT_FILE_TYPE_INVALID) + return 0; + if (info->path) - return unit_file_load(c, info, info->path, root_dir, allow_symlink, load, also); + return unit_file_load_or_readlink(c, info, info->path, root_dir, flags); assert(info->name); @@ -1107,14 +1061,15 @@ static int unit_file_search( if (!path) return -ENOMEM; - r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also); - if (r >= 0) { + r = unit_file_load_or_readlink(c, info, path, root_dir, flags); + if (r < 0) { + if (r != -ENOENT) + return r; + } else { info->path = path; path = NULL; return r; } - if (r != -ENOENT && r != -ELOOP) - return r; } if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) { @@ -1136,92 +1091,149 @@ static int unit_file_search( if (!path) return -ENOMEM; - r = unit_file_load(c, info, path, root_dir, allow_symlink, load, also); - if (r >= 0) { + r = unit_file_load_or_readlink(c, info, path, root_dir, flags); + if (r < 0) { + if (r != -ENOENT) + return r; + } else { info->path = path; path = NULL; return r; } - if (r != -ENOENT && r != -ELOOP) - return r; } } return -ENOENT; } -static int unit_file_can_install( - const LookupPaths *paths, +static int install_info_follow( + InstallContext *c, + UnitFileInstallInfo *i, const char *root_dir, - const char *name, - bool allow_symlink, - bool *also) { + SearchFlags flags) { + + assert(c); + assert(i); + + if (i->type != UNIT_FILE_TYPE_SYMLINK) + return -EINVAL; + if (!i->symlink_target) + return -EINVAL; + + /* If the basename doesn't match, the caller should add a + * complete new entry for this. */ + + if (!streq(basename(i->symlink_target), i->name)) + return -EXDEV; + + free(i->path); + i->path = i->symlink_target; + i->symlink_target = NULL; + i->type = _UNIT_FILE_TYPE_INVALID; + + return unit_file_load_or_readlink(c, i, i->path, root_dir, flags); +} + +static int install_info_traverse( + UnitFileScope scope, + InstallContext *c, + const char *root_dir, + const LookupPaths *paths, + UnitFileInstallInfo *start, + SearchFlags flags, + UnitFileInstallInfo **ret) { - _cleanup_(install_context_done) InstallContext c = {}; UnitFileInstallInfo *i; + unsigned k = 0; int r; assert(paths); - assert(name); + assert(start); + assert(c); - r = install_info_add_auto(&c, name); + r = unit_file_search(c, start, paths, root_dir, flags); if (r < 0) return r; - assert_se(i = ordered_hashmap_first(c.will_install)); + i = start; + while (i->type == UNIT_FILE_TYPE_SYMLINK) { + /* Follow the symlink */ - r = unit_file_search(&c, i, paths, root_dir, allow_symlink, true, also); + if (++k > UNIT_FILE_FOLLOW_SYMLINK_MAX) + return -ELOOP; - if (r >= 0) - r = - (int) strv_length(i->aliases) + - (int) strv_length(i->wanted_by) + - (int) strv_length(i->required_by); + if (!(flags & SEARCH_FOLLOW_CONFIG_SYMLINKS) && is_config_path(scope, i->path)) + return -ELOOP; - return r; -} + r = install_info_follow(c, i, root_dir, flags); + if (r < 0) { + _cleanup_free_ char *buffer = NULL; + const char *bn; -static int create_symlink( - const char *old_path, - const char *new_path, - bool force, - UnitFileChange **changes, - unsigned *n_changes) { + if (r != -EXDEV) + return r; - _cleanup_free_ char *dest = NULL; - int r; + /* Target has a different name, create a new + * install info object for that, and continue + * with that. */ - assert(old_path); - assert(new_path); + bn = basename(i->symlink_target); - mkdir_parents_label(new_path, 0755); + if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE) && + unit_name_is_valid(bn, UNIT_NAME_TEMPLATE)) { - if (symlink(old_path, new_path) >= 0) { - unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); - return 0; + _cleanup_free_ char *instance = NULL; + + r = unit_name_to_instance(i->name, &instance); + if (r < 0) + return r; + + r = unit_name_replace_instance(bn, instance, &buffer); + if (r < 0) + return r; + + bn = buffer; + } + + r = install_info_add(c, bn, NULL, &i); + if (r < 0) + return r; + + r = unit_file_search(c, i, paths, root_dir, flags); + if (r < 0) + return r; + } + + /* Try again, with the new target we found. */ } - if (errno != EEXIST) - return -errno; + if (ret) + *ret = i; - r = readlink_and_make_absolute(new_path, &dest); - if (r < 0) - return r; + return 0; +} - if (path_equal(dest, old_path)) - return 0; +static int install_info_discover( + UnitFileScope scope, + InstallContext *c, + const char *root_dir, + const LookupPaths *paths, + const char *name, + SearchFlags flags, + UnitFileInstallInfo **ret) { - if (!force) - return -EEXIST; + UnitFileInstallInfo *i; + int r; - r = symlink_atomic(old_path, new_path); + assert(c); + assert(paths); + assert(name); + + r = install_info_add_auto(c, name, &i); if (r < 0) return r; - unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, new_path, NULL); - unit_file_changes_add(changes, n_changes, UNIT_FILE_SYMLINK, new_path, old_path); - - return 0; + return install_info_traverse(scope, c, root_dir, paths, i, flags, ret); } static int install_info_symlink_alias( @@ -1356,6 +1368,9 @@ static int install_info_apply( assert(paths); assert(config_path); + if (i->type != UNIT_FILE_TYPE_REGULAR) + return 0; + r = install_info_symlink_alias(i, config_path, force, changes, n_changes); q = install_info_symlink_wants(i, config_path, i->wanted_by, ".wants/", force, changes, n_changes); @@ -1374,53 +1389,59 @@ static int install_info_apply( } static int install_context_apply( + UnitFileScope scope, InstallContext *c, const LookupPaths *paths, const char *config_path, const char *root_dir, bool force, + SearchFlags flags, UnitFileChange **changes, unsigned *n_changes) { UnitFileInstallInfo *i; - int r, q; + int r; assert(c); assert(paths); assert(config_path); - if (!ordered_hashmap_isempty(c->will_install)) { - r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); - if (r < 0) - return r; + if (ordered_hashmap_isempty(c->will_process)) + return 0; - r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install)); - if (r < 0) - return r; - } + r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); + if (r < 0) + return r; r = 0; - while ((i = ordered_hashmap_first(c->will_install))) { - assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); + while ((i = ordered_hashmap_first(c->will_process))) { + int q; - q = unit_file_search(c, i, paths, root_dir, false, true, NULL); - if (q < 0) { - if (r >= 0) - r = q; + q = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); + if (q < 0) + return q; + r = install_info_traverse(scope, c, root_dir, paths, i, flags, NULL); + if (r < 0) return r; - } else if (r >= 0) - r += q; + + if (i->type != UNIT_FILE_TYPE_REGULAR) + continue; q = install_info_apply(i, paths, config_path, root_dir, force, changes, n_changes); - if (r >= 0 && q < 0) - r = q; + if (r >= 0) { + if (q < 0) + r = q; + else + r+= q; + } } return r; } static int install_context_mark_for_removal( + UnitFileScope scope, InstallContext *c, const LookupPaths *paths, Set **remove_symlinks_to, @@ -1428,7 +1449,7 @@ static int install_context_mark_for_removal( const char *root_dir) { UnitFileInstallInfo *i; - int r, q; + int r; assert(c); assert(paths); @@ -1436,87 +1457,182 @@ static int install_context_mark_for_removal( /* Marks all items for removal */ - if (!ordered_hashmap_isempty(c->will_install)) { - r = ordered_hashmap_ensure_allocated(&c->have_installed, &string_hash_ops); + if (ordered_hashmap_isempty(c->will_process)) + return 0; + + r = ordered_hashmap_ensure_allocated(&c->have_processed, &string_hash_ops); + if (r < 0) + return r; + + while ((i = ordered_hashmap_first(c->will_process))) { + + r = ordered_hashmap_move_one(c->have_processed, c->will_process, i->name); if (r < 0) return r; - r = ordered_hashmap_reserve(c->have_installed, ordered_hashmap_size(c->will_install)); + r = install_info_traverse(scope, c, root_dir, paths, i, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, NULL); if (r < 0) return r; - } - r = 0; - while ((i = ordered_hashmap_first(c->will_install))) { - assert_se(ordered_hashmap_move_one(c->have_installed, c->will_install, i->name) == 0); - - q = unit_file_search(c, i, paths, root_dir, false, true, NULL); - if (q == -ENOENT) { - /* do nothing */ - } else if (q < 0) { - if (r >= 0) - r = q; + if (i->type != UNIT_FILE_TYPE_REGULAR) + continue; + r = mark_symlink_for_removal(remove_symlinks_to, i->name); + if (r < 0) return r; - } else if (r >= 0) - r += q; - - if (unit_name_is_valid(i->name, UNIT_NAME_INSTANCE)) { - char *unit_file; - - if (i->path) { - unit_file = basename(i->path); - - if (unit_name_is_valid(unit_file, UNIT_NAME_INSTANCE)) - /* unit file named as instance exists, thus all symlinks - * pointing to it will be removed */ - q = mark_symlink_for_removal(remove_symlinks_to, i->name); - else - /* does not exist, thus we will mark for removal symlinks - * to template unit file */ - q = mark_symlink_for_removal(remove_symlinks_to, unit_file); - } else { - /* If i->path is not set, it means that we didn't actually find - * the unit file. But we can still remove symlinks to the - * nonexistent template. */ - r = unit_name_template(i->name, &unit_file); - if (r < 0) - return r; + } - q = mark_symlink_for_removal(remove_symlinks_to, unit_file); - free(unit_file); - } - } else - q = mark_symlink_for_removal(remove_symlinks_to, i->name); + return 0; +} + +int unit_file_mask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_free_ char *prefix = NULL; + char **i; + int r; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + + r = get_config_path(scope, runtime, root_dir, &prefix); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + _cleanup_free_ char *path = NULL; + int q; - if (r >= 0 && q < 0) + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) { + if (r == 0) + r = -EINVAL; + continue; + } + + path = path_make_absolute(*i, prefix); + if (!path) + return -ENOMEM; + + q = create_symlink("/dev/null", path, force, changes, n_changes); + if (q < 0 && r >= 0) r = q; } return r; } -int unit_file_add_dependency( +int unit_file_unmask( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + _cleanup_free_ char *config_path = NULL; + _cleanup_free_ char **todo = NULL; + size_t n_todo = 0, n_allocated = 0; + char **i; + int r, q; + + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + + r = get_config_path(scope, runtime, root_dir, &config_path); + if (r < 0) + return r; + + STRV_FOREACH(i, files) { + _cleanup_free_ char *path = NULL; + + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + + path = path_make_absolute(*i, config_path); + if (!path) + return -ENOMEM; + + r = null_or_empty_path(path); + if (r == -ENOENT) + continue; + if (r < 0) + return r; + if (r == 0) + continue; + + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; + + todo[n_todo++] = *i; + } + + strv_uniq(todo); + + r = 0; + STRV_FOREACH(i, todo) { + _cleanup_free_ char *path = NULL; + + path = path_make_absolute(*i, config_path); + if (!path) + return -ENOMEM; + + if (unlink(path) < 0) { + if (errno != -ENOENT && r >= 0) + r = -errno; + } else { + q = mark_symlink_for_removal(&remove_symlinks_to, path); + if (q < 0) + return q; + + unit_file_changes_add(changes, n_changes, UNIT_FILE_UNLINK, path, NULL); + } + } + + q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + if (r >= 0) + r = q; + + return r; +} + +int unit_file_link( UnitFileScope scope, bool runtime, const char *root_dir, char **files, - char *target, - UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes) { _cleanup_lookup_paths_free_ LookupPaths paths = {}; - _cleanup_(install_context_done) InstallContext c = {}; _cleanup_free_ char *config_path = NULL; + _cleanup_free_ char **todo = NULL; + size_t n_todo = 0, n_allocated = 0; char **i; - int r; - UnitFileInstallInfo *info; + int r, q; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1526,55 +1642,135 @@ int unit_file_add_dependency( return r; STRV_FOREACH(i, files) { - UnitFileState state; + _cleanup_free_ char *full = NULL; + struct stat st; + char *fn; - state = unit_file_get_state(scope, root_dir, *i); - if (state < 0) - return log_error_errno(state, "Failed to get unit file state for %s: %m", *i); + if (!path_is_absolute(*i)) + return -EINVAL; - if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { - log_error("Failed to enable unit: Unit %s is masked", *i); - return -EOPNOTSUPP; - } + fn = basename(*i); + if (!unit_name_is_valid(fn, UNIT_NAME_ANY)) + return -EINVAL; - r = install_info_add_auto(&c, *i); - if (r < 0) - return r; + full = prefix_root(root_dir, *i); + if (!full) + return -ENOMEM; + + if (lstat(full, &st) < 0) + return -errno; + if (S_ISLNK(st.st_mode)) + return -ELOOP; + if (S_ISDIR(st.st_mode)) + return -EISDIR; + if (!S_ISREG(st.st_mode)) + return -ENOTTY; + + q = in_search_path(*i, paths.unit_path); + if (q < 0) + return q; + if (q > 0) + continue; + + if (!GREEDY_REALLOC0(todo, n_allocated, n_todo + 2)) + return -ENOMEM; + + todo[n_todo++] = *i; } - if (!ordered_hashmap_isempty(c.will_install)) { - r = ordered_hashmap_ensure_allocated(&c.have_installed, &string_hash_ops); - if (r < 0) - return r; + strv_uniq(todo); - r = ordered_hashmap_reserve(c.have_installed, ordered_hashmap_size(c.will_install)); - if (r < 0) - return r; + r = 0; + STRV_FOREACH(i, todo) { + _cleanup_free_ char *path = NULL; + + path = path_make_absolute(basename(*i), config_path); + if (!path) + return -ENOMEM; + + q = create_symlink(*i, path, force, changes, n_changes); + if (q < 0 && r >= 0) + r = q; } - while ((info = ordered_hashmap_first(c.will_install))) { - assert_se(ordered_hashmap_move_one(c.have_installed, c.will_install, info->name) == 0); + return r; +} + +int unit_file_add_dependency( + UnitFileScope scope, + bool runtime, + const char *root_dir, + char **files, + const char *target, + UnitDependency dep, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + _cleanup_lookup_paths_free_ LookupPaths paths = {}; + _cleanup_(install_context_done) InstallContext c = {}; + _cleanup_free_ char *config_path = NULL; + UnitFileInstallInfo *i, *target_info; + char **f; + int r; - r = unit_file_search(&c, info, &paths, root_dir, false, false, NULL); + assert(scope >= 0); + assert(scope < _UNIT_FILE_SCOPE_MAX); + assert(target); + + if (!IN_SET(dep, UNIT_WANTS, UNIT_REQUIRES)) + return -EINVAL; + + if (!unit_name_is_valid(target, UNIT_NAME_ANY)) + return -EINVAL; + + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; + + r = get_config_path(scope, runtime, root_dir, &config_path); + if (r < 0) + return r; + + r = install_info_discover(scope, &c, root_dir, &paths, target, SEARCH_FOLLOW_CONFIG_SYMLINKS, &target_info); + if (r < 0) + return r; + if (target_info->type == UNIT_FILE_TYPE_MASKED) + return -ESHUTDOWN; + + assert(target_info->type == UNIT_FILE_TYPE_REGULAR); + + STRV_FOREACH(f, files) { + char ***l; + + r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); if (r < 0) return r; + if (i->type == UNIT_FILE_TYPE_MASKED) + return -ESHUTDOWN; + + assert(i->type == UNIT_FILE_TYPE_REGULAR); + + /* We didn't actually load anything from the unit + * file, but instead just add in our new symlink to + * create. */ if (dep == UNIT_WANTS) - r = strv_extend(&info->wanted_by, target); - else if (dep == UNIT_REQUIRES) - r = strv_extend(&info->required_by, target); + l = &i->wanted_by; else - r = -EINVAL; - - if (r < 0) - return r; + l = &i->required_by; - r = install_info_apply(info, &paths, config_path, root_dir, force, changes, n_changes); - if (r < 0) - return r; + strv_free(*l); + *l = strv_new(target_info->name, NULL); + if (!*l) + return -ENOMEM; } - return 0; + return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_FOLLOW_CONFIG_SYMLINKS, changes, n_changes); } int unit_file_enable( @@ -1588,13 +1784,18 @@ int unit_file_enable( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; - char **i; _cleanup_free_ char *config_path = NULL; + UnitFileInstallInfo *i; + char **f; int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1603,29 +1804,22 @@ int unit_file_enable( if (r < 0) return r; - STRV_FOREACH(i, files) { - UnitFileState state; - - /* We only want to know if this unit is masked, so we ignore - * errors from unit_file_get_state, deferring other checks. - * This allows templated units to be enabled on the fly. */ - state = unit_file_get_state(scope, root_dir, *i); - if (state == UNIT_FILE_MASKED || state == UNIT_FILE_MASKED_RUNTIME) { - log_error("Failed to enable unit: Unit %s is masked", *i); - return -EOPNOTSUPP; - } - - r = install_info_add_auto(&c, *i); + STRV_FOREACH(f, files) { + r = install_info_discover(scope, &c, root_dir, &paths, *f, SEARCH_LOAD, &i); if (r < 0) return r; + if (i->type == UNIT_FILE_TYPE_MASKED) + return -ESHUTDOWN; + + assert(i->type == UNIT_FILE_TYPE_REGULAR); } /* This will return the number of symlink rules that were - supposed to be created, not the ones actually created. This is - useful to determine whether the passed files had any - installation data at all. */ + supposed to be created, not the ones actually created. This + is useful to determine whether the passed files had any + installation data at all. */ - return install_context_apply(&c, &paths, config_path, root_dir, force, changes, n_changes); + return install_context_apply(scope, &c, &paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); } int unit_file_disable( @@ -1638,14 +1832,18 @@ int unit_file_disable( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; - char **i; _cleanup_free_ char *config_path = NULL; _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - int r, q; + char **i; + int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1655,18 +1853,19 @@ int unit_file_disable( return r; STRV_FOREACH(i, files) { - r = install_info_add_auto(&c, *i); + if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) + return -EINVAL; + + r = install_info_add(&c, *i, NULL, NULL); if (r < 0) return r; } - r = install_context_mark_for_removal(&c, &paths, &remove_symlinks_to, config_path, root_dir); - - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); - if (r >= 0) - r = q; + r = install_context_mark_for_removal(scope, &c, &paths, &remove_symlinks_to, config_path, root_dir); + if (r < 0) + return r; - return r; + return remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); } int unit_file_reenable( @@ -1677,21 +1876,30 @@ int unit_file_reenable( bool force, UnitFileChange **changes, unsigned *n_changes) { + + char **n; int r; + size_t l, i; + + /* First, we invoke the disable command with only the basename... */ + l = strv_length(files); + n = newa(char*, l+1); + for (i = 0; i < l; i++) + n[i] = basename(files[i]); + n[i] = NULL; - r = unit_file_disable(scope, runtime, root_dir, files, - changes, n_changes); + r = unit_file_disable(scope, runtime, root_dir, n, changes, n_changes); if (r < 0) return r; - return unit_file_enable(scope, runtime, root_dir, files, force, - changes, n_changes); + /* But the enable command with the full name */ + return unit_file_enable(scope, runtime, root_dir, files, force, changes, n_changes); } int unit_file_set_default( UnitFileScope scope, const char *root_dir, - const char *file, + const char *name, bool force, UnitFileChange **changes, unsigned *n_changes) { @@ -1699,42 +1907,40 @@ int unit_file_set_default( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_(install_context_done) InstallContext c = {}; _cleanup_free_ char *config_path = NULL; - char *path; + UnitFileInstallInfo *i; + const char *path; int r; - UnitFileInstallInfo *i = NULL; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); - assert(file); + assert(name); - if (unit_name_to_type(file) != UNIT_TARGET) + if (unit_name_to_type(name) != UNIT_TARGET) + return -EINVAL; + if (streq(name, SPECIAL_DEFAULT_TARGET)) return -EINVAL; - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = verify_root_dir(scope, &root_dir); if (r < 0) return r; - r = get_config_path(scope, false, root_dir, &config_path); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; - r = install_info_add_auto(&c, file); + r = get_config_path(scope, false, root_dir, &config_path); if (r < 0) return r; - assert_se(i = ordered_hashmap_first(c.will_install)); - - r = unit_file_search(&c, i, &paths, root_dir, false, true, NULL); + r = install_info_discover(scope, &c, root_dir, &paths, name, 0, &i); if (r < 0) return r; + if (i->type == UNIT_FILE_TYPE_MASKED) + return -ESHUTDOWN; path = strjoina(config_path, "/" SPECIAL_DEFAULT_TARGET); - r = create_symlink(i->path, path, force, changes, n_changes); - if (r < 0) - return r; - - return 0; + return create_symlink(i->path, path, force, changes, n_changes); } int unit_file_get_default( @@ -1743,126 +1949,101 @@ int unit_file_get_default( char **name) { _cleanup_lookup_paths_free_ LookupPaths paths = {}; - char **p; + _cleanup_(install_context_done) InstallContext c = {}; + UnitFileInstallInfo *i; + char *n; int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - r = lookup_paths_init_from_scope(&paths, scope, root_dir); + r = verify_root_dir(scope, &root_dir); if (r < 0) return r; - STRV_FOREACH(p, paths.unit_path) { - _cleanup_free_ char *path = NULL, *tmp = NULL; - char *n; - - path = path_join(root_dir, *p, SPECIAL_DEFAULT_TARGET); - if (!path) - return -ENOMEM; - - r = readlink_malloc(path, &tmp); - if (r == -ENOENT) - continue; - else if (r == -EINVAL) - /* not a symlink */ - n = strdup(SPECIAL_DEFAULT_TARGET); - else if (r < 0) - return r; - else - n = strdup(basename(tmp)); + r = lookup_paths_init_from_scope(&paths, scope, root_dir); + if (r < 0) + return r; - if (!n) - return -ENOMEM; + r = install_info_discover(scope, &c, root_dir, &paths, SPECIAL_DEFAULT_TARGET, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + if (r < 0) + return r; + if (i->type == UNIT_FILE_TYPE_MASKED) + return -ESHUTDOWN; - *name = n; - return 0; - } + n = strdup(i->name); + if (!n) + return -ENOMEM; - return -ENOENT; + *name = n; + return 0; } -UnitFileState unit_file_lookup_state( +int unit_file_lookup_state( UnitFileScope scope, const char *root_dir, const LookupPaths *paths, - const char *name) { + const char *name, + UnitFileState *ret) { - UnitFileState state = _UNIT_FILE_STATE_INVALID; - char **i; - _cleanup_free_ char *path = NULL; - int r = 0; + _cleanup_(install_context_done) InstallContext c = {}; + UnitFileInstallInfo *i; + UnitFileState state; + int r; assert(paths); + assert(name); if (!unit_name_is_valid(name, UNIT_NAME_ANY)) return -EINVAL; - STRV_FOREACH(i, paths->unit_path) { - struct stat st; - char *partial; - bool also = false; + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; - free(path); - path = path_join(root_dir, *i, name); - if (!path) - return -ENOMEM; + r = install_info_discover(scope, &c, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + if (r < 0) + return r; - if (root_dir) - partial = path + strlen(root_dir); - else - partial = path; - - /* - * Search for a unit file in our default paths, to - * be sure, that there are no broken symlinks. - */ - if (lstat(path, &st) < 0) { - r = -errno; - if (errno != ENOENT) - return r; + /* Shortcut things, if the caller just wants to know if this unit exists. */ + if (!ret) + return 0; - if (!unit_name_is_valid(name, UNIT_NAME_INSTANCE)) - continue; - } else { - if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) - return -ENOENT; + switch (i->type) { - r = null_or_empty_path(path); - if (r < 0 && r != -ENOENT) - return r; - else if (r > 0) { - state = path_startswith(*i, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; - return state; - } - } + case UNIT_FILE_TYPE_MASKED: + state = path_startswith(i->path, "/run") ? UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; + break; - r = find_symlinks_in_scope(scope, root_dir, name, &state); + case UNIT_FILE_TYPE_REGULAR: + r = find_symlinks_in_scope(scope, root_dir, i->name, &state); if (r < 0) return r; - else if (r > 0) - return state; - - r = unit_file_can_install(paths, root_dir, partial, true, &also); - if (r < 0 && errno != ENOENT) - return r; - else if (r > 0) - return UNIT_FILE_DISABLED; - else if (r == 0) { - if (also) - return UNIT_FILE_INDIRECT; - return UNIT_FILE_STATIC; + if (r == 0) { + if (UNIT_FILE_INSTALL_INFO_HAS_RULES(i)) + state = UNIT_FILE_DISABLED; + else if (UNIT_FILE_INSTALL_INFO_HAS_ALSO(i)) + state = UNIT_FILE_INDIRECT; + else + state = UNIT_FILE_STATIC; } + + break; + + default: + assert_not_reached("Unexpect unit file type."); } - return r < 0 ? r : state; + *ret = state; + return 0; } -UnitFileState unit_file_get_state( +int unit_file_get_state( UnitFileScope scope, const char *root_dir, - const char *name) { + const char *name, + UnitFileState *ret) { _cleanup_lookup_paths_free_ LookupPaths paths = {}; int r; @@ -1871,14 +2052,15 @@ UnitFileState unit_file_get_state( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); - if (root_dir && scope != UNIT_FILE_SYSTEM) - return -EINVAL; + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; - return unit_file_lookup_state(scope, root_dir, &paths, name); + return unit_file_lookup_state(scope, root_dir, &paths, name, ret); } int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char *name) { @@ -1890,6 +2072,13 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char assert(scope < _UNIT_FILE_SCOPE_MAX); assert(name); + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + if (scope == UNIT_FILE_SYSTEM) r = conf_files_list(&files, ".preset", root_dir, "/etc/systemd/system-preset", @@ -1906,13 +2095,14 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char "/usr/lib/systemd/user-preset", NULL); else - return 1; + return 1; /* Default is "enable" */ if (r < 0) return r; STRV_FOREACH(p, files) { _cleanup_fclose_ FILE *f; + char line[LINE_MAX]; f = fopen(*p, "re"); if (!f) { @@ -1922,39 +2112,38 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char return -errno; } - for (;;) { - char line[LINE_MAX], *l; - - if (!fgets(line, sizeof(line), f)) - break; + FOREACH_LINE(line, f, return -errno) { + const char *parameter; + char *l; l = strstrip(line); - if (!*l) - continue; - if (strchr(COMMENTS "\n", *l)) + if (isempty(l)) + continue; + if (strchr(COMMENTS, *l)) continue; - if (first_word(l, "enable")) { - l += 6; - l += strspn(l, WHITESPACE); - - if (fnmatch(l, name, FNM_NOESCAPE) == 0) { + parameter = first_word(l, "enable"); + if (parameter) { + if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { log_debug("Preset file says enable %s.", name); return 1; } - } else if (first_word(l, "disable")) { - l += 7; - l += strspn(l, WHITESPACE); + continue; + } - if (fnmatch(l, name, FNM_NOESCAPE) == 0) { + parameter = first_word(l, "disable"); + if (parameter) { + if (fnmatch(parameter, name, FNM_NOESCAPE) == 0) { log_debug("Preset file says disable %s.", name); return 0; } - } else - log_debug("Couldn't parse line '%s'", l); + continue; + } + + log_debug("Couldn't parse line '%s'", l); } } @@ -1963,6 +2152,86 @@ int unit_file_query_preset(UnitFileScope scope, const char *root_dir, const char return 1; } +static int execute_preset( + UnitFileScope scope, + InstallContext *plus, + InstallContext *minus, + const LookupPaths *paths, + const char *config_path, + const char *root_dir, + char **files, + UnitFilePresetMode mode, + bool force, + UnitFileChange **changes, + unsigned *n_changes) { + + int r; + + assert(plus); + assert(minus); + assert(paths); + assert(config_path); + + if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { + _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; + + r = install_context_mark_for_removal(scope, minus, paths, &remove_symlinks_to, config_path, root_dir); + if (r < 0) + return r; + + r = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes); + } else + r = 0; + + if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { + int q; + + /* Returns number of symlinks that where supposed to be installed. */ + q = install_context_apply(scope, plus, paths, config_path, root_dir, force, SEARCH_LOAD, changes, n_changes); + if (r >= 0) { + if (q < 0) + r = q; + else + r+= q; + } + } + + return r; +} + +static int preset_prepare_one( + UnitFileScope scope, + InstallContext *plus, + InstallContext *minus, + LookupPaths *paths, + const char *root_dir, + UnitFilePresetMode mode, + const char *name) { + + UnitFileInstallInfo *i; + int r; + + if (install_info_find(plus, name) || + install_info_find(minus, name)) + return 0; + + r = unit_file_query_preset(scope, root_dir, name); + if (r < 0) + return r; + + if (r > 0) { + r = install_info_discover(scope, plus, root_dir, paths, name, SEARCH_LOAD|SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + if (r < 0) + return r; + + if (i->type == UNIT_FILE_TYPE_MASKED) + return -ESHUTDOWN; + } else + r = install_info_discover(scope, minus, root_dir, paths, name, SEARCH_FOLLOW_CONFIG_SYMLINKS, &i); + + return r; +} + int unit_file_preset( UnitFileScope scope, bool runtime, @@ -1977,12 +2246,16 @@ int unit_file_preset( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_free_ char *config_path = NULL; char **i; - int r, q; + int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -1992,44 +2265,15 @@ int unit_file_preset( return r; STRV_FOREACH(i, files) { - if (!unit_name_is_valid(*i, UNIT_NAME_ANY)) return -EINVAL; - r = unit_file_query_preset(scope, root_dir, *i); - if (r < 0) - return r; - - if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY) - r = install_info_add_auto(&plus, *i); - else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY) - r = install_info_add_auto(&minus, *i); - else - r = 0; + r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, *i); if (r < 0) return r; } - r = 0; - - if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { - _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - - r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); - - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, files); - if (r == 0) - r = q; - } - - if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { - /* Returns number of symlinks that where supposed to be installed. */ - q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); - if (r == 0) - r = q; - } - - return r; + return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, files, mode, force, changes, n_changes); } int unit_file_preset_all( @@ -2045,12 +2289,16 @@ int unit_file_preset_all( _cleanup_lookup_paths_free_ LookupPaths paths = {}; _cleanup_free_ char *config_path = NULL; char **i; - int r, q; + int r; assert(scope >= 0); assert(scope < _UNIT_FILE_SCOPE_MAX); assert(mode < _UNIT_FILE_PRESET_MAX); + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; + r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) return r; @@ -2062,6 +2310,7 @@ int unit_file_preset_all( STRV_FOREACH(i, paths.unit_path) { _cleanup_closedir_ DIR *d = NULL; _cleanup_free_ char *units_dir; + struct dirent *de; units_dir = path_join(root_dir, *i, NULL); if (!units_dir) @@ -2075,62 +2324,23 @@ int unit_file_preset_all( return -errno; } - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - - if (!de) - break; - - if (hidden_file(de->d_name)) - continue; + FOREACH_DIRENT(de, d, return -errno) { if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) continue; dirent_ensure_type(d, de); - if (de->d_type != DT_REG) + if (!IN_SET(de->d_type, DT_LNK, DT_REG)) continue; - r = unit_file_query_preset(scope, root_dir, de->d_name); - if (r < 0) - return r; - - if (r && mode != UNIT_FILE_PRESET_DISABLE_ONLY) - r = install_info_add_auto(&plus, de->d_name); - else if (!r && mode != UNIT_FILE_PRESET_ENABLE_ONLY) - r = install_info_add_auto(&minus, de->d_name); - else - r = 0; + r = preset_prepare_one(scope, &plus, &minus, &paths, root_dir, mode, de->d_name); if (r < 0) return r; } } - r = 0; - - if (mode != UNIT_FILE_PRESET_ENABLE_ONLY) { - _cleanup_set_free_free_ Set *remove_symlinks_to = NULL; - - r = install_context_mark_for_removal(&minus, &paths, &remove_symlinks_to, config_path, root_dir); - - q = remove_marked_symlinks(remove_symlinks_to, config_path, changes, n_changes, NULL); - if (r == 0) - r = q; - } - - if (mode != UNIT_FILE_PRESET_DISABLE_ONLY) { - q = install_context_apply(&plus, &paths, config_path, root_dir, force, changes, n_changes); - if (r == 0) - r = q; - } - - return r; + return execute_preset(scope, &plus, &minus, &paths, config_path, root_dir, NULL, mode, force, changes, n_changes); } static void unit_file_list_free_one(UnitFileList *f) { @@ -2141,6 +2351,15 @@ static void unit_file_list_free_one(UnitFileList *f) { free(f); } +Hashmap* unit_file_list_free(Hashmap *h) { + UnitFileList *i; + + while ((i = hashmap_steal_first(h))) + unit_file_list_free_one(i); + + return hashmap_free(h); +} + DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one); int unit_file_get_list( @@ -2156,14 +2375,9 @@ int unit_file_get_list( assert(scope < _UNIT_FILE_SCOPE_MAX); assert(h); - if (root_dir && scope != UNIT_FILE_SYSTEM) - return -EINVAL; - - if (root_dir) { - r = access(root_dir, F_OK); - if (r < 0) - return -errno; - } + r = verify_root_dir(scope, &root_dir); + if (r < 0) + return r; r = lookup_paths_init_from_scope(&paths, scope, root_dir); if (r < 0) @@ -2172,6 +2386,7 @@ int unit_file_get_list( STRV_FOREACH(i, paths.unit_path) { _cleanup_closedir_ DIR *d = NULL; _cleanup_free_ char *units_dir; + struct dirent *de; units_dir = path_join(root_dir, *i, NULL); if (!units_dir) @@ -2185,22 +2400,8 @@ int unit_file_get_list( return -errno; } - for (;;) { + FOREACH_DIRENT(de, d, return -errno) { _cleanup_(unit_file_list_free_onep) UnitFileList *f = NULL; - struct dirent *de; - _cleanup_free_ char *path = NULL; - bool also = false; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - - if (!de) - break; - - if (hidden_file(de->d_name)) - continue; if (!unit_name_is_valid(de->d_name, UNIT_NAME_ANY)) continue; @@ -2221,44 +2422,14 @@ int unit_file_get_list( if (!f->path) return -ENOMEM; - r = null_or_empty_path(f->path); - if (r < 0 && r != -ENOENT) - return r; - else if (r > 0) { - f->state = - path_startswith(*i, "/run") ? - UNIT_FILE_MASKED_RUNTIME : UNIT_FILE_MASKED; - goto found; - } - - r = find_symlinks_in_scope(scope, root_dir, de->d_name, &f->state); + r = unit_file_lookup_state(scope, root_dir, &paths, basename(f->path), &f->state); if (r < 0) - return r; - else if (r > 0) { - f->state = UNIT_FILE_ENABLED; - goto found; - } - - path = path_make_absolute(de->d_name, *i); - if (!path) - return -ENOMEM; + f->state = UNIT_FILE_BAD; - r = unit_file_can_install(&paths, root_dir, path, true, &also); - if (r == -EINVAL || /* Invalid setting? */ - r == -EBADMSG || /* Invalid format? */ - r == -ENOENT /* Included file not found? */) - f->state = UNIT_FILE_INVALID; - else if (r < 0) - return r; - else if (r > 0) - f->state = UNIT_FILE_DISABLED; - else - f->state = also ? UNIT_FILE_INDIRECT : UNIT_FILE_STATIC; - - found: r = hashmap_put(h, basename(f->path), f); if (r < 0) return r; + f = NULL; /* prevent cleanup */ } } @@ -2276,7 +2447,7 @@ static const char* const unit_file_state_table[_UNIT_FILE_STATE_MAX] = { [UNIT_FILE_STATIC] = "static", [UNIT_FILE_DISABLED] = "disabled", [UNIT_FILE_INDIRECT] = "indirect", - [UNIT_FILE_INVALID] = "invalid", + [UNIT_FILE_BAD] = "bad", }; DEFINE_STRING_TABLE_LOOKUP(unit_file_state, UnitFileState); diff --git a/src/shared/install.h b/src/shared/install.h index a9d77dd91b..45a417df92 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -25,13 +25,15 @@ typedef enum UnitFileScope UnitFileScope; typedef enum UnitFileState UnitFileState; typedef enum UnitFilePresetMode UnitFilePresetMode; typedef enum UnitFileChangeType UnitFileChangeType; +typedef enum UnitFileType UnitFileType; typedef struct UnitFileChange UnitFileChange; typedef struct UnitFileList UnitFileList; typedef struct UnitFileInstallInfo UnitFileInstallInfo; #include "hashmap.h" -#include "unit-name.h" #include "path-lookup.h" +#include "strv.h" +#include "unit-name.h" enum UnitFileScope { UNIT_FILE_SYSTEM, @@ -51,7 +53,7 @@ enum UnitFileState { UNIT_FILE_STATIC, UNIT_FILE_DISABLED, UNIT_FILE_INDIRECT, - UNIT_FILE_INVALID, + UNIT_FILE_BAD, _UNIT_FILE_STATE_MAX, _UNIT_FILE_STATE_INVALID = -1 }; @@ -82,10 +84,17 @@ struct UnitFileList { UnitFileState state; }; +enum UnitFileType { + UNIT_FILE_TYPE_REGULAR, + UNIT_FILE_TYPE_SYMLINK, + UNIT_FILE_TYPE_MASKED, + _UNIT_FILE_TYPE_MAX, + _UNIT_FILE_TYPE_INVALID = -1, +}; + struct UnitFileInstallInfo { char *name; char *path; - char *user; char **aliases; char **wanted_by; @@ -93,8 +102,26 @@ struct UnitFileInstallInfo { char **also; char *default_instance; + + UnitFileType type; + + char *symlink_target; }; +static inline bool UNIT_FILE_INSTALL_INFO_HAS_RULES(UnitFileInstallInfo *i) { + assert(i); + + return !strv_isempty(i->aliases) || + !strv_isempty(i->wanted_by) || + !strv_isempty(i->required_by); +} + +static inline bool UNIT_FILE_INSTALL_INFO_HAS_ALSO(UnitFileInstallInfo *i) { + assert(i); + + return !strv_isempty(i->also); +} + int unit_file_enable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_disable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); int unit_file_reenable(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes); @@ -105,21 +132,14 @@ int unit_file_mask(UnitFileScope scope, bool runtime, const char *root_dir, char int unit_file_unmask(UnitFileScope scope, bool runtime, const char *root_dir, char **files, UnitFileChange **changes, unsigned *n_changes); int unit_file_set_default(UnitFileScope scope, const char *root_dir, const char *file, bool force, UnitFileChange **changes, unsigned *n_changes); int unit_file_get_default(UnitFileScope scope, const char *root_dir, char **name); -int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); - -UnitFileState unit_file_lookup_state( - UnitFileScope scope, - const char *root_dir, - const LookupPaths *paths, - const char *name); -UnitFileState unit_file_get_state( - UnitFileScope scope, - const char *root_dir, - const char *filename); +int unit_file_add_dependency(UnitFileScope scope, bool runtime, const char *root_dir, char **files, const char *target, UnitDependency dep, bool force, UnitFileChange **changes, unsigned *n_changes); + +int unit_file_lookup_state(UnitFileScope scope, const char *root_dir,const LookupPaths *paths, const char *name, UnitFileState *ret); +int unit_file_get_state(UnitFileScope scope, const char *root_dir, const char *filename, UnitFileState *ret); int unit_file_get_list(UnitFileScope scope, const char *root_dir, Hashmap *h); +Hashmap* unit_file_list_free(Hashmap *h); -void unit_file_list_free(Hashmap *h); int unit_file_changes_add(UnitFileChange **changes, unsigned *n_changes, UnitFileChangeType type, const char *path, const char *source); void unit_file_changes_free(UnitFileChange *changes, unsigned n_changes); diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index dbc07aa7ad..0313b0946f 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -19,25 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <time.h> #include <errno.h> -#include <sys/socket.h> -#include <string.h> #include <fcntl.h> +#include <string.h> +#include <sys/socket.h> +#include <time.h> -#include "logs-show.h" -#include "log.h" -#include "util.h" -#include "utf8.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" #include "hashmap.h" +#include "hostname-util.h" +#include "io-util.h" #include "journal-internal.h" -#include "formats-util.h" +#include "log.h" +#include "logs-show.h" +#include "parse-util.h" #include "process-util.h" +#include "string-table.h" +#include "string-util.h" #include "terminal-util.h" -#include "hostname-util.h" +#include "utf8.h" +#include "util.h" -/* up to three lines (each up to 100 characters), - or 300 characters, whichever is less */ +/* up to three lines (each up to 100 characters) or 300 characters, whichever is less */ #define PRINT_LINE_THRESHOLD 3 #define PRINT_CHAR_THRESHOLD 300 diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 9c1e4d5e13..2c1da0a40d 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -23,15 +23,22 @@ #include <linux/fs.h> #include <sys/statfs.h> +#include "alloc-util.h" #include "btrfs-util.h" +#include "chattr-util.h" #include "copy.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "machine-image.h" #include "mkdir.h" #include "path-util.h" #include "rm-rf.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "utf8.h" - -#include "machine-image.h" +#include "xattr-util.h" static const char image_search_path[] = "/var/lib/machines\0" @@ -176,11 +183,10 @@ static int image_make( return r; if (r) { BtrfsSubvolInfo info; - BtrfsQuotaInfo quota; /* It's a btrfs subvolume */ - r = btrfs_subvol_get_info_fd(fd, &info); + r = btrfs_subvol_get_info_fd(fd, 0, &info); if (r < 0) return r; @@ -195,13 +201,17 @@ static int image_make( if (r < 0) return r; - r = btrfs_subvol_get_quota_fd(fd, "a); - if (r >= 0) { - (*ret)->usage = quota.referenced; - (*ret)->usage_exclusive = quota.exclusive; + if (btrfs_quota_scan_ongoing(fd) == 0) { + BtrfsQuotaInfo quota; - (*ret)->limit = quota.referenced_max; - (*ret)->limit_exclusive = quota.exclusive_max; + r = btrfs_subvol_get_subtree_quota_fd(fd, 0, "a); + if (r >= 0) { + (*ret)->usage = quota.referenced; + (*ret)->usage_exclusive = quota.exclusive; + + (*ret)->limit = quota.referenced_max; + (*ret)->limit_exclusive = quota.exclusive_max; + } } return 1; @@ -397,7 +407,7 @@ int image_remove(Image *i) { switch (i->type) { case IMAGE_SUBVOLUME: - r = btrfs_subvol_remove(i->path, true); + r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (r < 0) return r; break; @@ -587,7 +597,12 @@ int image_clone(Image *i, const char *new_name, bool read_only) { case IMAGE_DIRECTORY: new_path = strjoina("/var/lib/machines/", new_name); - r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot(i->path, new_path, (read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); + + /* Enable "subtree" quotas for the copy, if we didn't + * copy any quota from the source. */ + (void) btrfs_subvol_auto_qgroup(i->path, 0, true); + break; case IMAGE_RAW: @@ -629,6 +644,10 @@ int image_read_only(Image *i, bool b) { switch (i->type) { case IMAGE_SUBVOLUME: + + /* Note that we set the flag only on the top-level + * subvolume of the image. */ + r = btrfs_subvol_set_read_only(i->path, b); if (r < 0) return r; @@ -729,7 +748,14 @@ int image_set_limit(Image *i, uint64_t referenced_max) { if (i->type != IMAGE_SUBVOLUME) return -EOPNOTSUPP; - return btrfs_quota_limit(i->path, referenced_max); + /* We set the quota both for the subvolume as well as for the + * subtree. The latter is mostly for historical reasons, since + * we didn't use to have a concept of subtree quota, and hence + * only modified the subvolume quota. */ + + (void) btrfs_qgroup_set_limit(i->path, 0, referenced_max); + (void) btrfs_subvol_auto_qgroup(i->path, 0, true); + return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max); } int image_name_lock(const char *name, int operation, LockFile *ret) { diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index 8af78f47d5..4172a63fd0 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -19,19 +19,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <sys/mount.h> #include <sys/prctl.h> -#include <sys/vfs.h> #include <sys/statvfs.h> -#include <sys/mount.h> +#include <sys/vfs.h> -#include "util.h" -#include "process-util.h" +#include "alloc-util.h" +#include "btrfs-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "lockfile-util.h" +#include "machine-pool.h" #include "mkdir.h" -#include "btrfs-util.h" +#include "mount-util.h" +#include "parse-util.h" #include "path-util.h" +#include "process-util.h" #include "signal-util.h" -#include "machine-pool.h" +#include "stat-util.h" +#include "string-util.h" +#include "util.h" #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL) #define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL) @@ -170,7 +178,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { }; _cleanup_close_ int fd = -1, control = -1, loop = -1; _cleanup_free_ char* loopdev = NULL; - char tmpdir[] = "/tmp/import-mount.XXXXXX", *mntdir = NULL; + char tmpdir[] = "/tmp/machine-pool.XXXXXX", *mntdir = NULL; bool tmpdir_made = false, mntdir_made = false, mntdir_mounted = false; char buf[FORMAT_BYTES_MAX]; int r, nr = -1; @@ -194,14 +202,35 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { r = btrfs_quota_enable("/var/lib/machines", true); if (r < 0) - log_warning_errno(r, "Failed to enable quota, ignoring: %m"); + log_warning_errno(r, "Failed to enable quota for /var/lib/machines, ignoring: %m"); + + r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true); + if (r < 0) + log_warning_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, ignoring: %m"); + + return 1; + } + if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0) { + log_debug("/var/lib/machines is already a mount point, not creating loopback file for it."); return 0; } - if (path_is_mount_point("/var/lib/machines", AT_SYMLINK_FOLLOW) > 0 || - dir_is_empty("/var/lib/machines") == 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "/var/lib/machines is not a btrfs file system. Operation is not supported on legacy file systems."); + r = dir_is_populated("/var/lib/machines"); + if (r < 0 && r != -ENOENT) + return r; + if (r > 0) { + log_debug("/var/log/machines is already populated, not creating loopback file for it."); + return 0; + } + + r = mkfs_exists("btrfs"); + if (r == -ENOENT) { + log_debug("mkfs.btrfs is missing, cannot create loopback file for /var/lib/machines."); + return 0; + } + if (r < 0) + return r; fd = setup_machine_raw(size, error); if (fd < 0) @@ -266,6 +295,10 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { if (r < 0) log_warning_errno(r, "Failed to enable quota, ignoring: %m"); + r = btrfs_subvol_auto_qgroup(mntdir, 0, true); + if (r < 0) + log_warning_errno(r, "Failed to set up default quota hierarchy, ignoring: %m"); + if (chmod(mntdir, 0700) < 0) { r = sd_bus_error_set_errnof(error, errno, "Failed to fix owner: %m"); goto fail; @@ -286,7 +319,7 @@ int setup_machine_directory(uint64_t size, sd_bus_error *error) { (void) rmdir(mntdir); (void) rmdir(tmpdir); - return 0; + return 1; fail: if (mntdir_mounted) @@ -345,7 +378,7 @@ int grow_machine_directory(void) { if (b.f_bavail > b.f_blocks / 3) return 0; - /* Calculate how much we are willing to add at maximum */ + /* Calculate how much we are willing to add at most */ max_add = ((uint64_t) a.f_bavail * (uint64_t) a.f_bsize) - VAR_LIB_MACHINES_FREE_MIN; /* Calculate the old size */ @@ -370,9 +403,11 @@ int grow_machine_directory(void) { if (r <= 0) return r; - r = btrfs_quota_limit("/var/lib/machines", new_size); - if (r < 0) - return r; + /* Also bump the quota, of both the subvolume leaf qgroup, as + * well as of any subtree quota group by the same id but a + * higher level, if it exists. */ + (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, new_size); + (void) btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, new_size); log_info("Grew /var/lib/machines btrfs loopback file system to %s.", format_bytes(buf, sizeof(buf), new_size)); return 1; diff --git a/src/shared/pager.c b/src/shared/pager.c index d8f0fb404d..d149bc1722 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -21,17 +21,20 @@ #include <fcntl.h> #include <stdlib.h> -#include <unistd.h> #include <string.h> #include <sys/prctl.h> +#include <unistd.h> +#include "copy.h" +#include "fd-util.h" +#include "locale-util.h" +#include "macro.h" #include "pager.h" -#include "util.h" #include "process-util.h" -#include "macro.h" -#include "terminal-util.h" #include "signal-util.h" -#include "copy.h" +#include "string-util.h" +#include "terminal-util.h" +#include "util.h" static pid_t pager_pid = 0; diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 34eec959ef..d71f379e76 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -24,11 +24,13 @@ #include <string.h> #include <errno.h> +#include "alloc-util.h" #include "util.h" #include "strv.h" #include "path-util.h" -#include "path-lookup.h" #include "install.h" +#include "string-util.h" +#include "path-lookup.h" int user_config_home(char **config_home) { const char *e; @@ -210,7 +212,7 @@ static char** user_dirs( if (strv_extend(&res, generator_late) < 0) return NULL; - if (!path_strv_make_absolute_cwd(res)) + if (path_strv_make_absolute_cwd(res) < 0) return NULL; tmp = res; @@ -244,6 +246,7 @@ int lookup_paths_init( const char *e; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ + int r; assert(p); @@ -259,9 +262,9 @@ int lookup_paths_init( /* FIXME: empty components in other places should be * rejected. */ - p->unit_path = path_split_and_make_absolute(e); - if (!p->unit_path) - return -ENOMEM; + r = path_split_and_make_absolute(e, &p->unit_path); + if (r < 0) + return r; } else p->unit_path = NULL; @@ -269,7 +272,6 @@ int lookup_paths_init( /* Let's figure something out. */ _cleanup_strv_free_ char **unit_path; - int r; /* For the user units we include share/ in the search * path in order to comply with the XDG basedir spec. @@ -342,9 +344,9 @@ int lookup_paths_init( e = getenv("SYSTEMD_SYSVINIT_PATH"); if (e) { - p->sysvinit_path = path_split_and_make_absolute(e); - if (!p->sysvinit_path) - return -ENOMEM; + r = path_split_and_make_absolute(e, &p->sysvinit_path); + if (r < 0) + return r; } else p->sysvinit_path = NULL; @@ -360,9 +362,9 @@ int lookup_paths_init( e = getenv("SYSTEMD_SYSVRCND_PATH"); if (e) { - p->sysvrcnd_path = path_split_and_make_absolute(e); - if (!p->sysvrcnd_path) - return -ENOMEM; + r = path_split_and_make_absolute(e, &p->sysvrcnd_path); + if (r < 0) + return r; } else p->sysvrcnd_path = NULL; @@ -417,9 +419,8 @@ void lookup_paths_free(LookupPaths *p) { p->unit_path = strv_free(p->unit_path); #ifdef HAVE_SYSV_COMPAT - strv_free(p->sysvinit_path); - strv_free(p->sysvrcnd_path); - p->sysvinit_path = p->sysvrcnd_path = NULL; + p->sysvinit_path = strv_free(p->sysvinit_path); + p->sysvrcnd_path = strv_free(p->sysvrcnd_path); #endif } diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 7749f20540..63e81f4894 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -24,8 +24,10 @@ #include <limits.h> #include <termios.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "ptyfwd.h" +#include "util.h" struct PTYForward { sd_event *event; @@ -411,6 +413,7 @@ PTYForward *pty_forward_free(PTYForward *f) { sd_event_source_unref(f->stdin_event_source); sd_event_source_unref(f->stdout_event_source); sd_event_source_unref(f->master_event_source); + sd_event_source_unref(f->sigwinch_event_source); sd_event_unref(f->event); if (f->saved_stdout) diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index d73a74912e..c518cf83ec 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -21,6 +21,7 @@ #include <seccomp.h> +#include "string-util.h" #include "util.h" #include "seccomp-util.h" diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 3dedbd1f62..39b836d053 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -21,10 +21,15 @@ #include <stdio.h> +#include "alloc-util.h" #include "conf-parser.h" -#include "sleep-config.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" +#include "parse-util.h" +#include "sleep-config.h" +#include "string-util.h" #include "strv.h" #include "util.h" @@ -49,7 +54,7 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) { }; config_parse_many(PKGSYSCONFDIR "/sleep.conf", - CONF_DIRS_NULSTR("systemd/sleep.conf"), + CONF_PATHS_NULSTR("systemd/sleep.conf.d"), "Sleep\0", config_item_table_lookup, items, false, NULL); diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c index 4db249e1ca..ec6e5a8312 100644 --- a/src/shared/spawn-polkit-agent.c +++ b/src/shared/spawn-polkit-agent.c @@ -25,10 +25,13 @@ #include <errno.h> #include <poll.h> +#include "fd-util.h" +#include "io-util.h" #include "log.h" -#include "util.h" #include "process-util.h" #include "spawn-polkit-agent.h" +#include "stdio-util.h" +#include "util.h" #ifdef ENABLE_POLKIT static pid_t agent_pid = 0; @@ -76,8 +79,9 @@ void polkit_agent_close(void) { return; /* Inform agent that we are done */ - kill(agent_pid, SIGTERM); - kill(agent_pid, SIGCONT); + (void) kill(agent_pid, SIGTERM); + (void) kill(agent_pid, SIGCONT); + (void) wait_for_terminate(agent_pid, NULL); agent_pid = 0; } diff --git a/src/shared/specifier.c b/src/shared/specifier.c index 85bd477f2d..c5c4a4d7d7 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -22,10 +22,12 @@ #include <string.h> #include <sys/utsname.h> -#include "macro.h" -#include "util.h" +#include "alloc-util.h" #include "hostname-util.h" +#include "macro.h" #include "specifier.h" +#include "string-util.h" +#include "util.h" /* * Generic infrastructure for replacing %x style specifiers in diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index b12189cd10..fc885f6cb8 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -19,21 +19,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/stat.h> -#include <stdbool.h> #include <errno.h> +#include <fcntl.h> +#include <stdbool.h> #include <string.h> #include <sys/mount.h> +#include <sys/stat.h> #include <unistd.h> -#include <fcntl.h> -#include "util.h" -#include "path-util.h" -#include "mkdir.h" -#include "rm-rf.h" #include "base-filesystem.h" +#include "fd-util.h" #include "missing.h" +#include "mkdir.h" +#include "path-util.h" +#include "rm-rf.h" +#include "string-util.h" #include "switch-root.h" +#include "user-util.h" +#include "util.h" int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) { diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c index b2cab948ef..21cb82ea1c 100644 --- a/src/shared/sysctl-util.c +++ b/src/shared/sysctl-util.c @@ -29,6 +29,7 @@ #include "fileio.h" #include "log.h" +#include "string-util.h" #include "util.h" #include "sysctl-util.h" diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c index 4794ff45bb..079dd8752c 100644 --- a/src/shared/uid-range.c +++ b/src/shared/uid-range.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "uid-range.h" +#include "user-util.h" +#include "util.h" static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) { assert(range); diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c index 63f1e4ca6f..13b32a0509 100644 --- a/src/shared/utmp-wtmp.c +++ b/src/shared/utmp-wtmp.c @@ -19,18 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <utmpx.h> #include <errno.h> +#include <fcntl.h> +#include <poll.h> #include <string.h> #include <sys/utsname.h> -#include <fcntl.h> #include <unistd.h> -#include <poll.h> +#include <utmpx.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "hostname-util.h" #include "macro.h" #include "path-util.h" +#include "string-util.h" #include "terminal-util.h" -#include "hostname-util.h" +#include "user-util.h" #include "utmp-wtmp.h" int utmp_get_runlevel(int *runlevel, int *previous) { diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index 9d39beb340..d58f9873d5 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -27,6 +27,7 @@ #include "watchdog.h" #include "log.h" +#include "fd-util.h" static int watchdog_fd = -1; static usec_t watchdog_timeout = USEC_INFINITY; diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 1ba66eb998..95de369817 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -27,9 +27,11 @@ #include "sd-messages.h" #include "def.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" #include "sleep-config.h" +#include "string-util.h" #include "strv.h" #include "util.h" diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index 73c04fdfc0..ba82adadb4 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -34,10 +34,13 @@ #include "sd-event.h" #include "sd-resolve.h" +#include "alloc-util.h" +#include "fd-util.h" #include "log.h" #include "path-util.h" #include "set.h" #include "socket-util.h" +#include "string-util.h" #include "util.h" #define BUFFER_SIZE (256 * 1024) diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index ee34209a30..25b5ff52ea 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -28,17 +28,20 @@ #include <string.h> #include "conf-files.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" #include "hashmap.h" #include "log.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" #include "sysctl-util.h" #include "util.h" static char **arg_prefixes = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysctl"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysctl.d"); static int apply_all(Hashmap *sysctl_options) { char *property, *value; @@ -85,8 +88,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno if (feof(f)) break; - log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); } p = strstrip(l); diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c index 00045150f6..6c2f53774d 100644 --- a/src/system-update-generator/system-update-generator.c +++ b/src/system-update-generator/system-update-generator.c @@ -22,7 +22,9 @@ #include <errno.h> #include <unistd.h> +#include "fs-util.h" #include "log.h" +#include "string-util.h" #include "util.h" /* diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 420a246be1..51b82d57db 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -37,6 +37,7 @@ #include "sd-daemon.h" #include "sd-login.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-error.h" #include "bus-message.h" @@ -48,32 +49,42 @@ #include "efivars.h" #include "env-util.h" #include "exit-status.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "glob-util.h" #include "hostname-util.h" #include "initreq.h" #include "install.h" +#include "io-util.h" #include "list.h" +#include "locale-util.h" #include "log.h" #include "logs-show.h" #include "macro.h" #include "mkdir.h" #include "pager.h" +#include "parse-util.h" #include "path-lookup.h" #include "path-util.h" #include "process-util.h" +#include "rlimit-util.h" #include "set.h" #include "signal-util.h" #include "socket-util.h" #include "spawn-ask-password-agent.h" #include "spawn-polkit-agent.h" #include "special.h" +#include "stat-util.h" #include "strv.h" #include "terminal-util.h" #include "unit-name.h" +#include "user-util.h" #include "util.h" #include "utmp-wtmp.h" #include "verbs.h" +#include "virt.h" static char **arg_types = NULL; static char **arg_states = NULL; @@ -107,7 +118,7 @@ static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL; static char **arg_wall = NULL; static const char *arg_kill_who = NULL; static int arg_signal = SIGTERM; -static const char *arg_root = NULL; +static char *arg_root = NULL; static usec_t arg_when = 0; static enum action { _ACTION_INVALID, @@ -285,6 +296,10 @@ static bool install_client_side(void) { if (arg_scope == UNIT_FILE_GLOBAL) return true; + /* Unsupported environment variable, mostly for debugging purposes */ + if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0) + return true; + return false; } @@ -1320,7 +1335,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { UNIT_FILE_MASKED, UNIT_FILE_MASKED_RUNTIME, UNIT_FILE_DISABLED, - UNIT_FILE_INVALID)) { + UNIT_FILE_BAD)) { on = ansi_highlight_red(); off = ansi_normal(); } else if (u->state == UNIT_FILE_ENABLED) { @@ -1488,16 +1503,12 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha static const char *dependencies[_DEPENDENCY_MAX] = { [DEPENDENCY_FORWARD] = "Requires\0" - "RequiresOverridable\0" "Requisite\0" - "RequisiteOverridable\0" "Wants\0" "ConsistsOf\0" "BindsTo\0", [DEPENDENCY_REVERSE] = "RequiredBy\0" - "RequiredByOverridable\0" "RequisiteOf\0" - "RequisiteOfOverridable\0" "WantedBy\0" "PartOf\0" "BoundBy\0", @@ -2171,7 +2182,7 @@ static int list_jobs(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); output_jobs_list(jobs, c, skipped); - return r; + return 0; } static int cancel_job(int argc, char *argv[], void *userdata) { @@ -3475,7 +3486,8 @@ static void print_status_info( dir = mfree(dir); - if (path_get_parent(*dropin, &dir) < 0) { + dir = dirname_malloc(*dropin); + if (!dir) { log_oom(); return; } @@ -4889,102 +4901,6 @@ static int set_property(int argc, char *argv[], void *userdata) { return 0; } -static int snapshot(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_free_ char *n = NULL, *id = NULL; - const char *path; - sd_bus *bus; - int r; - - polkit_agent_open_if_enabled(); - - if (argc > 1) { - r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".snapshot", &n); - if (r < 0) - return log_error_errno(r, "Failed to generate unit name: %m"); - } else { - n = strdup(""); - if (!n) - return log_oom(); - } - - r = acquire_bus(BUS_MANAGER, &bus); - if (r < 0) - return r; - - r = sd_bus_call_method( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "CreateSnapshot", - &error, - &reply, - "sb", n, false); - if (r < 0) - return log_error_errno(r, "Failed to create snapshot: %s", bus_error_message(&error, r)); - - r = sd_bus_message_read(reply, "o", &path); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_get_property_string( - bus, - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Unit", - "Id", - &error, - &id); - if (r < 0) - return log_error_errno(r, "Failed to get ID of snapshot: %s", bus_error_message(&error, r)); - - if (!arg_quiet) - puts(id); - - return 0; -} - -static int delete_snapshot(int argc, char *argv[], void *userdata) { - _cleanup_strv_free_ char **names = NULL; - sd_bus *bus; - char **name; - int r; - - polkit_agent_open_if_enabled(); - - r = acquire_bus(BUS_MANAGER, &bus); - if (r < 0) - return r; - - r = expand_names(bus, strv_skip(argv, 1), ".snapshot", &names); - if (r < 0) - return log_error_errno(r, "Failed to expand names: %m"); - - STRV_FOREACH(name, names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - int q; - - q = sd_bus_call_method( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "RemoveSnapshot", - &error, - NULL, - "s", *name); - if (q < 0) { - log_error_errno(q, "Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q)); - if (r == 0) - r = q; - } - } - - return r; -} - static int daemon_reload(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; const char *method; @@ -5305,6 +5221,9 @@ static int enable_sysv_units(const char *verb, char **args) { if (arg_scope != UNIT_FILE_SYSTEM) return 0; + if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0) + return 0; + if (!STR_IN_SET(verb, "enable", "disable", @@ -5514,10 +5433,10 @@ static int enable_unit(int argc, char *argv[], void *userdata) { else assert_not_reached("Unknown verb"); - if (r < 0) { - log_error_errno(r, "Operation failed: %m"); - goto finish; - } + if (r == -ESHUTDOWN) + return log_error_errno(r, "Unit file is masked."); + if (r < 0) + return log_error_errno(r, "Operation failed: %m"); if (!arg_quiet) dump_unit_file_changes(changes, n_changes); @@ -5634,7 +5553,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) { r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) - return r; + goto finish; new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop"); for (i = 0; i < n_changes; i++) @@ -5680,7 +5599,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) { unsigned n_changes = 0; r = unit_file_add_dependency(arg_scope, arg_runtime, arg_root, names, target, dep, arg_force, &changes, &n_changes); - + if (r == -ESHUTDOWN) + return log_error_errno(r, "Unit file is masked."); if (r < 0) return log_error_errno(r, "Can't add dependency: %m"); @@ -5817,8 +5737,8 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { STRV_FOREACH(name, names) { UnitFileState state; - state = unit_file_get_state(arg_scope, arg_root, *name); - if (state < 0) + r = unit_file_get_state(arg_scope, arg_root, *name, &state); + if (r < 0) return log_error_errno(state, "Failed to get unit file state for %s: %m", *name); if (IN_SET(state, @@ -6362,9 +6282,6 @@ static void systemctl_help(void) { "Job Commands:\n" " list-jobs [PATTERN...] List jobs\n" " cancel [JOB...] Cancel all, one, or more jobs\n\n" - "Snapshot Commands:\n" - " snapshot [NAME] Create a snapshot\n" - " delete NAME... Remove one or more snapshots\n\n" "Environment Commands:\n" " show-environment Dump environment\n" " set-environment NAME=VALUE... Set one or more environment variables\n" @@ -6507,11 +6424,6 @@ static void help_states(void) { puts(slice_state_to_string(i)); if (!arg_no_legend) - puts("\nAvailable snapshot unit substates:"); - for (i = 0; i < _SNAPSHOT_STATE_MAX; i++) - puts(snapshot_state_to_string(i)); - - if (!arg_no_legend) puts("\nAvailable socket unit substates:"); for (i = 0; i < _SOCKET_STATE_MAX; i++) puts(socket_state_to_string(i)); @@ -6612,7 +6524,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { {} }; - int c; + const char *p; + int c, r; assert(argc >= 0); assert(argv); @@ -6632,15 +6545,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return version(); case 't': { - const char *word, *state; - size_t size; + if (isempty(optarg)) + return log_error_errno(r, "--type requires arguments."); - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { - _cleanup_free_ char *type; + p = optarg; + for(;;) { + _cleanup_free_ char *type = NULL; - type = strndup(word, size); - if (!type) - return -ENOMEM; + r = extract_first_word(&p, &type, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse type: %s", optarg); + + if (r == 0) + break; if (streq(type, "help")) { help_types(); @@ -6681,18 +6598,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) { if (!arg_properties) return log_oom(); } else { - const char *word, *state; - size_t size; + p = optarg; + for(;;) { + _cleanup_free_ char *prop = NULL; - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { - char *prop; + r = extract_first_word(&p, &prop, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse property: %s", optarg); - prop = strndup(word, size); - if (!prop) - return log_oom(); + if (r == 0) + break; - if (strv_consume(&arg_properties, prop) < 0) + if (strv_push(&arg_properties, prop) < 0) return log_oom(); + + prop = NULL; } } @@ -6769,7 +6689,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - arg_root = optarg; + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case 'l': @@ -6856,15 +6778,19 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_STATE: { - const char *word, *state; - size_t size; + if (isempty(optarg)) + return log_error_errno(r, "--signal requires arguments."); - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { + p = optarg; + for(;;) { _cleanup_free_ char *s = NULL; - s = strndup(word, size); - if (!s) - return log_oom(); + r = extract_first_word(&p, &s, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse signal: %s", optarg); + + if (r == 0) + break; if (streq(s, "help")) { help_states(); @@ -7399,14 +7325,14 @@ static int talk_initctl(void) { static int systemctl_main(int argc, char *argv[]) { static const Verb verbs[] = { - { "list-units", VERB_ANY, 1, VERB_DEFAULT, list_units }, - { "list-unit-files", VERB_ANY, 1, 0, list_unit_files }, - { "list-sockets", VERB_ANY, 1, 0, list_sockets }, - { "list-timers", VERB_ANY, 1, 0, list_timers }, - { "list-jobs", VERB_ANY, 1, 0, list_jobs }, - { "list-machines", VERB_ANY, 1, 0, list_machines }, + { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units }, + { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files }, + { "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets }, + { "list-timers", VERB_ANY, VERB_ANY, 0, list_timers }, + { "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs }, + { "list-machines", VERB_ANY, VERB_ANY, 0, list_machines }, { "clear-jobs", VERB_ANY, 1, 0, daemon_reload }, - { "cancel", 2, VERB_ANY, 0, cancel_job }, + { "cancel", VERB_ANY, VERB_ANY, 0, cancel_job }, { "start", 2, VERB_ANY, 0, start_unit }, { "stop", 2, VERB_ANY, 0, start_unit }, { "condstop", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */ @@ -7427,8 +7353,6 @@ static int systemctl_main(int argc, char *argv[]) { { "cat", 2, VERB_ANY, 0, cat }, { "status", VERB_ANY, VERB_ANY, 0, show }, { "help", VERB_ANY, VERB_ANY, 0, show }, - { "snapshot", VERB_ANY, 2, 0, snapshot }, - { "delete", 2, VERB_ANY, 0, delete_snapshot }, { "daemon-reload", VERB_ANY, 1, 0, daemon_reload }, { "daemon-reexec", VERB_ANY, 1, 0, daemon_reload }, { "show-environment", VERB_ANY, 1, 0, show_environment }, @@ -7778,8 +7702,11 @@ finish: strv_free(arg_properties); strv_free(arg_wall); + free(arg_root); release_busses(); + /* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */ + return r < 0 ? EXIT_FAILURE : r; } diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 38cb2a1102..fc11725821 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -24,7 +24,7 @@ ***/ #include <sys/types.h> -#include <stdint.h> +#include <inttypes.h> #include "_sd-common.h" diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 4291fb7ebc..c0146158f3 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -22,12 +22,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/in.h> +#include <inttypes.h> #include <net/ethernet.h> +#include <netinet/in.h> +#include <sys/types.h> #include "sd-event.h" #include "sd-dhcp-lease.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + enum { SD_DHCP_CLIENT_EVENT_STOP = 0, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1, @@ -72,4 +78,6 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int pri int sd_dhcp_client_detach_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h index ed5bceecdd..38222594e7 100644 --- a/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/sd-dhcp-lease.h @@ -23,8 +23,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/in.h> +#include <inttypes.h> #include <net/ethernet.h> +#include <netinet/in.h> +#include <sys/types.h> + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; typedef struct sd_dhcp_lease sd_dhcp_lease; struct sd_dhcp_route; @@ -52,4 +58,6 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 4b0c7a1852..55bceb1ea5 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -23,10 +23,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> +#include <inttypes.h> #include <netinet/in.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; typedef struct sd_dhcp_server sd_dhcp_server; @@ -39,7 +42,7 @@ int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int pri int sd_dhcp_server_detach_event(sd_dhcp_server *client); sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client); -bool sd_dhcp_server_is_running(sd_dhcp_server *server); +int sd_dhcp_server_is_running(sd_dhcp_server *server); int sd_dhcp_server_start(sd_dhcp_server *server); int sd_dhcp_server_stop(sd_dhcp_server *server); @@ -55,4 +58,6 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t); int sd_dhcp_server_forcerenew(sd_dhcp_server *server); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 90c35ef3f6..9f0e92806e 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -22,12 +22,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <net/ethernet.h> +#include <sys/types.h> #include "sd-event.h" - #include "sd-dhcp6-lease.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + enum { SD_DHCP6_CLIENT_EVENT_STOP = 0, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10, @@ -48,10 +53,8 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, size_t duid_len); -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, - bool enabled); -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, - bool *enabled); +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option); @@ -59,6 +62,7 @@ int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret); int sd_dhcp6_client_stop(sd_dhcp6_client *client); int sd_dhcp6_client_start(sd_dhcp6_client *client); +int sd_dhcp6_client_is_running(sd_dhcp6_client *client); int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority); int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); @@ -67,4 +71,6 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client); int sd_dhcp6_client_new(sd_dhcp6_client **ret); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h index dc3df3bbf7..3fc0ee4bed 100644 --- a/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/sd-dhcp6-lease.h @@ -23,8 +23,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <netinet/in.h> +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + typedef struct sd_dhcp6_lease sd_dhcp6_lease; void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease); @@ -42,4 +47,6 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-hwdb.h b/src/systemd/sd-hwdb.h index 3c44b981d6..49269a073a 100644 --- a/src/systemd/sd-hwdb.h +++ b/src/systemd/sd-hwdb.h @@ -39,9 +39,11 @@ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias); int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value); -/* the inverse condition avoids ambiguity of danling 'else' after the macro */ +/* the inverse condition avoids ambiguity of dangling 'else' after the macro */ #define SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) \ if (sd_hwdb_seek(hwdb, modalias) < 0) { } \ else while (sd_hwdb_enumerate(hwdb, &(key), &(value)) > 0) +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-icmp6-nd.h b/src/systemd/sd-icmp6-nd.h deleted file mode 100644 index cb6c24a0cb..0000000000 --- a/src/systemd/sd-icmp6-nd.h +++ /dev/null @@ -1,79 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdicmp6ndfoo -#define foosdicmp6ndfoo - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <net/ethernet.h> - -#include "sd-event.h" - -enum { - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE = 0, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER = 2, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4, -}; - -typedef struct sd_icmp6_nd sd_icmp6_nd; - -typedef void(*sd_icmp6_nd_callback_t)(sd_icmp6_nd *nd, int event, - void *userdata); - -int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t cb, - void *userdata); -int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index); -int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr); - -int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority); -int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd); -sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd); - -sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd); -sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd); -int sd_icmp6_nd_new(sd_icmp6_nd **ret); - -int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen, - struct in6_addr *addr); - -int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu); -int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr, - uint8_t *prefixlen); -int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, - uint8_t *prefixlen); - -int sd_icmp6_nd_stop(sd_icmp6_nd *nd); -int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd); - -#define SD_ICMP6_ND_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" - -#define SD_ICMP6_ND_ADDRESS_FORMAT_VAL(address) \ - be16toh((address).s6_addr16[0]), \ - be16toh((address).s6_addr16[1]), \ - be16toh((address).s6_addr16[2]), \ - be16toh((address).s6_addr16[3]), \ - be16toh((address).s6_addr16[4]), \ - be16toh((address).s6_addr16[5]), \ - be16toh((address).s6_addr16[6]), \ - be16toh((address).s6_addr16[7]) - -#endif diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index adcb2c7b92..6337d61452 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -23,11 +23,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <netinet/in.h> #include <net/ethernet.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; enum { SD_IPV4ACD_EVENT_STOP = 0, @@ -45,11 +47,13 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); -bool sd_ipv4acd_is_running(sd_ipv4acd *ll); +int sd_ipv4acd_is_running(sd_ipv4acd *ll); int sd_ipv4acd_start(sd_ipv4acd *ll); int sd_ipv4acd_stop(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll); int sd_ipv4acd_new (sd_ipv4acd **ret); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 677505f0c6..2949f1dfb2 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -22,11 +22,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <netinet/in.h> #include <net/ethernet.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; enum { SD_IPV4LL_EVENT_STOP = 0, @@ -43,12 +45,15 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); +int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed); -bool sd_ipv4ll_is_running(sd_ipv4ll *ll); +int sd_ipv4ll_is_running(sd_ipv4ll *ll); int sd_ipv4ll_start(sd_ipv4ll *ll); int sd_ipv4ll_stop(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); int sd_ipv4ll_new (sd_ipv4ll **ret); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 30d9dedf2c..31651ce132 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -1,5 +1,8 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#ifndef foosdlldphfoo +#define foosdlldphfoo + /*** This file is part of systemd. @@ -20,9 +23,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once +#include <net/ethernet.h> +#include <inttypes.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; enum { SD_LLDP_EVENT_UPDATE_INFO = 0, @@ -72,3 +79,7 @@ sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h new file mode 100644 index 0000000000..80e24325f7 --- /dev/null +++ b/src/systemd/sd-ndisc.h @@ -0,0 +1,83 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdndiscfoo +#define foosdndiscfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <inttypes.h> +#include <net/ethernet.h> + +#include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_NDISC_EVENT_STOP = 0, + SD_NDISC_EVENT_TIMEOUT = 1, +}; + +typedef struct sd_ndisc sd_ndisc; + +typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata); +typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, + unsigned lifetime, void *userdata); +typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, + unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata); +typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata); + +int sd_ndisc_set_callback(sd_ndisc *nd, + sd_ndisc_router_callback_t rcb, + sd_ndisc_prefix_onlink_callback_t plcb, + sd_ndisc_prefix_autonomous_callback_t pacb, + sd_ndisc_callback_t cb, + void *userdata); +int sd_ndisc_set_index(sd_ndisc *nd, int interface_index); +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); + +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority); +int sd_ndisc_detach_event(sd_ndisc *nd); +sd_event *sd_ndisc_get_event(sd_ndisc *nd); + +sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); +sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); +int sd_ndisc_new(sd_ndisc **ret); + +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu); + +int sd_ndisc_stop(sd_ndisc *nd); +int sd_ndisc_router_discovery_start(sd_ndisc *nd); + +#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" + +#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \ + be16toh((address).s6_addr16[0]), \ + be16toh((address).s6_addr16[1]), \ + be16toh((address).s6_addr16[2]), \ + be16toh((address).s6_addr16[3]), \ + be16toh((address).s6_addr16[4]), \ + be16toh((address).s6_addr16[5]), \ + be16toh((address).s6_addr16[6]), \ + be16toh((address).s6_addr16[7]) + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index e09b8c8e2d..2960deda0a 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -136,7 +136,13 @@ int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type); int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope); +int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags); +int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags); int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family); +int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol); +int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope); +int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos); +int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table); int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len); int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len); diff --git a/src/systemd/sd-path.h b/src/systemd/sd-path.h index e238c0ce20..3280303633 100644 --- a/src/systemd/sd-path.h +++ b/src/systemd/sd-path.h @@ -24,6 +24,10 @@ #include <inttypes.h> +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + enum { /* Temporary files */ SD_PATH_TEMPORARY = 0x0ULL, @@ -84,4 +88,6 @@ enum { int sd_path_home(uint64_t type, const char *suffix, char **path); int sd_path_search(uint64_t type, const char *suffix, char ***paths); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-pppoe.h b/src/systemd/sd-pppoe.h deleted file mode 100644 index 90878ffa27..0000000000 --- a/src/systemd/sd-pppoe.h +++ /dev/null @@ -1,53 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdpppoefoo -#define foosdpppoefoo - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdbool.h> -#include <net/ethernet.h> - -#include "sd-event.h" - -#include "sparse-endian.h" - -enum { - SD_PPPOE_EVENT_RUNNING = 0, - SD_PPPOE_EVENT_STOPPED = 1, -}; - -typedef struct sd_pppoe sd_pppoe; -typedef void (*sd_pppoe_cb_t)(sd_pppoe *ppp, int event, void *userdata); - -int sd_pppoe_detach_event(sd_pppoe *ppp); -int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority); -int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel); -int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata); -int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex); -int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname); -int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name); -int sd_pppoe_start(sd_pppoe *ppp); -int sd_pppoe_stop(sd_pppoe *ppp); -sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp); -sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp); -int sd_pppoe_new (sd_pppoe **ret); - -#endif diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 80c5852e45..82c4b39efe 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -22,12 +22,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> -#include <sys/socket.h> +#include <inttypes.h> #include <netdb.h> +#include <sys/socket.h> +#include <sys/types.h> -#include "_sd-common.h" #include "sd-event.h" +#include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index ba09727080..675f94906b 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -26,19 +26,24 @@ #include <shadow.h> #include <utmp.h> +#include "alloc-util.h" #include "conf-files.h" #include "copy.h" +#include "def.h" +#include "fd-util.h" #include "fileio-label.h" #include "formats-util.h" #include "hashmap.h" #include "path-util.h" #include "selinux-util.h" +#include "smack-util.h" #include "specifier.h" +#include "string-util.h" #include "strv.h" #include "uid-range.h" +#include "user-util.h" #include "utf8.h" #include "util.h" -#include "smack-util.h" typedef enum ItemType { ADD_USER = 'u', @@ -67,7 +72,7 @@ typedef struct Item { static char *arg_root = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("sysusers"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("sysusers.d"); static Hashmap *users = NULL, *groups = NULL; static Hashmap *todo_uids = NULL, *todo_gids = NULL; @@ -938,7 +943,7 @@ static int add_user(Item *i) { } } - /* Otherwise try to reuse the group ID */ + /* Otherwise, try to reuse the group ID */ if (!i->uid_set && i->gid_set) { r = uid_is_ok((uid_t) i->gid, i->name); if (r < 0) @@ -1762,7 +1767,7 @@ static int parse_argv(int argc, char *argv[]) { {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -1779,12 +1784,9 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_ROOT: - free(arg_root); - arg_root = path_make_absolute_cwd(optarg); - if (!arg_root) - return log_oom(); - - path_kill_slashes(arg_root); + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case '?': @@ -1859,7 +1861,7 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - lock = take_password_lock(arg_root); + lock = take_etc_passwd_lock(arg_root); if (lock < 0) { log_error_errno(lock, "Failed to take lock: %m"); goto finish; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 964750076a..5075548507 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -25,17 +25,24 @@ #include <stdio.h> #include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "hexdecoct.h" +#include "install.h" +#include "log.h" #include "mkdir.h" -#include "strv.h" -#include "path-util.h" #include "path-lookup.h" -#include "log.h" -#include "unit-name.h" -#include "special.h" -#include "hashmap.h" +#include "path-util.h" #include "set.h" -#include "install.h" +#include "special.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "util.h" typedef enum RunlevelType { RUNLEVEL_UP, @@ -80,9 +87,13 @@ typedef struct SysvStub { char **conflicts; bool has_lsb; bool reload; + bool loaded; } SysvStub; static void free_sysvstub(SysvStub *s) { + if (!s) + return; + free(s->name); free(s->path); free(s->description); @@ -107,19 +118,14 @@ static void free_sysvstub_hashmapp(Hashmap **h) { } static int add_symlink(const char *service, const char *where) { - _cleanup_free_ char *from = NULL, *to = NULL; + const char *from, *to; int r; assert(service); assert(where); - from = strjoin(arg_dest, "/", service, NULL); - if (!from) - return log_oom(); - - to = strjoin(arg_dest, "/", where, ".wants/", service, NULL); - if (!to) - return log_oom(); + from = strjoina(arg_dest, "/", service); + to = strjoina(arg_dest, "/", where, ".wants/", service); mkdir_parents_label(to, 0755); @@ -127,6 +133,7 @@ static int add_symlink(const char *service, const char *where) { if (r < 0) { if (errno == EEXIST) return 0; + return -errno; } @@ -134,20 +141,19 @@ static int add_symlink(const char *service, const char *where) { } static int add_alias(const char *service, const char *alias) { - _cleanup_free_ char *link = NULL; + const char *link; int r; assert(service); assert(alias); - link = strjoin(arg_dest, "/", alias, NULL); - if (!link) - return log_oom(); + link = strjoina(arg_dest, "/", alias); r = symlink(service, link); if (r < 0) { if (errno == EEXIST) return 0; + return -errno; } @@ -155,26 +161,32 @@ static int add_alias(const char *service, const char *alias) { } static int generate_unit_file(SysvStub *s) { - char **p; + _cleanup_free_ char *before = NULL, *after = NULL, *wants = NULL, *conflicts = NULL; _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *unit = NULL, - *before = NULL, *after = NULL, - *wants = NULL, *conflicts = NULL; + const char *unit; + char **p; int r; + assert(s); + + if (!s->loaded) + return 0; + + unit = strjoina(arg_dest, "/", s->name); + before = strv_join(s->before, " "); after = strv_join(s->after, " "); wants = strv_join(s->wants, " "); conflicts = strv_join(s->conflicts, " "); - unit = strjoin(arg_dest, "/", s->name, NULL); - if (!before || !after || !wants || !conflicts || !unit) + + if (!before || !after || !wants || !conflicts) return log_oom(); /* We might already have a symlink with the same name from a Provides:, * or from backup files like /etc/init.d/foo.bak. Real scripts always win, * so remove an existing link */ if (is_symlink(unit) > 0) { - log_warning("Overwriting existing symlink %s with real service", unit); + log_warning("Overwriting existing symlink %s with real service.", unit); (void) unlink(unit); } @@ -186,9 +198,11 @@ static int generate_unit_file(SysvStub *s) { "# Automatically generated by systemd-sysv-generator\n\n" "[Unit]\n" "Documentation=man:systemd-sysv-generator(8)\n" - "SourcePath=%s\n" - "Description=%s\n", - s->path, s->description); + "SourcePath=%s\n", + s->path); + + if (s->description) + fprintf(f, "Description=%s\n", s->description); if (!isempty(before)) fprintf(f, "Before=%s\n", before); @@ -221,13 +235,17 @@ static int generate_unit_file(SysvStub *s) { if (s->reload) fprintf(f, "ExecReload=%s reload\n", s->path); + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write unit %s: %m", unit); + STRV_FOREACH(p, s->wanted_by) { r = add_symlink(s->name, *p); if (r < 0) - log_error_errno(r, "Failed to create 'Wants' symlink to %s: %m", *p); + log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p); } - return 0; + return 1; } static bool usage_contains_reload(const char *line) { @@ -257,7 +275,7 @@ static char *sysv_translate_name(const char *name) { return res; } -static int sysv_translate_facility(const char *name, const char *filename, char **_r) { +static int sysv_translate_facility(const char *name, const char *filename, char **ret) { /* We silently ignore the $ prefix here. According to the LSB * spec it simply indicates whether something is a @@ -276,31 +294,45 @@ static int sysv_translate_facility(const char *name, const char *filename, char "time", SPECIAL_TIME_SYNC_TARGET, }; - char *filename_no_sh, *e, *r; + char *filename_no_sh, *e, *m; const char *n; unsigned i; + int r; assert(name); - assert(_r); + assert(filename); + assert(ret); n = *name == '$' ? name + 1 : name; for (i = 0; i < ELEMENTSOF(table); i += 2) { - if (!streq(table[i], n)) continue; if (!table[i+1]) return 0; - r = strdup(table[i+1]); - if (!r) + m = strdup(table[i+1]); + if (!m) return log_oom(); - goto finish; + *ret = m; + return 1; + } + + /* If we don't know this name, fallback heuristics to figure + * out whether something is a target or a service alias. */ + + /* Facilities starting with $ are most likely targets */ + if (*name == '$') { + r = unit_name_build(n, NULL, ".target", ret); + if (r < 0) + return log_error_errno(r, "Failed to build name: %m"); + + return r; } - /* strip ".sh" suffix from file name for comparison */ + /* Strip ".sh" suffix from file name for comparison */ filename_no_sh = strdupa(filename); e = endswith(filename_no_sh, ".sh"); if (e) { @@ -308,103 +340,103 @@ static int sysv_translate_facility(const char *name, const char *filename, char filename = filename_no_sh; } - /* If we don't know this name, fallback heuristics to figure - * out whether something is a target or a service alias. */ - - if (*name == '$') { - int k; - - /* Facilities starting with $ are most likely targets */ - k = unit_name_build(n, NULL, ".target", &r); - if (k < 0) - return k; - - } else if (streq_ptr(n, filename)) - /* Names equaling the file name of the services are redundant */ + /* Names equaling the file name of the services are redundant */ + if (streq_ptr(n, filename)) return 0; - else - /* Everything else we assume to be normal service names */ - r = sysv_translate_name(n); - if (!r) - return -ENOMEM; -finish: - *_r = r; + /* Everything else we assume to be normal service names */ + m = sysv_translate_name(n); + if (!m) + return log_oom(); + *ret = m; return 1; } static int handle_provides(SysvStub *s, unsigned line, const char *full_text, const char *text) { - const char *word, *state_; - size_t z; int r; - FOREACH_WORD_QUOTED(word, z, text, state_) { - _cleanup_free_ char *n = NULL, *m = NULL; - UnitType t; + assert(s); + assert(full_text); + assert(text); - n = strndup(word, z); - if (!n) - return log_oom(); + for (;;) { + _cleanup_free_ char *word = NULL, *m = NULL; - r = sysv_translate_facility(n, basename(s->path), &m); + r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) - return r; + return log_error_errno(r, "Failed to parse word from provides string: %m"); if (r == 0) + break; + + r = sysv_translate_facility(word, basename(s->path), &m); + if (r <= 0) /* continue on error */ continue; - t = unit_name_to_type(m); - if (t == UNIT_SERVICE) { + switch (unit_name_to_type(m)) { + + case UNIT_SERVICE: log_debug("Adding Provides: alias '%s' for '%s'", m, s->name); r = add_alias(s->name, m); if (r < 0) log_warning_errno(r, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m", s->path, line, m); - } else if (t == UNIT_TARGET) { + break; + + case UNIT_TARGET: + /* NB: SysV targets which are provided by a * service are pulled in by the services, as * an indication that the generic service is * now available. This is strictly one-way. * The targets do NOT pull in SysV services! */ + r = strv_extend(&s->before, m); if (r < 0) return log_oom(); + r = strv_extend(&s->wants, m); if (r < 0) return log_oom(); + if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)) { r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET); if (r < 0) return log_oom(); } - } else if (t == _UNIT_TYPE_INVALID) + + break; + + case _UNIT_TYPE_INVALID: log_warning("Unit name '%s' is invalid", m); - else + break; + + default: log_warning("Unknown unit type for unit '%s'", m); + } } - if (!isempty(state_)) - log_error("[%s:%u] Trailing garbage in Provides, ignoring.", s->path, line); + return 0; } static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text, const char *text) { - const char *word, *state_; - size_t z; int r; - FOREACH_WORD_QUOTED(word, z, text, state_) { - _cleanup_free_ char *n = NULL, *m = NULL; - bool is_before; + assert(s); + assert(full_text); + assert(text); - n = strndup(word, z); - if (!n) - return log_oom(); + for (;;) { + _cleanup_free_ char *word = NULL, *m = NULL; + bool is_before; - r = sysv_translate_facility(n, basename(s->path), &m); - if (r < 0) { - log_warning_errno(r, "[%s:%u] Failed to translate LSB dependency %s, ignoring: %m", s->path, line, n); - continue; - } + r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + if (r < 0) + return log_error_errno(r, "Failed to parse word from provides string: %m"); if (r == 0) + break; + + r = sysv_translate_facility(word, basename(s->path), &m); + if (r <= 0) /* continue on error */ continue; is_before = startswith_no_case(full_text, "X-Start-Before:"); @@ -414,15 +446,14 @@ static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text r = strv_extend(&s->after, m); if (r < 0) return log_oom(); + r = strv_extend(&s->wants, m); } else r = strv_extend(is_before ? &s->before : &s->after, m); - if (r < 0) return log_oom(); } - if (!isempty(state_)) - log_warning("[%s:%u] Trailing garbage in %*s, ignoring.", s->path, line, (int)(strchr(full_text, ':') - full_text), full_text); + return 0; } @@ -440,24 +471,22 @@ static int load_sysv(SysvStub *s) { _cleanup_free_ char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL; char *description; bool supports_reload = false; + char l[LINE_MAX]; assert(s); f = fopen(s->path, "re"); - if (!f) - return errno == ENOENT ? 0 : -errno; - - log_debug("Loading SysV script %s", s->path); + if (!f) { + if (errno == ENOENT) + return 0; - while (!feof(f)) { - char l[LINE_MAX], *t; + return log_error_errno(errno, "Failed to open %s: %m", s->path); + } - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; + log_debug("Loading SysV script %s", s->path); - return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path); - } + FOREACH_LINE(l, f, goto fail) { + char *t; line++; @@ -500,29 +529,25 @@ static int load_sysv(SysvStub *s) { if (startswith_no_case(t, "description:")) { - size_t k = strlen(t); - char *d; + size_t k; const char *j; - if (t[k-1] == '\\') { + k = strlen(t); + if (k > 0 && t[k-1] == '\\') { state = DESCRIPTION; t[k-1] = 0; } j = strstrip(t+12); - if (j && *j) { - d = strdup(j); - if (!d) - return -ENOMEM; - } else - d = NULL; + if (isempty(j)) + j = NULL; - free(chkconfig_description); - chkconfig_description = d; + r = free_and_strdup(&chkconfig_description, j); + if (r < 0) + return log_oom(); } else if (startswith_no_case(t, "pidfile:")) { - - char *fn; + const char *fn; state = NORMAL; @@ -532,12 +557,9 @@ static int load_sysv(SysvStub *s) { continue; } - fn = strdup(fn); - if (!fn) - return -ENOMEM; - - free(s->pid_file); - s->pid_file = fn; + r = free_and_strdup(&s->pid_file, fn); + if (r < 0) + return log_oom(); } } else if (state == DESCRIPTION) { @@ -545,25 +567,25 @@ static int load_sysv(SysvStub *s) { /* Try to parse Red Hat style description * continuation */ - size_t k = strlen(t); + size_t k; char *j; - if (t[k-1] == '\\') + k = strlen(t); + if (k > 0 && t[k-1] == '\\') t[k-1] = 0; else state = NORMAL; j = strstrip(t); - if (j && *j) { + if (!isempty(j)) { char *d = NULL; if (chkconfig_description) d = strjoin(chkconfig_description, " ", j, NULL); else d = strdup(j); - if (!d) - return -ENOMEM; + return log_oom(); free(chkconfig_description); chkconfig_description = d; @@ -577,6 +599,7 @@ static int load_sysv(SysvStub *s) { r = handle_provides(s, line, t, t + 9); if (r < 0) return r; + } else if (startswith_no_case(t, "Required-Start:") || startswith_no_case(t, "Should-Start:") || startswith_no_case(t, "X-Start-Before:") || @@ -588,55 +611,47 @@ static int load_sysv(SysvStub *s) { if (r < 0) return r; - } else if (startswith_no_case(t, "Description:")) { - char *d, *j; + const char *j; state = LSB_DESCRIPTION; j = strstrip(t+12); - if (j && *j) { - d = strdup(j); - if (!d) - return -ENOMEM; - } else - d = NULL; + if (isempty(j)) + j = NULL; - free(long_description); - long_description = d; + r = free_and_strdup(&long_description, j); + if (r < 0) + return log_oom(); } else if (startswith_no_case(t, "Short-Description:")) { - char *d, *j; + const char *j; state = LSB; j = strstrip(t+18); - if (j && *j) { - d = strdup(j); - if (!d) - return -ENOMEM; - } else - d = NULL; + if (isempty(j)) + j = NULL; - free(short_description); - short_description = d; + r = free_and_strdup(&short_description, j); + if (r < 0) + return log_oom(); } else if (state == LSB_DESCRIPTION) { if (startswith(l, "#\t") || startswith(l, "# ")) { - char *j; + const char *j; j = strstrip(t); - if (j && *j) { + if (!isempty(j)) { char *d = NULL; if (long_description) d = strjoin(long_description, " ", t, NULL); else d = strdup(j); - if (!d) - return -ENOMEM; + return log_oom(); free(long_description); long_description = d; @@ -667,12 +682,16 @@ static int load_sysv(SysvStub *s) { d = strappend(s->has_lsb ? "LSB: " : "SYSV: ", description); if (!d) - return -ENOMEM; + return log_oom(); s->description = d; } + s->loaded = true; return 0; + +fail: + return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path); } static int fix_order(SysvStub *s, Hashmap *all_services) { @@ -682,6 +701,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { assert(s); + if (!s->loaded) + return 0; + if (s->sysv_start_priority < 0) return 0; @@ -689,6 +711,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { if (s == other) continue; + if (!other->loaded) + continue; + if (other->sysv_start_priority < 0) continue; @@ -701,13 +726,12 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { r = strv_extend(&s->after, other->name); if (r < 0) return log_oom(); - } - else if (other->sysv_start_priority > s->sysv_start_priority) { + + } else if (other->sysv_start_priority > s->sysv_start_priority) { r = strv_extend(&s->before, other->name); if (r < 0) return log_oom(); - } - else + } else continue; /* FIXME: Maybe we should compare the name here lexicographically? */ @@ -718,6 +742,10 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { char **path; + int r; + + assert(lp); + assert(all_services); STRV_FOREACH(path, lp->sysvinit_path) { _cleanup_closedir_ DIR *d = NULL; @@ -726,21 +754,17 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { d = opendir(*path); if (!d) { if (errno != ENOENT) - log_warning_errno(errno, "opendir(%s) failed: %m", *path); + log_warning_errno(errno, "Opening %s failed, ignoring: %m", *path); continue; } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path)) { _cleanup_free_ char *fpath = NULL, *name = NULL; _cleanup_(free_sysvstubp) SysvStub *service = NULL; struct stat st; - int r; - - if (hidden_file(de->d_name)) - continue; if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) { - log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name); + log_warning_errno(errno, "stat() failed on %s/%s, ignoring: %m", *path, de->d_name); continue; } @@ -757,15 +781,19 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { if (hashmap_contains(all_services, name)) continue; + r = unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name, NULL); + if (r < 0 && r != -ENOENT) { + log_debug_errno(r, "Failed to detect whether %s exists, skipping: %m", name); + continue; + } else if (r >= 0) { + log_debug("Native unit for %s already exists, skipping.", name); + continue; + } + fpath = strjoin(*path, "/", de->d_name, NULL); if (!fpath) return log_oom(); - if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) { - log_debug("Native unit for %s already exists, skipping", name); - continue; - } - service = new0(SysvStub, 1); if (!service) return log_oom(); @@ -773,12 +801,12 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { service->sysv_start_priority = -1; service->name = name; service->path = fpath; + name = fpath = NULL; r = hashmap_put(all_services, service->name, service); if (r < 0) return log_oom(); - name = fpath = NULL; service = NULL; } } @@ -787,43 +815,41 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { } static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) { - char **p; - unsigned i; - _cleanup_closedir_ DIR *d = NULL; - _cleanup_free_ char *path = NULL, *fpath = NULL; - SysvStub *service; - Iterator j; Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {}; _cleanup_set_free_ Set *shutdown_services = NULL; - int r = 0; + SysvStub *service; + unsigned i; + Iterator j; + char **p; + int r; + + assert(lp); - STRV_FOREACH(p, lp->sysvrcnd_path) + STRV_FOREACH(p, lp->sysvrcnd_path) { for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { + + _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *path = NULL; struct dirent *de; - free(path); path = strjoin(*p, "/", rcnd_table[i].path, NULL); - if (!path) - return -ENOMEM; - - safe_closedir(d); + if (!path) { + r = log_oom(); + goto finish; + } d = opendir(path); if (!d) { if (errno != ENOENT) - log_warning_errno(errno, "opendir(%s) failed: %m", path); + log_warning_errno(errno, "Opening %s failed, ignoring: %m", path); continue; } - while ((de = readdir(d))) { - _cleanup_free_ char *name = NULL; - + FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", path)) { + _cleanup_free_ char *name = NULL, *fpath = NULL; int a, b; - if (hidden_file(de->d_name)) - continue; - if (de->d_name[0] != 'S' && de->d_name[0] != 'K') continue; @@ -836,10 +862,9 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic if (a < 0 || b < 0) continue; - free(fpath); fpath = strjoin(*p, "/", de->d_name, NULL); if (!fpath) { - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -851,64 +876,77 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic service = hashmap_get(all_services, name); if (!service){ - log_debug("Ignoring %s symlink in %s, not generating %s.", - de->d_name, rcnd_table[i].path, name); + log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name); continue; } if (de->d_name[0] == 'S') { - if (rcnd_table[i].type == RUNLEVEL_UP) { - service->sysv_start_priority = - MAX(a*10 + b, service->sysv_start_priority); - } + if (rcnd_table[i].type == RUNLEVEL_UP) + service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority); r = set_ensure_allocated(&runlevel_services[i], NULL); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } r = set_put(runlevel_services[i], service); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } } else if (de->d_name[0] == 'K' && (rcnd_table[i].type == RUNLEVEL_DOWN)) { r = set_ensure_allocated(&shutdown_services, NULL); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } r = set_put(shutdown_services, service); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } } } } + } for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) SET_FOREACH(service, runlevel_services[i], j) { r = strv_extend(&service->before, rcnd_table[i].target); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } r = strv_extend(&service->wanted_by, rcnd_table[i].target); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } } SET_FOREACH(service, shutdown_services, j) { r = strv_extend(&service->before, SPECIAL_SHUTDOWN_TARGET); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } r = strv_extend(&service->conflicts, SPECIAL_SHUTDOWN_TARGET); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } } r = 0; finish: - for (i = 0; i < ELEMENTSOF(rcnd_table); i++) set_free(runlevel_services[i]); @@ -916,11 +954,11 @@ finish: } int main(int argc, char *argv[]) { - int r, q; - _cleanup_lookup_paths_free_ LookupPaths lp = {}; _cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL; + _cleanup_lookup_paths_free_ LookupPaths lp = {}; SysvStub *service; Iterator j; + int r; if (argc > 1 && argc != 4) { log_error("This program takes three or no arguments."); @@ -938,43 +976,34 @@ int main(int argc, char *argv[]) { r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL); if (r < 0) { - log_error("Failed to find lookup paths."); - return EXIT_FAILURE; + log_error_errno(r, "Failed to find lookup paths: %m"); + goto finish; } all_services = hashmap_new(&string_hash_ops); if (!all_services) { - log_oom(); - return EXIT_FAILURE; + r = log_oom(); + goto finish; } r = enumerate_sysv(&lp, all_services); - if (r < 0) { - log_error("Failed to generate units for all init scripts."); - return EXIT_FAILURE; - } + if (r < 0) + goto finish; r = set_dependencies_from_rcnd(&lp, all_services); - if (r < 0) { - log_error("Failed to read runlevels from rcnd links."); - return EXIT_FAILURE; - } + if (r < 0) + goto finish; - HASHMAP_FOREACH(service, all_services, j) { - q = load_sysv(service); - if (q < 0) - continue; - } + HASHMAP_FOREACH(service, all_services, j) + (void) load_sysv(service); HASHMAP_FOREACH(service, all_services, j) { - q = fix_order(service, all_services); - if (q < 0) - continue; - - q = generate_unit_file(service); - if (q < 0) - continue; + (void) fix_order(service, all_services); + (void) generate_unit_file(service); } - return EXIT_SUCCESS; + r = 0; + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/test/test-af-list.c b/src/test/test-af-list.c index d69104f540..aeaa0929b1 100644 --- a/src/test/test-af-list.c +++ b/src/test/test-af-list.c @@ -17,17 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <string.h> +#include <sys/socket.h> #include "macro.h" +#include "string-util.h" #include "util.h" static const struct af_name* lookup_af(register const char *str, register unsigned int len); +#include "af-from-name.h" #include "af-list.h" #include "af-to-name.h" -#include "af-from-name.h" int main(int argc, const char *argv[]) { @@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) { assert_se(af_from_name("huddlduddl") == AF_UNSPEC); return 0; -}
\ No newline at end of file +} diff --git a/src/test/test-arphrd-list.c b/src/test/test-arphrd-list.c index d7c8eaa4a9..f3989ad201 100644 --- a/src/test/test-arphrd-list.c +++ b/src/test/test-arphrd-list.c @@ -21,13 +21,14 @@ #include <string.h> #include "macro.h" +#include "string-util.h" #include "util.h" static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len); +#include "arphrd-from-name.h" #include "arphrd-list.h" #include "arphrd-to-name.h" -#include "arphrd-from-name.h" int main(int argc, const char *argv[]) { @@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) { assert_se(arphrd_from_name("huddlduddl") == 0); return 0; -}
\ No newline at end of file +} diff --git a/src/test/test-async.c b/src/test/test-async.c index abd36d693c..ada6d67c42 100644 --- a/src/test/test-async.c +++ b/src/test/test-async.c @@ -20,8 +20,9 @@ #include <unistd.h> #include "async.h" -#include "util.h" +#include "fileio.h" #include "macro.h" +#include "util.h" static bool test_async = false; diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index e4771c9dd7..33356f8387 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -21,23 +21,26 @@ #include <fcntl.h> -#include "log.h" +#include "btrfs-util.h" +#include "fd-util.h" #include "fileio.h" +#include "log.h" +#include "parse-util.h" +#include "string-util.h" #include "util.h" -#include "btrfs-util.h" int main(int argc, char *argv[]) { + BtrfsQuotaInfo quota; int r, fd; fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (fd < 0) log_error_errno(errno, "Failed to open root directory: %m"); else { - BtrfsSubvolInfo info; - BtrfsQuotaInfo quota; char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX]; + BtrfsSubvolInfo info; - r = btrfs_subvol_get_info_fd(fd, &info); + r = btrfs_subvol_get_info_fd(fd, 0, &info); if (r < 0) log_error_errno(r, "Failed to get subvolume info: %m"); else { @@ -45,7 +48,7 @@ int main(int argc, char *argv[]) { log_info("read-only (search): %s", yes_no(info.read_only)); } - r = btrfs_subvol_get_quota_fd(fd, "a); + r = btrfs_qgroup_get_quota_fd(fd, 0, "a); if (r < 0) log_error_errno(r, "Failed to get quota info: %m"); else { @@ -80,15 +83,15 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); - r = btrfs_subvol_remove("/xxxtest", false); + r = btrfs_subvol_remove("/xxxtest", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); - r = btrfs_subvol_remove("/xxxtest2", false); + r = btrfs_subvol_remove("/xxxtest2", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); - r = btrfs_subvol_remove("/xxxtest3", false); + r = btrfs_subvol_remove("/xxxtest3", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); @@ -96,7 +99,7 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to make snapshot: %m"); - r = btrfs_subvol_remove("/etc2", false); + r = btrfs_subvol_remove("/etc2", BTRFS_REMOVE_QUOTA); if (r < 0) log_error_errno(r, "Failed to remove subvolume: %m"); @@ -137,13 +140,61 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "Failed to snapshot subvolume: %m"); - r = btrfs_subvol_remove("/xxxrectest", true); + r = btrfs_subvol_remove("/xxxrectest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); if (r < 0) log_error_errno(r, "Failed to recursively remove subvolume: %m"); - r = btrfs_subvol_remove("/xxxrectest2", true); + r = btrfs_subvol_remove("/xxxrectest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); if (r < 0) log_error_errno(r, "Failed to recursively remove subvolume: %m"); + r = btrfs_subvol_make("/xxxquotatest"); + if (r < 0) + log_error_errno(r, "Failed to make subvolume: %m"); + + r = btrfs_subvol_auto_qgroup("/xxxquotatest", 0, true); + if (r < 0) + log_error_errno(r, "Failed to set up auto qgroup: %m"); + + r = btrfs_subvol_make("/xxxquotatest/beneath"); + if (r < 0) + log_error_errno(r, "Failed to make subvolume: %m"); + + r = btrfs_subvol_auto_qgroup("/xxxquotatest/beneath", 0, false); + if (r < 0) + log_error_errno(r, "Failed to set up auto qgroup: %m"); + + r = btrfs_qgroup_set_limit("/xxxquotatest/beneath", 0, 4ULL * 1024 * 1024 * 1024); + if (r < 0) + log_error_errno(r, "Failed to set up quota limit: %m"); + + r = btrfs_subvol_set_subtree_quota_limit("/xxxquotatest", 0, 5ULL * 1024 * 1024 * 1024); + if (r < 0) + log_error_errno(r, "Failed to set up quota limit: %m"); + + r = btrfs_subvol_snapshot("/xxxquotatest", "/xxxquotatest2", BTRFS_SNAPSHOT_RECURSIVE|BTRFS_SNAPSHOT_QUOTA); + if (r < 0) + log_error_errno(r, "Failed to setup snapshot: %m"); + + r = btrfs_qgroup_get_quota("/xxxquotatest2/beneath", 0, "a); + if (r < 0) + log_error_errno(r, "Failed to query quota: %m"); + + assert_se(quota.referenced_max == 4ULL * 1024 * 1024 * 1024); + + r = btrfs_subvol_get_subtree_quota("/xxxquotatest2", 0, "a); + if (r < 0) + log_error_errno(r, "Failed to query quota: %m"); + + assert_se(quota.referenced_max == 5ULL * 1024 * 1024 * 1024); + + r = btrfs_subvol_remove("/xxxquotatest", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); + if (r < 0) + log_error_errno(r, "Failed remove subvolume: %m"); + + r = btrfs_subvol_remove("/xxxquotatest2", BTRFS_REMOVE_QUOTA|BTRFS_REMOVE_RECURSIVE); + if (r < 0) + log_error_errno(r, "Failed remove subvolume: %m"); + return 0; } diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 87e1da1258..70819b0371 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -21,7 +21,9 @@ #include <string.h> +#include "alloc-util.h" #include "calendarspec.h" +#include "string-util.h" #include "util.h" static void test_one(const char *input, const char *output) { @@ -50,6 +52,44 @@ static void test_one(const char *input, const char *output) { assert_se(streq(q, p)); } +static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) { + CalendarSpec *c; + usec_t u; + char *old_tz; + char buf[FORMAT_TIMESTAMP_MAX]; + int r; + + old_tz = getenv("TZ"); + if (old_tz) + old_tz = strdupa(old_tz); + + if (new_tz) + assert_se(setenv("TZ", new_tz, 1) >= 0); + else + assert_se(unsetenv("TZ") >= 0); + tzset(); + + assert_se(calendar_spec_from_string(input, &c) >= 0); + + printf("\"%s\"\n", input); + + u = after; + r = calendar_spec_next_usec(c, after, &u); + printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u)); + if (expect != (usec_t)-1) + assert_se(r >= 0 && u == expect); + else + assert(r == -ENOENT); + + calendar_spec_free(c); + + if (old_tz) + assert_se(setenv("TZ", old_tz, 1) >= 0); + else + assert_se(unsetenv("TZ") >= 0); + tzset(); +} + int main(int argc, char* argv[]) { CalendarSpec *c; @@ -82,6 +122,15 @@ int main(int argc, char* argv[]) { test_one("semi-annually", "*-01,07-01 00:00:00"); test_one("annually", "*-01-01 00:00:00"); test_one("*:2/3", "*-*-* *:02/3:00"); + test_one("2015-10-25 01:00:00 uTc", "2015-10-25 01:00:00 UTC"); + + test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000); + test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000); + test_next("2016-03-27 03:17:00", "EET", 12345, -1); + test_next("2016-03-27 03:17:00 UTC", NULL, 12345, 1459048620000000); + test_next("2016-03-27 03:17:00 UTC", "", 12345, 1459048620000000); + test_next("2016-03-27 03:17:00 UTC", "CET", 12345, 1459048620000000); + test_next("2016-03-27 03:17:00 UTC", "EET", 12345, 1459048620000000); assert_se(calendar_spec_from_string("test", &c) < 0); assert_se(calendar_spec_from_string("", &c) < 0); diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c index 43a2d35b80..4418bafda6 100644 --- a/src/test/test-cap-list.c +++ b/src/test/test-cap-list.c @@ -19,12 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "fileio.h" -#include "cap-list.h" -#include "capability.h" #include <sys/prctl.h> +#include "alloc-util.h" +#include "cap-list.h" +#include "capability-util.h" +#include "fileio.h" +#include "parse-util.h" +#include "util.h" + /* verify the capability parser */ static void test_cap_list(void) { int i; diff --git a/src/test/test-capability.c b/src/test/test-capability.c index f47452ce72..fc8d3ffe0d 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -17,20 +17,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/wait.h> -#include <sys/capability.h> -#include <sys/socket.h> #include <netinet/in.h> #include <pwd.h> +#include <sys/capability.h> +#include <sys/socket.h> +#include <sys/wait.h> #include <unistd.h> -#include "capability.h" -#include "util.h" +#include "capability-util.h" +#include "fd-util.h" #include "macro.h" +#include "util.h" static uid_t test_uid = -1; static gid_t test_gid = -1; -// We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage + +/* We keep CAP_DAC_OVERRIDE to avoid errors with gcov when doing test coverage */ static uint64_t test_flags = 1ULL << CAP_DAC_OVERRIDE; static void fork_test(void (*test_func)(void)) { diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 4ecf09a29e..a48b324e26 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -19,12 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "util.h" +#include "alloc-util.h" #include "cgroup-util.h" -#include "test-helper.h" +#include "dirent-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "parse-util.h" #include "process-util.h" +#include "string-util.h" +#include "test-helper.h" +#include "user-util.h" +#include "util.h" static void check_p_d_u(const char *path, int code, const char *result) { _cleanup_free_ char *unit = NULL; diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index 37b1c3554a..c20a29ba1f 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <string.h> +#include <unistd.h> #include "cgroup-util.h" #include "path-util.h" +#include "string-util.h" #include "util.h" int main(int argc, char*argv[]) { diff --git a/src/test/test-condition.c b/src/test/test-condition.c index b788c9532d..f224c6cdd8 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -17,18 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-id128.h" + +#include "alloc-util.h" +#include "apparmor-util.h" +#include "architecture.h" +#include "audit-util.h" #include "condition.h" -#include "macro.h" -#include "util.h" +#include "hostname-util.h" +#include "ima-util.h" #include "log.h" -#include "architecture.h" -#include "sd-id128.h" +#include "macro.h" #include "selinux-util.h" -#include "audit.h" -#include "ima-util.h" -#include "apparmor-util.h" #include "smack-util.h" -#include "hostname-util.h" +#include "util.h" static void test_condition_test_path(void) { Condition *condition; diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c index 01ece022c1..86ac513d4f 100644 --- a/src/test/test-conf-files.c +++ b/src/test/test-conf-files.c @@ -19,14 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdarg.h> +#include <stdio.h> +#include "alloc-util.h" #include "conf-files.h" +#include "fs-util.h" #include "macro.h" +#include "parse-util.h" +#include "rm-rf.h" +#include "string-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" -#include "rm-rf.h" static void setup_test_dir(char *tmp_dir, const char *files, ...) { va_list ap; @@ -36,7 +41,7 @@ static void setup_test_dir(char *tmp_dir, const char *files, ...) { va_start(ap, files); while (files != NULL) { _cleanup_free_ char *path = strappend(tmp_dir, files); - assert_se(touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0) == 0); + assert_se(touch_file(path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID) == 0); files = va_arg(ap, const char *); } va_end(ap); diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 463906d304..b3a4c40339 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -18,10 +18,11 @@ ***/ #include "conf-parser.h" +#include "log.h" #include "macro.h" -#include "util.h" +#include "string-util.h" #include "strv.h" -#include "log.h" +#include "util.h" static void test_config_parse_path_one(const char *rvalue, const char *expected) { char *path = NULL; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index a03a68bd43..ad57cb0202 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -19,14 +19,18 @@ #include <unistd.h> +#include "alloc-util.h" #include "copy.h" -#include "path-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "macro.h" #include "mkdir.h" +#include "path-util.h" +#include "rm-rf.h" +#include "string-util.h" #include "strv.h" -#include "macro.h" #include "util.h" -#include "rm-rf.h" static void test_copy_file(void) { _cleanup_free_ char *buf = NULL; diff --git a/src/test/test-date.c b/src/test/test-date.c index 00b569080c..c6d8bf82ea 100644 --- a/src/test/test-date.c +++ b/src/test/test-date.c @@ -21,14 +21,16 @@ #include <string.h> +#include "alloc-util.h" +#include "string-util.h" #include "util.h" -static void test_one(const char *p) { +static void test_should_pass(const char *p) { usec_t t, q; char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX]; assert_se(parse_timestamp(p, &t) >= 0); - format_timestamp(buf, sizeof(buf), t); + format_timestamp_us(buf, sizeof(buf), t); log_info("%s", buf); /* Chop off timezone */ @@ -42,23 +44,57 @@ static void test_one(const char *p) { assert_se(parse_timestamp(buf, &q) >= 0); } +static void test_should_parse(const char *p) { + usec_t t; + + assert_se(parse_timestamp(p, &t) >= 0); +} + +static void test_should_fail(const char *p) { + usec_t t; + + assert_se(parse_timestamp(p, &t) < 0); +} + +static void test_one(const char *p) { + _cleanup_free_ char *with_utc; + + log_info("Test: %s", p); + with_utc = strjoin(p, " UTC", NULL); + test_should_pass(p); + test_should_pass(with_utc); +} + +static void test_one_noutc(const char *p) { + _cleanup_free_ char *with_utc; + + log_info("Test: %s", p); + with_utc = strjoin(p, " UTC", NULL); + test_should_pass(p); + test_should_fail(with_utc); +} + int main(int argc, char *argv[]) { test_one("17:41"); test_one("18:42:44"); + test_one("18:42:44.0"); + test_one("18:42:44.999999999999"); test_one("12-10-02 12:13:14"); test_one("12-10-2 12:13:14"); test_one("12-10-03 12:13"); test_one("2012-12-30 18:42"); test_one("2012-10-02"); test_one("Tue 2012-10-02"); - test_one("now"); + test_one_noutc("now"); test_one("yesterday"); test_one("today"); test_one("tomorrow"); - test_one("+2d"); - test_one("+2y 4d"); - test_one("5months ago"); - test_one("@1395716396"); + test_one_noutc("+2d"); + test_one_noutc("+2y 4d"); + test_one_noutc("5months ago"); + test_one_noutc("@1395716396"); + test_should_parse("today UTC"); + test_should_fail("today UTC UTC"); return 0; } diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c index 59ba4be087..646b168cc0 100644 --- a/src/test/test-device-nodes.c +++ b/src/test/test-device-nodes.c @@ -21,7 +21,9 @@ #include <sys/types.h> +#include "alloc-util.h" #include "device-nodes.h" +#include "string-util.h" #include "util.h" /* helpers for test_encode_devnode_name */ diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index 2193eb6f7d..d5778748a0 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "macro.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "macro.h" +#include "string-util.h" static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) { char buffer[buffer_sz]; diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c index 27df9089c3..c597d5aecd 100644 --- a/src/test/test-ellipsize.c +++ b/src/test/test-ellipsize.c @@ -21,9 +21,11 @@ #include <stdio.h> -#include "util.h" -#include "terminal-util.h" +#include "alloc-util.h" #include "def.h" +#include "string-util.h" +#include "terminal-util.h" +#include "util.h" static void test_one(const char *p) { _cleanup_free_ char *t; diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 6596069ade..954ed0d9e0 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test1: (Trivial)\n"); - r = manager_add_job(m, JOB_START, c, JOB_REPLACE, false, &err, &j); + r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j); if (sd_bus_error_is_set(&err)) log_error("error: %s: %s", err.name, err.message); assert_se(r == 0); @@ -65,15 +65,15 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test2: (Cyclic Order, Unfixable)\n"); - assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, false, NULL, &j) == -EDEADLK); + assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK); manager_dump_jobs(m, stdout, "\t"); printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n"); - assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Test4: (Identical transaction)\n"); - assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Load3:\n"); @@ -81,21 +81,21 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test5: (Colliding transaction, fail)\n"); - assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, false, NULL, &j) == -EDEADLK); + assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK); printf("Test6: (Colliding transaction, replace)\n"); - assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Test7: (Unmergeable job type, fail)\n"); - assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EDEADLK); + assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK); printf("Test8: (Mergeable job type, fail)\n"); - assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Test9: (Unmergeable job type, replace)\n"); - assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); printf("Load4:\n"); @@ -103,7 +103,7 @@ int main(int argc, char *argv[]) { manager_dump_units(m, stdout, "\t"); printf("Test10: (Unmergeable job type of auxiliary job, fail)\n"); - assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, false, NULL, &j) == 0); + assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); manager_free(m); diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c index 110223f3b8..c1315bbf9f 100644 --- a/src/test/test-env-replace.c +++ b/src/test/test-env-replace.c @@ -21,9 +21,10 @@ #include <string.h> -#include "util.h" -#include "strv.h" #include "env-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static void test_strv_env_delete(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; diff --git a/src/test/test-execute.c b/src/test/test-execute.c index fa6336f1fb..03ec0fcfc7 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -17,14 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <grp.h> +#include <pwd.h> #include <stdio.h> +#include <sys/types.h> -#include "unit.h" -#include "manager.h" -#include "util.h" +#include "fileio.h" +#include "fs-util.h" #include "macro.h" +#include "manager.h" #include "mkdir.h" +#include "path-util.h" #include "rm-rf.h" +#include "unit.h" +#include "util.h" typedef void (*test_function_t)(Manager *m); @@ -123,11 +129,17 @@ static void test_exec_systemcallerrornumber(Manager *m) { } static void test_exec_user(Manager *m) { - test(m, "exec-user.service", 0, CLD_EXITED); + if (getpwnam("nobody")) + test(m, "exec-user.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m"); } static void test_exec_group(Manager *m) { - test(m, "exec-group.service", 0, CLD_EXITED); + if (getgrnam("nobody")) + test(m, "exec-group.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m"); } static void test_exec_environment(Manager *m) { @@ -136,6 +148,50 @@ static void test_exec_environment(Manager *m) { test(m, "exec-environment-empty.service", 0, CLD_EXITED); } +static void test_exec_environmentfile(Manager *m) { + static const char e[] = + "VAR1='word1 word2'\n" + "VAR2=word3 \n" + "# comment1\n" + "\n" + "; comment2\n" + " ; # comment3\n" + "line without an equal\n" + "VAR3='$word 5 6'\n"; + int r; + + r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE); + assert_se(r == 0); + + test(m, "exec-environmentfile.service", 0, CLD_EXITED); + + unlink("/tmp/test-exec_environmentfile.conf"); +} + +static void test_exec_passenvironment(Manager *m) { + /* test-execute runs under MANAGER_USER which, by default, forwards all + * variables present in the environment, but only those that are + * present _at the time it is created_! + * + * So these PassEnvironment checks are still expected to work, since we + * are ensuring the variables are not present at manager creation (they + * are unset explicitly in main) and are only set here. + * + * This is still a good approximation of how a test for MANAGER_SYSTEM + * would work. + */ + assert_se(setenv("VAR1", "word1 word2", 1) == 0); + assert_se(setenv("VAR2", "word3", 1) == 0); + assert_se(setenv("VAR3", "$word 5 6", 1) == 0); + test(m, "exec-passenvironment.service", 0, CLD_EXITED); + test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED); + test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED); + assert_se(unsetenv("VAR1") == 0); + assert_se(unsetenv("VAR2") == 0); + assert_se(unsetenv("VAR3") == 0); + test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED); +} + static void test_exec_umask(Manager *m) { test(m, "exec-umask-default.service", 0, CLD_EXITED); test(m, "exec-umask-0177.service", 0, CLD_EXITED); @@ -144,7 +200,51 @@ static void test_exec_umask(Manager *m) { static void test_exec_runtimedirectory(Manager *m) { test(m, "exec-runtimedirectory.service", 0, CLD_EXITED); test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); - test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + if (getgrnam("nobody")) + test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m"); +} + +static void test_exec_capabilityboundingset(Manager *m) { + int r; + + /* We use capsh to test if the capabilities are + * properly set, so be sure that it exists */ + r = find_binary("capsh", NULL); + if (r < 0) { + log_error_errno(r, "Skipping test_exec_capabilityboundingset, could not find capsh binary: %m"); + return; + } + + test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED); +} + +static void test_exec_privatenetwork(Manager *m) { + int r; + + r = find_binary("ip", NULL); + if (r < 0) { + log_error_errno(r, "Skipping test_exec_privatenetwork, could not find ip binary: %m"); + return; + } + + test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED); +} + +static void test_exec_oomscoreadjust(Manager *m) { + test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED); + test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED); +} + +static void test_exec_ioschedulingclass(Manager *m) { + test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED); } int main(int argc, char *argv[]) { @@ -154,13 +254,19 @@ int main(int argc, char *argv[]) { test_exec_ignoresigpipe, test_exec_privatetmp, test_exec_privatedevices, + test_exec_privatenetwork, test_exec_systemcallfilter, test_exec_systemcallerrornumber, test_exec_user, test_exec_group, test_exec_environment, + test_exec_environmentfile, + test_exec_passenvironment, test_exec_umask, test_exec_runtimedirectory, + test_exec_capabilityboundingset, + test_exec_oomscoreadjust, + test_exec_ioschedulingclass, NULL, }; test_function_t *test = NULL; @@ -177,7 +283,17 @@ int main(int argc, char *argv[]) { } assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0); - assert_se(set_unit_path(TEST_DIR) >= 0); + assert_se(set_unit_path(TEST_DIR "/test-execute/") >= 0); + + /* Unset VAR1, VAR2 and VAR3 which are used in the PassEnvironment test + * cases, otherwise (and if they are present in the environment), + * `manager_default_environment` will copy them into the default + * environment which is passed to each created job, which will make the + * tests that expect those not to be present to fail. + */ + assert_se(unsetenv("VAR1") == 0); + assert_se(unsetenv("VAR2") == 0); + assert_se(unsetenv("VAR3") == 0); r = manager_new(MANAGER_USER, true, &m); if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c new file mode 100644 index 0000000000..65d3a0a96e --- /dev/null +++ b/src/test/test-extract-word.c @@ -0,0 +1,558 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdlib.h> +#include <string.h> + +#include "extract-word.h" +#include "log.h" +#include "string-util.h" + +static void test_extract_first_word(void) { + const char *p, *original; + char *t; + + p = original = "foobar waldo"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 7); + + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\"foobar\"")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\'waldo\'")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\"")); + free(t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'"; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'")); + free(t); + assert_se(isempty(p)); + + p = original = "\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "\"fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "yay\'foo\'bar"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "yay\'foo\'bar")); + free(t); + assert_se(isempty(p)); + + p = original = "yay\'foo\'bar"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "yayfoobar")); + free(t); + assert_se(isempty(p)); + + p = original = " foobar "; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "foo\ba\x6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobax6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "föo")); + free(t); + assert_se(p == original + 13); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "pi\360\237\222\251le")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "foo::bar"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "foo")); + free(t); + assert_se(p == original + 5); + + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "bar")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "foo\\:bar::waldo"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); + assert_se(p == original + 5); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(isempty(p)); + + p = original = "\\w+\\b"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(isempty(p)); + + p = original = "-N ''"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "-N")); + free(t); + assert_se(p == original + 3); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "")); + free(t); + assert_se(isempty(p)); + + p = original = ":foo\\:bar::waldo:"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 1); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 11); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(p == original + 17); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "")); + free(t); + assert_se(p == NULL); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0); + assert_se(!t); + assert_se(!p); + + p = "foo\\xbar"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "fooxbar")); + free(t); + assert_se(p == NULL); + + p = "foo\\xbar"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RETAIN_ESCAPE) > 0); + assert_se(streq(t, "foo\\xbar")); + free(t); + assert_se(p == NULL); +} + +static void test_extract_first_word_and_warn(void) { + const char *p, *original; + char *t; + + p = original = "foobar waldo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 7); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'fooo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo\ba\x6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobax6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "föo")); + free(t); + assert_se(p == original + 13); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "pi\360\237\222\251le")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(isempty(p)); + + p = original = "\\w+\\b"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(isempty(p)); +} + +static void test_extract_many_words(void) { + const char *p, *original; + char *a, *b, *c; + + p = original = "foobar waldi piep"; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + assert_se(streq_ptr(b, "waldi")); + assert_se(streq_ptr(c, "piep")); + free(a); + free(b); + free(c); + + p = original = "'foobar' wa\"ld\"i "; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "'foobar'")); + assert_se(streq_ptr(b, "wa\"ld\"i")); + assert_se(streq_ptr(c, NULL)); + free(a); + free(b); + + p = original = "'foobar' wa\"ld\"i "; + assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + assert_se(streq_ptr(b, "waldi")); + assert_se(streq_ptr(c, NULL)); + free(a); + free(b); + + p = original = ""; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); + assert_se(streq_ptr(a, NULL)); + assert_se(streq_ptr(b, NULL)); + assert_se(streq_ptr(c, NULL)); + + p = original = " "; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); + assert_se(streq_ptr(a, NULL)); + assert_se(streq_ptr(b, NULL)); + assert_se(streq_ptr(c, NULL)); + + p = original = "foobar"; + assert_se(extract_many_words(&p, NULL, 0, NULL) == 0); + assert_se(p == original); + + p = original = "foobar waldi"; + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); + assert_se(p == original+7); + assert_se(streq_ptr(a, "foobar")); + free(a); + + p = original = " foobar "; + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + free(a); +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_extract_first_word(); + test_extract_first_word_and_warn(); + test_extract_many_words(); + + return 0; +} diff --git a/src/test/test-fdset.c b/src/test/test-fdset.c index 242c5d9dc2..282aab1246 100644 --- a/src/test/test-fdset.c +++ b/src/test/test-fdset.c @@ -20,9 +20,11 @@ #include <fcntl.h> #include <unistd.h> +#include "fd-util.h" #include "fdset.h" -#include "util.h" +#include "fileio.h" #include "macro.h" +#include "util.h" static void test_fdset_new_fill(void) { int fd = -1; diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index ad547822e7..bde3c7c3cf 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -23,13 +23,17 @@ #include <fcntl.h> #include <unistd.h> -#include "util.h" -#include "process-util.h" +#include "alloc-util.h" +#include "ctype.h" +#include "def.h" +#include "env-util.h" +#include "fd-util.h" #include "fileio.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" #include "strv.h" -#include "env-util.h" -#include "def.h" -#include "ctype.h" +#include "util.h" static void test_parse_env_file(void) { char t[] = "/tmp/test-fileio-in-XXXXXX", @@ -359,6 +363,26 @@ static void test_write_string_file_no_create(void) { unlink(fn); } +static void test_write_string_file_verify(void) { + _cleanup_free_ char *buf = NULL, *buf2 = NULL; + int r; + + assert_se(read_one_line_file("/proc/cmdline", &buf) >= 0); + assert_se((buf2 = strjoin(buf, "\n", NULL))); + + r = write_string_file("/proc/cmdline", buf, 0); + assert_se(r == -EACCES || r == -EIO); + r = write_string_file("/proc/cmdline", buf2, 0); + assert_se(r == -EACCES || r == -EIO); + + assert_se(write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0); + assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0); + + r = write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE); + assert_se(r == -EACCES || r == -EIO); + assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0); +} + static void test_load_env_file_pairs(void) { char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX"; int fd; @@ -415,6 +439,7 @@ int main(int argc, char *argv[]) { test_write_string_stream(); test_write_string_file(); test_write_string_file_no_create(); + test_write_string_file_verify(); test_load_env_file_pairs(); return 0; diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index 50e5dee0a7..27816ac779 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -19,9 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "fstab-util.h" -#include "util.h" #include "log.h" +#include "string-util.h" +#include "util.h" /* int fstab_filter_options(const char *opts, const char *names, diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index c691f577c6..6bf33306a9 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -17,9 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "hashmap.h" +#include "string-util.h" #include "strv.h" #include "util.h" -#include "hashmap.h" void test_hashmap_funcs(void); diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c index 6f5ef2615e..590175433c 100644 --- a/src/test/test-hostname-util.c +++ b/src/test/test-hostname-util.c @@ -21,9 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" #include "fileio.h" #include "hostname-util.h" +#include "string-util.h" +#include "util.h" static void test_hostname_is_valid(void) { assert_se(hostname_is_valid("foobar", false)); diff --git a/src/test/test-id128.c b/src/test/test-id128.c index a6a0cd77a1..32cf3f80ca 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -21,11 +21,13 @@ #include <string.h> -#include "systemd/sd-id128.h" +#include "sd-daemon.h" +#include "sd-id128.h" -#include "util.h" +#include "alloc-util.h" #include "macro.h" -#include "sd-daemon.h" +#include "string-util.h" +#include "util.h" #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) #define STR_WALDI "0102030405060708090a0b0c0d0e0f10" diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c new file mode 100644 index 0000000000..08fde94f7f --- /dev/null +++ b/src/test/test-install-root.c @@ -0,0 +1,665 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "fileio.h" +#include "install.h" +#include "mkdir.h" +#include "rm-rf.h" +#include "string-util.h" + +static void test_basic_mask_and_enable(const char *root) { + const char *p; + UnitFileState state; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/a.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/b.service"); + assert_se(symlink("a.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/c.service"); + assert_se(symlink("/usr/lib/systemd/system/a.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + p = strjoina(root, "/usr/lib/systemd/system/d.service"); + assert_se(symlink("c.service", p) >= 0); + + /* This one is interesting, as d follows a relative, then an absolute symlink */ + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", NULL) >= 0); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_mask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/dev/null")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); + assert_se(streq(changes[0].path, p)); + + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_MASKED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_MASKED); + + /* Enabling a masked unit should fail! */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == -ESHUTDOWN); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* Enabling it again should succeed but be a NOP */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), false, &changes, &n_changes) == 1); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + /* Disabling a disabled unit must suceed but be a NOP */ + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + /* Let's enable this indirectly via a symlink */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("d.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* Let's try to reenable */ + + assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("b.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/a.service"); + assert_se(streq(changes[0].path, p)); + assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); + assert_se(streq(changes[1].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "a.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "b.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "c.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "d.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +} + +static void test_linked_units(const char *root) { + const char *p, *q; + UnitFileState state; + UnitFileChange *changes = NULL; + unsigned n_changes = 0, i; + + /* + * We'll test three cases here: + * + * a) a unit file in /opt, that we use "systemctl link" and + * "systemctl enable" on to make it available to the system + * + * b) a unit file in /opt, that is statically linked into + * /usr/lib/systemd/system, that "enable" should work on + * correctly. + * + * c) a unit file in /opt, that is linked into + * /etc/systemd/system, and where "enable" should result in + * -ELOOP, since using information from /etc to generate + * information in /etc should not be allowed. + */ + + p = strjoina(root, "/opt/linked.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/opt/linked2.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/opt/linked3.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", NULL) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", NULL) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/linked2.service"); + assert_se(symlink("/opt/linked2.service", p) >= 0); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked3.service"); + assert_se(symlink("/opt/linked3.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked2.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked3.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* First, let's link the unit into the search path */ + assert_se(unit_file_link(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/opt/linked.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_LINKED); + + /* Let's unlink it from the search path again */ + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + + /* Now, let's not just link it, but also enable it */ + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("/opt/linked.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + for (i = 0 ; i < n_changes; i++) { + assert_se(changes[i].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[i].source, "/opt/linked.service")); + + if (p && streq(changes[i].path, p)) + p = NULL; + else if (q && streq(changes[i].path, q)) + q = NULL; + else + assert_not_reached("wut?"); + } + assert(!p && !q); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + /* And let's unlink it again */ + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked.service"); + for (i = 0; i < n_changes; i++) { + assert_se(changes[i].type == UNIT_FILE_UNLINK); + + if (p && streq(changes[i].path, p)) + p = NULL; + else if (q && streq(changes[i].path, q)) + q = NULL; + else + assert_not_reached("wut?"); + } + assert(!p && !q); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "linked.service", NULL) == -ENOENT); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked2.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 2); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/linked2.service"); + q = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/linked2.service"); + for (i = 0 ; i < n_changes; i++) { + assert_se(changes[i].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[i].source, "/opt/linked2.service")); + + if (p && streq(changes[i].path, p)) + p = NULL; + else if (q && streq(changes[i].path, q)) + q = NULL; + else + assert_not_reached("wut?"); + } + assert(!p && !q); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("linked3.service"), false, &changes, &n_changes) == -ELOOP); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + +static void test_default(const char *root) { + _cleanup_free_ char *def = NULL; + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + const char *p; + + p = strjoina(root, "/usr/lib/systemd/system/test-default-real.target"); + assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/test-default.target"); + assert_se(symlink("test-default-real.target", p) >= 0); + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + + assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "idontexist.target", false, &changes, &n_changes) == -ENOENT); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) == -ENOENT); + + assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, root, "test-default.target", false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/default.target"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_default(UNIT_FILE_SYSTEM, root, &def) >= 0); + assert_se(streq_ptr(def, "test-default-real.target")); +} + +static void test_add_dependency(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + const char *p; + + p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-target.target"); + assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-target.target"); + assert_se(symlink("real-add-dependency-test-target.target", p) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/real-add-dependency-test-service.service"); + assert_se(write_string_file(p, "# pretty much empty", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/add-dependency-test-service.service"); + assert_se(symlink("real-add-dependency-test-service.service", p) >= 0); + + assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + +static void test_template_enable(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileState state; + const char *p; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/template@.service"); + assert_se(write_string_file(p, + "[Install]\n" + "DefaultInstance=def\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/template-symlink@.service"); + assert_se(symlink("template@.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@def.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), false, &changes, &n_changes) >= 0); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@foo.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("template-symlink@quux.service"), false, &changes, &n_changes) >= 0); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/template@quux.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@def.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@foo.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "template-symlink@quux.service", &state) >= 0 && state == UNIT_FILE_ENABLED); +} + +static void test_indirect(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + UnitFileState state; + const char *p; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/indirecta.service"); + assert_se(write_string_file(p, + "[Install]\n" + "Also=indirectb.service\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/indirectb.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/indirectc.service"); + assert_se(symlink("indirecta.service", p) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + + assert_se(unit_file_enable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirecta.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectb.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "indirectc.service", &state) >= 0 && state == UNIT_FILE_INDIRECT); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/indirectb.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; +} + +static void test_preset_and_list(const char *root) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0, i; + const char *p, *q; + UnitFileState state; + bool got_yes = false, got_no = false; + Iterator j; + UnitFileList *fl; + Hashmap *h; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) == -ENOENT); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) == -ENOENT); + + p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); + assert_se(write_string_file(p, + "[Install]\n" + "WantedBy=multi-user.target\n", WRITE_STRING_FILE_CREATE) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system-preset/test.preset"); + assert_se(write_string_file(p, + "enable *-yes.*\n" + "disable *\n", WRITE_STRING_FILE_CREATE) >= 0); + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_disable(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); + assert_se(n_changes == 1); + assert_se(changes[0].type == UNIT_FILE_UNLINK); + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); + assert_se(streq(changes[0].path, p)); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset(UNIT_FILE_SYSTEM, false, root, STRV_MAKE("preset-no.service"), UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + assert_se(n_changes == 0); + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(unit_file_preset_all(UNIT_FILE_SYSTEM, false, root, UNIT_FILE_PRESET_FULL, false, &changes, &n_changes) >= 0); + + assert_se(n_changes > 0); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/multi-user.target.wants/preset-yes.service"); + + for (i = 0; i < n_changes; i++) { + + if (changes[i].type == UNIT_FILE_SYMLINK) { + assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); + assert_se(streq(changes[i].path, p)); + } else + assert_se(changes[i].type == UNIT_FILE_UNLINK); + } + + unit_file_changes_free(changes, n_changes); + changes = NULL; n_changes = 0; + + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-yes.service", &state) >= 0 && state == UNIT_FILE_ENABLED); + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "preset-no.service", &state) >= 0 && state == UNIT_FILE_DISABLED); + + assert_se(h = hashmap_new(&string_hash_ops)); + assert_se(unit_file_get_list(UNIT_FILE_SYSTEM, root, h) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system/preset-yes.service"); + q = strjoina(root, "/usr/lib/systemd/system/preset-no.service"); + + HASHMAP_FOREACH(fl, h, j) { + assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, basename(fl->path), &state) >= 0); + assert_se(fl->state == state); + + if (streq(fl->path, p)) { + got_yes = true; + assert_se(fl->state == UNIT_FILE_ENABLED); + } else if (streq(fl->path, q)) { + got_no = true; + assert_se(fl->state == UNIT_FILE_DISABLED); + } else + assert_se(IN_SET(fl->state, UNIT_FILE_DISABLED, UNIT_FILE_STATIC, UNIT_FILE_INDIRECT)); + } + + unit_file_list_free(h); + + assert_se(got_yes && got_no); +} + +int main(int argc, char *argv[]) { + char root[] = "/tmp/rootXXXXXX"; + const char *p; + + assert_se(mkdtemp(root)); + + p = strjoina(root, "/usr/lib/systemd/system/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, SYSTEM_CONFIG_UNIT_PATH"/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, "/run/systemd/system/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, "/opt/"); + assert_se(mkdir_p(p, 0755) >= 0); + + p = strjoina(root, "/usr/lib/systemd/system-preset/"); + assert_se(mkdir_p(p, 0755) >= 0); + + test_basic_mask_and_enable(root); + test_linked_units(root); + test_default(root); + test_add_dependency(root); + test_template_enable(root); + test_indirect(root); + test_preset_and_list(root); + + assert_se(rm_rf(root, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); + + return 0; +} diff --git a/src/test/test-install.c b/src/test/test-install.c index 5ee52e64cb..359b262347 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -46,17 +46,19 @@ int main(int argc, char* argv[]) { const char *const files2[] = { "/home/lennart/test.service", NULL }; UnitFileChange *changes = NULL; unsigned n_changes = 0; + UnitFileState state = 0; h = hashmap_new(&string_hash_ops); r = unit_file_get_list(UNIT_FILE_SYSTEM, NULL, h); assert_se(r == 0); HASHMAP_FOREACH(p, h, i) { - UnitFileState s; + UnitFileState s = _UNIT_FILE_STATE_INVALID; - s = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path)); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(p->path), &s); - assert_se(p->state == s); + assert_se((r < 0 && p->state == UNIT_FILE_BAD) || + (p->state == s)); fprintf(stderr, "%s (%s)\n", p->path, @@ -78,7 +80,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_ENABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); log_error("disable"); @@ -91,7 +95,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); log_error("mask"); changes = NULL; @@ -106,7 +112,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); log_error("unmask"); changes = NULL; @@ -121,7 +129,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); log_error("mask"); changes = NULL; @@ -133,7 +143,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); log_error("disable"); changes = NULL; @@ -148,7 +160,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_MASKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_MASKED); log_error("umask"); changes = NULL; @@ -160,7 +174,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0]) == UNIT_FILE_DISABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, files[0], &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_DISABLED); log_error("enable files2"); changes = NULL; @@ -172,19 +188,22 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); log_error("disable files2"); changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); log_error("link files2"); changes = NULL; @@ -196,19 +215,22 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_LINKED); log_error("disable files2"); changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); log_error("link files2"); changes = NULL; @@ -220,7 +242,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_LINKED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_LINKED); log_error("reenable files2"); changes = NULL; @@ -232,19 +256,22 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == UNIT_FILE_ENABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); log_error("disable files2"); changes = NULL; n_changes = 0; - r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, (char**) files2, &changes, &n_changes); + r = unit_file_disable(UNIT_FILE_SYSTEM, false, NULL, STRV_MAKE(basename(files2[0])), &changes, &n_changes); assert_se(r >= 0); dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0])) == _UNIT_FILE_STATE_INVALID); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files2[0]), &state); + assert_se(r < 0); log_error("preset files"); changes = NULL; n_changes = 0; @@ -255,7 +282,9 @@ int main(int argc, char* argv[]) { dump_changes(changes, n_changes); unit_file_changes_free(changes, n_changes); - assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0])) == UNIT_FILE_ENABLED); + r = unit_file_get_state(UNIT_FILE_SYSTEM, NULL, basename(files[0]), &state); + assert_se(r >= 0); + assert_se(state == UNIT_FILE_ENABLED); return 0; } diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 4944bf6ad9..5841cb3fb1 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "clean-ipc.h" +#include "user-util.h" +#include "util.h" int main(int argc, char *argv[]) { uid_t uid; diff --git a/src/test/test-json.c b/src/test/test-json.c index 1058c583c3..3995224eea 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -21,8 +21,10 @@ #include <math.h> -#include "util.h" +#include "alloc-util.h" #include "json.h" +#include "string-util.h" +#include "util.h" static void test_one(const char *data, ...) { void *state = NULL; diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index 34c49b969a..350eaf734d 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -18,12 +18,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <unistd.h> #include <getopt.h> +#include <stdio.h> #include <sys/epoll.h> +#include <unistd.h> #include "libudev.h" + +#include "string-util.h" #include "udev-util.h" #include "util.h" diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 7d7e08dc5d..5a12e959d4 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -21,9 +21,12 @@ #include <sys/socket.h> +#include "alloc-util.h" +#include "fd-util.h" #include "namespace.h" -#include "util.h" #include "process-util.h" +#include "string-util.h" +#include "util.h" static void test_tmpdir(const char *id, const char *A, const char *B) { _cleanup_free_ char *a, *b; diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c index 2879d7450f..a1e8774063 100644 --- a/src/test/test-netlink-manual.c +++ b/src/test/test-netlink-manual.c @@ -20,15 +20,16 @@ ***/ #include <arpa/inet.h> -#include <net/if.h> +#include <libkmod.h> #include <linux/ip.h> +#include <net/if.h> #include <linux/if_tunnel.h> -#include <libkmod.h> -#include "util.h" -#include "macro.h" #include "sd-netlink.h" +#include "macro.h" +#include "util.h" + static int load_module(const char *mod_name) { struct kmod_ctx *ctx; struct kmod_list *list = NULL, *l; diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c new file mode 100644 index 0000000000..f0d5d71083 --- /dev/null +++ b/src/test/test-parse-util.c @@ -0,0 +1,495 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <locale.h> +#include <math.h> + +#include "log.h" +#include "parse-util.h" + +static void test_parse_boolean(void) { + assert_se(parse_boolean("1") == 1); + assert_se(parse_boolean("y") == 1); + assert_se(parse_boolean("Y") == 1); + assert_se(parse_boolean("yes") == 1); + assert_se(parse_boolean("YES") == 1); + assert_se(parse_boolean("true") == 1); + assert_se(parse_boolean("TRUE") == 1); + assert_se(parse_boolean("on") == 1); + assert_se(parse_boolean("ON") == 1); + + assert_se(parse_boolean("0") == 0); + assert_se(parse_boolean("n") == 0); + assert_se(parse_boolean("N") == 0); + assert_se(parse_boolean("no") == 0); + assert_se(parse_boolean("NO") == 0); + assert_se(parse_boolean("false") == 0); + assert_se(parse_boolean("FALSE") == 0); + assert_se(parse_boolean("off") == 0); + assert_se(parse_boolean("OFF") == 0); + + assert_se(parse_boolean("garbage") < 0); + assert_se(parse_boolean("") < 0); + assert_se(parse_boolean("full") < 0); +} + +static void test_parse_pid(void) { + int r; + pid_t pid; + + r = parse_pid("100", &pid); + assert_se(r == 0); + assert_se(pid == 100); + + r = parse_pid("0x7FFFFFFF", &pid); + assert_se(r == 0); + assert_se(pid == 2147483647); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("-100", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + r = parse_pid("junk", &pid); + assert_se(r == -EINVAL); +} + +static void test_parse_mode(void) { + mode_t m; + + assert_se(parse_mode("-1", &m) < 0); + assert_se(parse_mode("", &m) < 0); + assert_se(parse_mode("888", &m) < 0); + assert_se(parse_mode("77777", &m) < 0); + + assert_se(parse_mode("544", &m) >= 0 && m == 0544); + assert_se(parse_mode("777", &m) >= 0 && m == 0777); + assert_se(parse_mode("7777", &m) >= 0 && m == 07777); + assert_se(parse_mode("0", &m) >= 0 && m == 0); +} + +static void test_parse_size(void) { + uint64_t bytes; + + assert_se(parse_size("111", 1024, &bytes) == 0); + assert_se(bytes == 111); + + assert_se(parse_size("111.4", 1024, &bytes) == 0); + assert_se(bytes == 111); + + assert_se(parse_size(" 112 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size("3.5 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024 + 512); + + assert_se(parse_size("3. K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size("3.0 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL); + + assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0); + assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512); + + assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("3.5G3B", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3); + + assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4); + + assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("4T3G3B", 1024, &bytes) == 0); + assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); + + assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0); + assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); + + assert_se(parse_size("12P", 1024, &bytes) == 0); + assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024); + + assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("3E 2P", 1024, &bytes) == 0); + assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024); + + assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); +} + +static void test_parse_range(void) { + unsigned lower, upper; + + /* Successful cases */ + assert_se(parse_range("111", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 111); + + assert_se(parse_range("111-123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("123-111", &lower, &upper) == 0); + assert_se(lower == 123); + assert_se(upper == 111); + + assert_se(parse_range("123-123", &lower, &upper) == 0); + assert_se(lower == 123); + assert_se(upper == 123); + + assert_se(parse_range("0", &lower, &upper) == 0); + assert_se(lower == 0); + assert_se(upper == 0); + + assert_se(parse_range("0-15", &lower, &upper) == 0); + assert_se(lower == 0); + assert_se(upper == 15); + + assert_se(parse_range("15-0", &lower, &upper) == 0); + assert_se(lower == 15); + assert_se(upper == 0); + + assert_se(parse_range("128-65535", &lower, &upper) == 0); + assert_se(lower == 128); + assert_se(upper == 65535); + + assert_se(parse_range("1024-4294967295", &lower, &upper) == 0); + assert_se(lower == 1024); + assert_se(upper == 4294967295); + + /* Leading whitespace is acceptable */ + assert_se(parse_range(" 111", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 111); + + assert_se(parse_range(" 111-123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("111- 123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("\t111-\t123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + /* Error cases, make sure they fail as expected */ + lower = upper = 9999; + assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Empty string */ + lower = upper = 9999; + assert_se(parse_range("", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */ + assert_se(parse_range("111--123", &lower, &upper) == -ERANGE); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Error on trailing dash */ + assert_se(parse_range("111-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111--", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111- ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Whitespace is not a separator */ + assert_se(parse_range("111 123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Trailing whitespace is invalid (from safe_atou) */ + assert_se(parse_range("111 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Out of the "unsigned" range, this is 1<<64 */ + assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE); + assert_se(lower == 9999); + assert_se(upper == 9999); +} + +static void test_safe_atolli(void) { + int r; + long long l; + + r = safe_atolli("12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atolli(" 12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atolli("-12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atolli(" -12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atolli("12345678901234567890", &l); + assert_se(r == -ERANGE); + + r = safe_atolli("-12345678901234567890", &l); + assert_se(r == -ERANGE); + + r = safe_atolli("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atou16(void) { + int r; + uint16_t l; + + r = safe_atou16("12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atou16(" 12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atou16("123456", &l); + assert_se(r == -ERANGE); + + r = safe_atou16("-1", &l); + assert_se(r == -ERANGE); + + r = safe_atou16(" -1", &l); + assert_se(r == -ERANGE); + + r = safe_atou16("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atoi16(void) { + int r; + int16_t l; + + r = safe_atoi16("-12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atoi16(" -12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atoi16("32767", &l); + assert_se(r == 0); + assert_se(l == 32767); + + r = safe_atoi16(" 32767", &l); + assert_se(r == 0); + assert_se(l == 32767); + + r = safe_atoi16("36536", &l); + assert_se(r == -ERANGE); + + r = safe_atoi16("-32769", &l); + assert_se(r == -ERANGE); + + r = safe_atoi16("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atod(void) { + int r; + double d; + char *e; + + r = safe_atod("junk", &d); + assert_se(r == -EINVAL); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); + + /* Check if this really is locale independent */ + if (setlocale(LC_NUMERIC, "de_DE.utf8")) { + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001); + } + + /* And check again, reset */ + assert_se(setlocale(LC_NUMERIC, "C")); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_parse_boolean(); + test_parse_pid(); + test_parse_mode(); + test_parse_size(); + test_parse_range(); + test_safe_atolli(); + test_safe_atou16(); + test_safe_atoi16(); + test_safe_atod(); + + return 0; +} diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index aa4bac6cdd..65cb894ff7 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -19,29 +19,39 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <stdlib.h> #include <sys/stat.h> -#include "path-lookup.h" #include "log.h" -#include "strv.h" +#include "path-lookup.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" static void test_paths(ManagerRunningAs running_as, bool personal) { char template[] = "/tmp/test-path-lookup.XXXXXXX"; - _cleanup_lookup_paths_free_ LookupPaths lp = {}; - char *exists, *not; + _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {}; + _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {}; + char *exists, *not, *systemd_unit_path; assert_se(mkdtemp(template)); exists = strjoina(template, "/exists"); assert_se(mkdir(exists, 0755) == 0); not = strjoina(template, "/not"); - assert_se(lookup_paths_init(&lp, running_as, personal, NULL, exists, not, not) == 0); + assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); + assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0); + + assert_se(!strv_isempty(lp_without_env.unit_path)); + assert_se(strv_contains(lp_without_env.unit_path, exists)); + assert_se(strv_contains(lp_without_env.unit_path, not)); - assert_se(!strv_isempty(lp.unit_path)); - assert_se(strv_contains(lp.unit_path, exists)); - assert_se(strv_contains(lp.unit_path, not)); + systemd_unit_path = strjoina(template, "/systemd-unit-path"); + assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); + assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0); + assert_se(strv_length(lp_with_env.unit_path) == 1); + assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path)); assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index fce4e81a09..3f0f0264ab 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -20,14 +20,18 @@ ***/ #include <stdio.h> -#include <unistd.h> #include <sys/mount.h> +#include <unistd.h> -#include "path-util.h" -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "macro.h" -#include "strv.h" +#include "mount-util.h" +#include "path-util.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define test_path_compare(a, b, result) { \ assert_se(path_compare(a, b) == result); \ @@ -75,20 +79,6 @@ static void test_path(void) { assert_se(streq(basename("/aa///file..."), "file...")); assert_se(streq(basename("file.../"), "")); -#define test_parent(x, y) { \ - _cleanup_free_ char *z = NULL; \ - int r = path_get_parent(x, &z); \ - printf("expected: %s\n", y ? y : "error"); \ - printf("actual: %s\n", r<0 ? "error" : z); \ - assert_se((y==NULL) ^ (r==0)); \ - assert_se(y==NULL || path_equal(z, y)); \ - } - - test_parent("./aa/bb/../file.da.", "./aa/bb/.."); - test_parent("/aa///.file", "/aa///"); - test_parent("/aa///file...", "/aa///"); - test_parent("file.../", NULL); - fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY); assert_se(fd >= 0); assert_se(fd_is_mount_point(fd, "/", 0) > 0); @@ -104,32 +94,28 @@ static void test_path(void) { } } -static void test_find_binary(const char *self, bool local) { +static void test_find_binary(const char *self) { char *p; - assert_se(find_binary("/bin/sh", local, &p) == 0); + assert_se(find_binary("/bin/sh", &p) == 0); puts(p); - assert_se(streq(p, "/bin/sh")); + assert_se(path_equal(p, "/bin/sh")); free(p); - assert_se(find_binary(self, local, &p) == 0); + assert_se(find_binary(self, &p) == 0); puts(p); assert_se(endswith(p, "/test-path-util")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("sh", local, &p) == 0); + assert_se(find_binary("sh", &p) == 0); puts(p); assert_se(endswith(p, "/sh")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT); - - assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) == - (local ? -ENOENT : 0)); - if (!local) - free(p); + assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT); + assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT); } static void test_prefixes(void) { @@ -210,9 +196,10 @@ static void test_fsck_exists(void) { unsetenv("PATH"); /* fsck.minix is provided by util-linux and will probably exist. */ - assert_se(fsck_exists("minix") == 0); + assert_se(fsck_exists("minix") == 1); - assert_se(fsck_exists("AbCdE") == -ENOENT); + assert_se(fsck_exists("AbCdE") == 0); + assert_se(fsck_exists("/../bin/") == 0); } static void test_make_relative(void) { @@ -450,8 +437,7 @@ static void test_path_is_mount_point(void) { int main(int argc, char **argv) { test_path(); - test_find_binary(argv[0], true); - test_find_binary(argv[0], false); + test_find_binary(argv[0]); test_prefixes(); test_path_join(); test_fsck_exists(); diff --git a/src/test/test-path.c b/src/test/test-path.c index 676c9f1793..8302bdd283 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -17,16 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> -#include "unit.h" -#include "manager.h" -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "macro.h" -#include "strv.h" +#include "manager.h" #include "mkdir.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "unit.h" +#include "util.h" typedef void (*test_function_t)(Manager *m); @@ -254,7 +258,7 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - assert_se(set_unit_path(TEST_DIR) >= 0); + assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0); for (test = tests; test && *test; test++) { int r; diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c index 1e2e42cbca..07273ffe79 100644 --- a/src/test/test-prioq.c +++ b/src/test/test-prioq.c @@ -21,10 +21,11 @@ #include <stdlib.h> -#include "util.h" -#include "set.h" +#include "alloc-util.h" #include "prioq.h" +#include "set.h" #include "siphash24.h" +#include "util.h" #define SET_SIZE 1024*4 diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index eb0f443a43..48be5a3a87 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -18,17 +18,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> -#include "process-util.h" +#include "alloc-util.h" #include "log.h" -#include "util.h" #include "macro.h" -#include "virt.h" +#include "process-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" +#include "virt.h" static void test_get_process_comm(void) { struct stat st; @@ -53,7 +55,7 @@ static void test_get_process_comm(void) { assert_se(get_process_cmdline(1, 8, false, &d) >= 0); log_info("pid1 cmdline truncated: '%s'", d); - assert_se(get_parent_of_pid(1, &e) >= 0); + assert_se(get_process_ppid(1, &e) >= 0); log_info("pid1 ppid: "PID_FMT, e); assert_se(e == 0); diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c index b1d42d77fd..2de2091561 100644 --- a/src/test/test-replace-var.c +++ b/src/test/test-replace-var.c @@ -21,9 +21,10 @@ #include <string.h> -#include "util.h" #include "macro.h" #include "replace-var.h" +#include "string-util.h" +#include "util.h" static char *lookup(const char *variable, void *userdata) { return strjoin("<<<", variable, ">>>", NULL); diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c index f5bae65bef..b3ccc7509d 100644 --- a/src/test/test-sigbus.c +++ b/src/test/test-sigbus.c @@ -21,8 +21,9 @@ #include <sys/mman.h> -#include "util.h" +#include "fd-util.h" #include "sigbus.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int fd = -1; diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 2c18090ae5..33ff3755bc 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -17,12 +17,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "socket-util.h" +#include "alloc-util.h" +#include "async.h" +#include "fd-util.h" #include "in-addr-util.h" -#include "util.h" -#include "macro.h" #include "log.h" -#include "async.h" +#include "macro.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" static void test_socket_address_parse(void) { SocketAddress a; @@ -38,28 +41,25 @@ static void test_socket_address_parse(void) { assert_se(socket_address_parse(&a, "65535") >= 0); - if (socket_ipv6_is_supported()) { - assert_se(socket_address_parse(&a, "[::1]") < 0); - assert_se(socket_address_parse(&a, "[::1]8888") < 0); - assert_se(socket_address_parse(&a, "::1") < 0); - assert_se(socket_address_parse(&a, "[::1]:0") < 0); - assert_se(socket_address_parse(&a, "[::1]:65536") < 0); - assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0); + /* The checks below will pass even if ipv6 is disabled in + * kernel. The underlying glibc's inet_pton() is just a string + * parser and doesn't make any syscalls. */ - assert_se(socket_address_parse(&a, "8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); + assert_se(socket_address_parse(&a, "[::1]") < 0); + assert_se(socket_address_parse(&a, "[::1]8888") < 0); + assert_se(socket_address_parse(&a, "::1") < 0); + assert_se(socket_address_parse(&a, "[::1]:0") < 0); + assert_se(socket_address_parse(&a, "[::1]:65536") < 0); + assert_se(socket_address_parse(&a, "[a:b:1]:8888") < 0); - assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); + assert_se(socket_address_parse(&a, "8888") >= 0); + assert_se(a.sockaddr.sa.sa_family == (socket_ipv6_is_supported() ? AF_INET6 : AF_INET)); - assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET6); - } else { - assert_se(socket_address_parse(&a, "[::1]:8888") < 0); + assert_se(socket_address_parse(&a, "[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888") >= 0); + assert_se(a.sockaddr.sa.sa_family == AF_INET6); - assert_se(socket_address_parse(&a, "8888") >= 0); - assert_se(a.sockaddr.sa.sa_family == AF_INET); - } + assert_se(socket_address_parse(&a, "[::1]:8888") >= 0); + assert_se(a.sockaddr.sa.sa_family == AF_INET6); assert_se(socket_address_parse(&a, "192.168.1.254:8888") >= 0); assert_se(a.sockaddr.sa.sa_family == AF_INET); diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c index 4ec648ae66..1d8eda0c15 100644 --- a/src/test/test-strbuf.c +++ b/src/test/test-strbuf.c @@ -23,6 +23,7 @@ #include <string.h> #include "strbuf.h" +#include "string-util.h" #include "strv.h" #include "util.h" diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c new file mode 100644 index 0000000000..25444c794a --- /dev/null +++ b/src/test/test-string-util.c @@ -0,0 +1,61 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "string-util.h" + +static void test_string_erase(void) { + char *x; + + x = strdupa(""); + assert_se(streq(string_erase(x), "")); + + x = strdupa("1"); + assert_se(streq(string_erase(x), "x")); + + x = strdupa("12"); + assert_se(streq(string_erase(x), "xx")); + + x = strdupa("123"); + assert_se(streq(string_erase(x), "xxx")); + + x = strdupa("1234"); + assert_se(streq(string_erase(x), "xxxx")); + + x = strdupa("12345"); + assert_se(streq(string_erase(x), "xxxxx")); + + x = strdupa("123456"); + assert_se(streq(string_erase(x), "xxxxxx")); + + x = strdupa("1234567"); + assert_se(streq(string_erase(x), "xxxxxxx")); + + x = strdupa("12345678"); + assert_se(streq(string_erase(x), "xxxxxxxx")); + + x = strdupa("123456789"); + assert_se(streq(string_erase(x), "xxxxxxxxx")); +} + +int main(int argc, char *argv[]) { + test_string_erase(); + return 0; +} diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c index 6cec8768b1..10fc98ced5 100644 --- a/src/test/test-strip-tab-ansi.c +++ b/src/test/test-strip-tab-ansi.c @@ -21,8 +21,9 @@ #include <stdio.h> -#include "util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" int main(int argc, char *argv[]) { char *p; diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 623c926521..c27f15283e 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -22,9 +22,11 @@ #include <string.h> -#include "util.h" +#include "alloc-util.h" #include "specifier.h" +#include "string-util.h" #include "strv.h" +#include "util.h" static void test_specifier_printf(void) { static const Specifier table[] = { diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c index 858a4081da..e411d479ab 100644 --- a/src/test/test-strxcpyx.c +++ b/src/test/test-strxcpyx.c @@ -21,8 +21,9 @@ #include <string.h> -#include "util.h" +#include "string-util.h" #include "strxcpyx.h" +#include "util.h" static void test_strpcpy(void) { char target[25]; diff --git a/src/test/test-tables.c b/src/test/test-tables.c index 0e5ab1645f..da27cde3da 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -17,7 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "architecture.h" #include "automount.h" +#include "bus-xml-policy.h" +#include "busname.h" #include "cgroup.h" #include "compress.h" #include "condition.h" @@ -25,7 +28,10 @@ #include "execute.h" #include "install.h" #include "job.h" +#include "journald-server.h" #include "kill.h" +#include "link-config.h" +#include "locale-util.h" #include "log.h" #include "logs-show.h" #include "mount.h" @@ -33,7 +39,6 @@ #include "scope.h" #include "service.h" #include "slice.h" -#include "snapshot.h" #include "socket-util.h" #include "socket.h" #include "swap.h" @@ -42,12 +47,7 @@ #include "unit-name.h" #include "unit.h" #include "util.h" -#include "architecture.h" -#include "link-config.h" -#include "bus-xml-policy.h" -#include "busname.h" -#include "journald-server.h" -#include "locale-util.h" +#include "rlimit-util.h" #include "test-tables.h" @@ -97,7 +97,6 @@ int main(int argc, char **argv) { test_table(service_state, SERVICE_STATE); test_table(service_type, SERVICE_TYPE); test_table(slice_state, SLICE_STATE); - test_table(snapshot_state, SNAPSHOT_STATE); test_table(socket_address_bind_ipv6_only, SOCKET_ADDRESS_BIND_IPV6_ONLY); test_table(socket_exec_command, SOCKET_EXEC_COMMAND); test_table(socket_result, SOCKET_RESULT); diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index d81fdb9923..e940b5a204 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -21,10 +21,12 @@ #include <stdio.h> #include <stdbool.h> -#include "terminal-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" #include "macro.h" +#include "terminal-util.h" #include "util.h" -#include "log.h" static void test_default_term_for_tty(void) { puts(default_term_for_tty("/dev/tty23")); diff --git a/src/test/test-time.c b/src/test/test-time.c index 3840fff061..820e4aaee2 100644 --- a/src/test/test-time.c +++ b/src/test/test-time.c @@ -57,6 +57,28 @@ static void test_parse_sec(void) { assert_se(parse_sec(".3 infinity", &u) < 0); } +static void test_parse_time(void) { + usec_t u; + + assert_se(parse_time("5", &u, 1) >= 0); + assert_se(u == 5); + + assert_se(parse_time("5", &u, USEC_PER_MSEC) >= 0); + assert_se(u == 5 * USEC_PER_MSEC); + + assert_se(parse_time("5", &u, USEC_PER_SEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, 1) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, USEC_PER_SEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); + + assert_se(parse_time("5s", &u, USEC_PER_MSEC) >= 0); + assert_se(u == 5 * USEC_PER_SEC); +} + static void test_parse_nsec(void) { nsec_t u; @@ -161,6 +183,7 @@ static void test_get_timezones(void) { int main(int argc, char *argv[]) { test_parse_sec(); + test_parse_time(); test_parse_nsec(); test_format_timespan(1); test_format_timespan(USEC_PER_MSEC); diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index 221dd67eb2..a8bd722e44 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -20,12 +20,16 @@ ***/ #include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "string-util.h" +#include "util.h" int main(int argc, char** argv) { const char *p = argv[1] ?: "/tmp"; diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 2b765a3e90..9cc64f7c68 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -18,19 +18,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> #include <errno.h> -#include <unistd.h> #include <sched.h> +#include <stdio.h> +#include <stdlib.h> #include <sys/mount.h> #include <sys/signalfd.h> +#include <unistd.h> +#include "fs-util.h" #include "missing.h" #include "selinux-util.h" #include "signal-util.h" -#include "udev.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" static int fake_filesystems(void) { static const struct fakefs { @@ -42,7 +44,7 @@ static int fake_filesystems(void) { { "test/dev", "/dev", "failed to mount test /dev" }, { "test/run", "/run", "failed to mount test /run" }, { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, - { "test/run", "/usr/lib/udev/rules.d", "failed to mount empty /usr/lib/udev/rules.d" }, + { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" }, }; unsigned int i; int err; @@ -64,7 +66,7 @@ static int fake_filesystems(void) { err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL); if (err < 0) { err = -errno; - fprintf(stderr, "%s %m", fakefss[i].error); + fprintf(stderr, "%s %m\n", fakefss[i].error); return err; } } diff --git a/src/test/test-uid-range.c b/src/test/test-uid-range.c index bc5baa2fcb..4dcf10e26d 100644 --- a/src/test/test-uid-range.c +++ b/src/test/test-uid-range.c @@ -21,8 +21,10 @@ #include <stddef.h> -#include "util.h" +#include "alloc-util.h" #include "uid-range.h" +#include "user-util.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_free_ UidRange *p = NULL; diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 8358789e6f..c3973a316e 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -20,23 +20,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <fcntl.h> #include <stddef.h> +#include <stdio.h> #include <string.h> +#include <sys/capability.h> #include <unistd.h> -#include <fcntl.h> -#include "install.h" -#include "install-printf.h" -#include "specifier.h" -#include "util.h" -#include "macro.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "hashmap.h" +#include "hostname-util.h" +#include "install-printf.h" +#include "install.h" #include "load-fragment.h" +#include "macro.h" +#include "specifier.h" +#include "string-util.h" #include "strv.h" -#include "fileio.h" #include "test-helper.h" -#include "hostname-util.h" +#include "user-util.h" +#include "util.h" static int test_unit_file_get_set(void) { int r; @@ -554,76 +559,215 @@ static void test_load_env_file_5(void) { static void test_install_printf(void) { char name[] = "name.service", - path[] = "/run/systemd/system/name.service", - user[] = "xxxx-no-such-user"; - UnitFileInstallInfo i = {name, path, user}; - UnitFileInstallInfo i2 = {name, path, NULL}; + path[] = "/run/systemd/system/name.service"; + UnitFileInstallInfo i = { .name = name, .path = path, }; + UnitFileInstallInfo i2 = { .name= name, .path = path, }; char name3[] = "name@inst.service", path3[] = "/run/systemd/system/name.service"; - UnitFileInstallInfo i3 = {name3, path3, user}; - UnitFileInstallInfo i4 = {name3, path3, NULL}; + UnitFileInstallInfo i3 = { .name = name3, .path = path3, }; + UnitFileInstallInfo i4 = { .name = name3, .path = path3, }; - _cleanup_free_ char *mid, *bid, *host; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL; assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); assert_se((host = gethostname_malloc())); + assert_se((user = getusername_malloc())); + assert_se(asprintf(&uid, UID_FMT, getuid()) >= 0); #define expect(src, pattern, result) \ do { \ _cleanup_free_ char *t = NULL; \ _cleanup_free_ char \ *d1 = strdup(i.name), \ - *d2 = strdup(i.path), \ - *d3 = strdup(i.user); \ + *d2 = strdup(i.path); \ assert_se(install_full_printf(&src, pattern, &t) >= 0 || !result); \ memzero(i.name, strlen(i.name)); \ memzero(i.path, strlen(i.path)); \ - memzero(i.user, strlen(i.user)); \ - assert_se(d1 && d2 && d3); \ + assert_se(d1 && d2); \ if (result) { \ printf("%s\n", t); \ - assert_se(streq(t, result)); \ - } else assert_se(t == NULL); \ + assert_se(streq(t, result)); \ + } else assert_se(t == NULL); \ strcpy(i.name, d1); \ strcpy(i.path, d2); \ - strcpy(i.user, d3); \ } while(false) - assert_se(setenv("USER", "root", 1) == 0); - expect(i, "%n", "name.service"); expect(i, "%N", "name"); expect(i, "%p", "name"); expect(i, "%i", ""); - expect(i, "%u", "xxxx-no-such-user"); - - DISABLE_WARNING_NONNULL; - expect(i, "%U", NULL); - REENABLE_WARNING; + expect(i, "%u", user); + expect(i, "%U", uid); expect(i, "%m", mid); expect(i, "%b", bid); expect(i, "%H", host); - expect(i2, "%u", "root"); - expect(i2, "%U", "0"); + expect(i2, "%u", user); + expect(i2, "%U", uid); expect(i3, "%n", "name@inst.service"); expect(i3, "%N", "name@inst"); expect(i3, "%p", "name"); - expect(i3, "%u", "xxxx-no-such-user"); - - DISABLE_WARNING_NONNULL; - expect(i3, "%U", NULL); - REENABLE_WARNING; + expect(i3, "%u", user); + expect(i3, "%U", uid); expect(i3, "%m", mid); expect(i3, "%b", bid); expect(i3, "%H", host); - expect(i4, "%u", "root"); - expect(i4, "%U", "0"); + expect(i4, "%u", user); + expect(i4, "%U", uid); +} + +static uint64_t make_cap(int cap) { + return ((uint64_t) 1ULL << (uint64_t) cap); +} + +static void test_config_parse_bounding_set(void) { + /* int config_parse_bounding_set( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ + int r; + uint64_t capability_bounding_set_drop = 0; + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_RAW", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW)); + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL)); + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "~", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == (uint64_t) 0ULL); + + capability_bounding_set_drop = 0; + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); +} + +static void test_config_parse_rlimit(void) { + struct rlimit * rl[_RLIMIT_MAX] = {}; + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); + assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + + rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + + rl[RLIMIT_RTTIME] = mfree(rl[RLIMIT_RTTIME]); +} + +static void test_config_parse_pass_environ(void) { + /* int config_parse_pass_environ( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ + int r; + _cleanup_strv_free_ char **passenv = NULL; + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "A B", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_length(passenv) == 2); + assert_se(streq(passenv[0], "A")); + assert_se(streq(passenv[1], "B")); + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_isempty(passenv)); + + r = config_parse_pass_environ(NULL, "fake", 1, "section", 1, + "PassEnvironment", 0, "'invalid name' 'normal_name' A=1 \\", + &passenv, NULL); + assert_se(r >= 0); + assert_se(strv_length(passenv) == 1); + assert_se(streq(passenv[0], "normal_name")); + } int main(int argc, char *argv[]) { @@ -634,6 +778,9 @@ int main(int argc, char *argv[]) { r = test_unit_file_get_set(); test_config_parse_exec(); + test_config_parse_bounding_set(); + test_config_parse_rlimit(); + test_config_parse_pass_environ(); test_load_env_file_1(); test_load_env_file_2(); test_load_env_file_3(); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index e5405fb7f3..842ca40102 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -21,21 +21,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <pwd.h> +#include "alloc-util.h" +#include "hostname-util.h" +#include "macro.h" #include "manager.h" -#include "unit.h" +#include "path-util.h" +#include "specifier.h" +#include "string-util.h" +#include "test-helper.h" #include "unit-name.h" #include "unit-printf.h" -#include "specifier.h" +#include "unit.h" +#include "user-util.h" #include "util.h" -#include "macro.h" -#include "path-util.h" -#include "test-helper.h" -#include "hostname-util.h" static void test_unit_name_is_valid(void) { assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY)); @@ -191,15 +194,15 @@ static int test_unit_printf(void) { Unit *u, *u2; int r; - _cleanup_free_ char *mid, *bid, *host, *root_uid; - struct passwd *root; + _cleanup_free_ char *mid = NULL, *bid = NULL, *host = NULL, *uid = NULL, *user = NULL, *shell = NULL, *home = NULL; assert_se(specifier_machine_id('m', NULL, NULL, &mid) >= 0 && mid); assert_se(specifier_boot_id('b', NULL, NULL, &bid) >= 0 && bid); - assert_se((host = gethostname_malloc())); - - assert_se((root = getpwnam("root"))); - assert_se(asprintf(&root_uid, "%d", (int) root->pw_uid) > 0); + assert_se(host = gethostname_malloc()); + assert_se(user = getusername_malloc()); + assert_se(asprintf(&uid, UID_FMT, getuid())); + assert_se(get_home_dir(&home) >= 0); + assert_se(get_shell(&shell) >= 0); r = manager_new(MANAGER_USER, true, &m); if (r == -EPERM || r == -EACCES || r == -EADDRINUSE) { @@ -220,8 +223,6 @@ static int test_unit_printf(void) { assert_se(streq(t, expected)); \ } - assert_se(setenv("USER", "root", 1) == 0); - assert_se(setenv("HOME", "/root", 1) == 0); assert_se(setenv("XDG_RUNTIME_DIR", "/run/user/1/", 1) == 0); assert_se(u = unit_new(m, sizeof(Service))); @@ -240,9 +241,9 @@ static int test_unit_printf(void) { expect(u, "%p", "blah"); expect(u, "%P", "blah"); expect(u, "%i", ""); - expect(u, "%u", root->pw_name); - expect(u, "%U", root_uid); - expect(u, "%h", root->pw_dir); + expect(u, "%u", user); + expect(u, "%U", uid); + expect(u, "%h", home); expect(u, "%m", mid); expect(u, "%b", bid); expect(u, "%H", host); @@ -260,9 +261,9 @@ static int test_unit_printf(void) { expect(u2, "%P", "blah"); expect(u2, "%i", "foo-foo"); expect(u2, "%I", "foo/foo"); - expect(u2, "%u", root->pw_name); - expect(u2, "%U", root_uid); - expect(u2, "%h", root->pw_dir); + expect(u2, "%u", user); + expect(u2, "%U", uid); + expect(u2, "%h", home); expect(u2, "%m", mid); expect(u2, "%b", bid); expect(u2, "%H", host); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c new file mode 100644 index 0000000000..09d37087e5 --- /dev/null +++ b/src/test/test-user-util.c @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "macro.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" + +static void test_uid_to_name_one(uid_t uid, const char *name) { + _cleanup_free_ char *t = NULL; + + assert_se(t = uid_to_name(uid)); + assert_se(streq_ptr(t, name)); +} + +static void test_gid_to_name_one(gid_t gid, const char *name) { + _cleanup_free_ char *t = NULL; + + assert_se(t = gid_to_name(gid)); + assert_se(streq_ptr(t, name)); +} + +int main(int argc, char*argv[]) { + + test_uid_to_name_one(0, "root"); + test_uid_to_name_one(0xFFFF, "65535"); + test_uid_to_name_one(0xFFFFFFFF, "4294967295"); + + test_gid_to_name_one(0, "root"); + test_gid_to_name_one(TTY_GID, "tty"); + test_gid_to_name_one(0xFFFF, "65535"); + test_gid_to_name_one(0xFFFFFFFF, "4294967295"); + + return 0; +} diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index 346f8524c6..0af8349732 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "utf8.h" #include "util.h" +#include "string-util.h" static void test_utf8_is_printable(void) { assert_se(utf8_is_printable("ascii is valid\tunicode", 22)); diff --git a/src/test/test-util.c b/src/test/test-util.c index 503e840803..f6ed55878c 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -22,8 +22,6 @@ #include <errno.h> #include <fcntl.h> -#include <locale.h> -#include <math.h> #include <signal.h> #include <string.h> #include <sys/types.h> @@ -31,17 +29,34 @@ #include <sys/xattr.h> #include <unistd.h> +#include "alloc-util.h" #include "conf-parser.h" #include "cpu-set-util.h" #include "def.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "fstab-util.h" +#include "glob-util.h" +#include "hexdecoct.h" +#include "io-util.h" #include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "process-util.h" #include "rm-rf.h" #include "signal-util.h" +#include "special.h" +#include "stat-util.h" +#include "string-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" #include "virt.h" +#include "web-util.h" +#include "xattr-util.h" static void test_streq_ptr(void) { assert_se(streq_ptr(NULL, NULL)); @@ -221,63 +236,6 @@ static void test_close_many(void) { unlink(name2); } -static void test_parse_boolean(void) { - assert_se(parse_boolean("1") == 1); - assert_se(parse_boolean("y") == 1); - assert_se(parse_boolean("Y") == 1); - assert_se(parse_boolean("yes") == 1); - assert_se(parse_boolean("YES") == 1); - assert_se(parse_boolean("true") == 1); - assert_se(parse_boolean("TRUE") == 1); - assert_se(parse_boolean("on") == 1); - assert_se(parse_boolean("ON") == 1); - - assert_se(parse_boolean("0") == 0); - assert_se(parse_boolean("n") == 0); - assert_se(parse_boolean("N") == 0); - assert_se(parse_boolean("no") == 0); - assert_se(parse_boolean("NO") == 0); - assert_se(parse_boolean("false") == 0); - assert_se(parse_boolean("FALSE") == 0); - assert_se(parse_boolean("off") == 0); - assert_se(parse_boolean("OFF") == 0); - - assert_se(parse_boolean("garbage") < 0); - assert_se(parse_boolean("") < 0); - assert_se(parse_boolean("full") < 0); -} - -static void test_parse_pid(void) { - int r; - pid_t pid; - - r = parse_pid("100", &pid); - assert_se(r == 0); - assert_se(pid == 100); - - r = parse_pid("0x7FFFFFFF", &pid); - assert_se(r == 0); - assert_se(pid == 2147483647); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("0", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("-100", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - r = parse_pid("junk", &pid); - assert_se(r == -EINVAL); -} - static void test_parse_uid(void) { int r; uid_t uid; @@ -293,96 +251,6 @@ static void test_parse_uid(void) { assert_se(r == -EINVAL); } -static void test_safe_atou16(void) { - int r; - uint16_t l; - - r = safe_atou16("12345", &l); - assert_se(r == 0); - assert_se(l == 12345); - - r = safe_atou16("123456", &l); - assert_se(r == -ERANGE); - - r = safe_atou16("junk", &l); - assert_se(r == -EINVAL); -} - -static void test_safe_atoi16(void) { - int r; - int16_t l; - - r = safe_atoi16("-12345", &l); - assert_se(r == 0); - assert_se(l == -12345); - - r = safe_atoi16("36536", &l); - assert_se(r == -ERANGE); - - r = safe_atoi16("junk", &l); - assert_se(r == -EINVAL); -} - -static void test_safe_atolli(void) { - int r; - long long l; - - r = safe_atolli("12345", &l); - assert_se(r == 0); - assert_se(l == 12345); - - r = safe_atolli("junk", &l); - assert_se(r == -EINVAL); -} - -static void test_safe_atod(void) { - int r; - double d; - char *e; - - r = safe_atod("junk", &d); - assert_se(r == -EINVAL); - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - strtod("0,5", &e); - assert_se(*e == ','); - - /* Check if this really is locale independent */ - if (setlocale(LC_NUMERIC, "de_DE.utf8")) { - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001); - } - - /* And check again, reset */ - assert_se(setlocale(LC_NUMERIC, "C")); - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - strtod("0,5", &e); - assert_se(*e == ','); -} - static void test_strappend(void) { _cleanup_free_ char *t1, *t2, *t3, *t4; @@ -895,74 +763,6 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_parse_size(void) { - uint64_t bytes; - - assert_se(parse_size("111", 1024, &bytes) == 0); - assert_se(bytes == 111); - - assert_se(parse_size("111.4", 1024, &bytes) == 0); - assert_se(bytes == 111); - - assert_se(parse_size(" 112 B", 1024, &bytes) == 0); - assert_se(bytes == 112); - - assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0); - assert_se(bytes == 112); - - assert_se(parse_size("3.5 K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024 + 512); - - assert_se(parse_size("3. K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024); - - assert_se(parse_size("3.0 K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024); - - assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL); - - assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0); - assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512); - - assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("3.5G3B", 1024, &bytes) == 0); - assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3); - - assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0); - assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4); - - assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("4T3G3B", 1024, &bytes) == 0); - assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); - - assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0); - assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); - - assert_se(parse_size("12P", 1024, &bytes) == 0); - assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024); - - assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("3E 2P", 1024, &bytes) == 0); - assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024); - - assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); - assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); - assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); - - assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE); - - assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); -} - static void test_parse_cpu_set(void) { cpu_set_t *c = NULL; int ncpus; @@ -996,19 +796,76 @@ static void test_parse_cpu_set(void) { /* Use commas as separators */ ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Commas with spaces (and trailing comma, space) */ + ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); /* Ranges */ ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges with trailing comma, space */ + ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Negative range (returns empty cpu_set) */ + ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); + c = mfree(c); + + /* Overlapping ranges */ + ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Mix ranges and individual CPUs */ + ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); + assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); /* Garbage */ ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus < 0); assert_se(!c); + /* Range with garbage */ + ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus < 0); + assert_se(!c); + /* Empty string */ c = NULL; ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); @@ -1554,507 +1411,6 @@ static void test_execute_directory(void) { (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL); } -static void test_extract_first_word(void) { - const char *p, *original; - char *t; - - p = original = "foobar waldo"; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 7); - - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, NULL, 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "\"foobar\"")); - free(t); - assert_se(p == original + 9); - - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "\'waldo\'")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, NULL, 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 9); - - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, NULL, 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\""; - assert_se(extract_first_word(&p, &t, NULL, 0) == 1); - assert_se(streq(t, "\"")); - free(t); - assert_se(isempty(p)); - - p = original = "\""; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'"; - assert_se(extract_first_word(&p, &t, NULL, 0) == 1); - assert_se(streq(t, "\'")); - free(t); - assert_se(isempty(p)); - - p = original = "\'"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, 0) == 1); - assert_se(streq(t, "\'fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "yay\'foo\'bar"; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "yay\'foo\'bar")); - free(t); - assert_se(isempty(p)); - - p = original = "yay\'foo\'bar"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "yayfoobar")); - free(t); - assert_se(isempty(p)); - - p = original = " foobar "; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); - assert_se(streq(t, "foo\ba\x6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "foobax6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); - assert_se(streq(t, "föo")); - free(t); - assert_se(p == original + 13); - - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0); - assert_se(streq(t, "pi\360\237\222\251le")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(isempty(p)); - - p = original = "foo::bar"; - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "foo")); - free(t); - assert_se(p == original + 5); - - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "bar")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, ":", 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "foo\\:bar::waldo"; - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "foo:bar")); - free(t); - assert_se(p == original + 10); - - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, ":", 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "foo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "foo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); - assert_se(p == original + 5); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\ bar")); - free(t); - assert_se(p == original + 10); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "\\w+@\\K[\\d.]+")); - free(t); - assert_se(isempty(p)); - - p = original = "\\w+\\b"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "\\w+\b")); - free(t); - assert_se(isempty(p)); - - p = original = "-N ''"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "-N")); - free(t); - assert_se(p == original + 3); - - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "")); - free(t); - assert_se(isempty(p)); - - p = original = ":foo\\:bar::waldo:"; - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(t); - assert_se(streq(t, "")); - free(t); - assert_se(p == original + 1); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(streq(t, "foo:bar")); - free(t); - assert_se(p == original + 10); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(t); - assert_se(streq(t, "")); - free(t); - assert_se(p == original + 11); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(streq(t, "waldo")); - free(t); - assert_se(p == original + 17); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(streq(t, "")); - free(t); - assert_se(p == NULL); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0); - assert_se(!t); - assert_se(!p); -} - -static void test_extract_first_word_and_warn(void) { - const char *p, *original; - char *t; - - p = original = "foobar waldo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 7); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 9); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\""; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'fooo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\'fooo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo\ba\x6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobax6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "föo")); - free(t); - assert_se(p == original + 13); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "pi\360\237\222\251le")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\ bar")); - free(t); - assert_se(p == original + 10); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "\\w+@\\K[\\d.]+")); - free(t); - assert_se(isempty(p)); - - p = original = "\\w+\\b"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "\\w+\b")); - free(t); - assert_se(isempty(p)); -} - -static void test_extract_many_words(void) { - const char *p, *original; - char *a, *b, *c; - - p = original = "foobar waldi piep"; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "foobar")); - assert_se(streq_ptr(b, "waldi")); - assert_se(streq_ptr(c, "piep")); - free(a); - free(b); - free(c); - - p = original = "'foobar' wa\"ld\"i "; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "'foobar'")); - assert_se(streq_ptr(b, "wa\"ld\"i")); - assert_se(streq_ptr(c, NULL)); - free(a); - free(b); - - p = original = "'foobar' wa\"ld\"i "; - assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "foobar")); - assert_se(streq_ptr(b, "waldi")); - assert_se(streq_ptr(c, NULL)); - free(a); - free(b); - - p = original = ""; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); - assert_se(isempty(p)); - assert_se(streq_ptr(a, NULL)); - assert_se(streq_ptr(b, NULL)); - assert_se(streq_ptr(c, NULL)); - - p = original = " "; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); - assert_se(isempty(p)); - assert_se(streq_ptr(a, NULL)); - assert_se(streq_ptr(b, NULL)); - assert_se(streq_ptr(c, NULL)); - - p = original = "foobar"; - assert_se(extract_many_words(&p, NULL, 0, NULL) == 0); - assert_se(p == original); - - p = original = "foobar waldi"; - assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); - assert_se(p == original+7); - assert_se(streq_ptr(a, "foobar")); - free(a); - - p = original = " foobar "; - assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "foobar")); - free(a); -} - static int parse_item(const char *key, const char *value) { assert_se(key); @@ -2203,20 +1559,6 @@ static void test_shell_maybe_quote(void) { test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); } -static void test_parse_mode(void) { - mode_t m; - - assert_se(parse_mode("-1", &m) < 0); - assert_se(parse_mode("", &m) < 0); - assert_se(parse_mode("888", &m) < 0); - assert_se(parse_mode("77777", &m) < 0); - - assert_se(parse_mode("544", &m) >= 0 && m == 0544); - assert_se(parse_mode("777", &m) >= 0 && m == 0777); - assert_se(parse_mode("7777", &m) >= 0 && m == 07777); - assert_se(parse_mode("0", &m) >= 0 && m == 0); -} - static void test_tempfn(void) { char *ret = NULL, *p; @@ -2297,6 +1639,12 @@ cleanup: assert_se(rmdir(t) >= 0); } +static void test_runlevel_to_target(void) { + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -2309,13 +1657,7 @@ int main(int argc, char *argv[]) { test_div_round_up(); test_first_word(); test_close_many(); - test_parse_boolean(); - test_parse_pid(); test_parse_uid(); - test_safe_atou16(); - test_safe_atoi16(); - test_safe_atolli(); - test_safe_atod(); test_strappend(); test_strstrip(); test_delete_chars(); @@ -2342,7 +1684,6 @@ int main(int argc, char *argv[]) { test_memdup_multiply(); test_u64log2(); test_protect_errno(); - test_parse_size(); test_parse_cpu_set(); test_config_parse_iec_uint64(); test_strextend(); @@ -2374,9 +1715,6 @@ int main(int argc, char *argv[]) { test_search_and_fopen_nulstr(); test_glob_exists(); test_execute_directory(); - test_extract_first_word(); - test_extract_first_word_and_warn(); - test_extract_many_words(); test_parse_proc_cmdline(); test_raw_clone(); test_same_fd(); @@ -2384,10 +1722,10 @@ int main(int argc, char *argv[]) { test_sparse_write(); test_shell_escape(); test_shell_maybe_quote(); - test_parse_mode(); test_tempfn(); test_strcmp_ptr(); test_fgetxattrat_fake(); + test_runlevel_to_target(); return 0; } diff --git a/src/test/test-xml.c b/src/test/test-xml.c index ea109fbde0..548d75a3c3 100644 --- a/src/test/test-xml.c +++ b/src/test/test-xml.c @@ -21,8 +21,10 @@ #include <stdarg.h> -#include "xml.h" +#include "alloc-util.h" +#include "string-util.h" #include "util.h" +#include "xml.h" static void test_one(const char *data, ...) { void *state = NULL; diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 68fbe3f5b8..564d72773a 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -30,6 +30,7 @@ #include "bus-error.h" #include "bus-util.h" #include "pager.h" +#include "parse-util.h" #include "spawn-polkit-agent.h" #include "strv.h" #include "terminal-util.h" diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 6de9e246f6..968ef8a788 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -23,21 +23,24 @@ #include <string.h> #include <unistd.h> -#include "sd-messages.h" -#include "sd-event.h" #include "sd-bus.h" +#include "sd-event.h" +#include "sd-messages.h" -#include "util.h" -#include "strv.h" -#include "def.h" -#include "clock-util.h" -#include "path-util.h" -#include "fileio-label.h" -#include "bus-util.h" -#include "bus-error.h" +#include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-error.h" +#include "bus-util.h" +#include "clock-util.h" +#include "def.h" #include "event-util.h" +#include "fileio-label.h" +#include "fs-util.h" +#include "path-util.h" #include "selinux-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index 28ad378a93..5881bc0c45 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -19,14 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - +#include "alloc-util.h" +#include "def.h" +#include "extract-word.h" +#include "string-util.h" +#include "timesyncd-conf.h" #include "timesyncd-manager.h" #include "timesyncd-server.h" -#include "timesyncd-conf.h" int manager_parse_server_string(Manager *m, ServerType type, const char *string) { - const char *word, *state; - size_t length; ServerName *first; int r; @@ -35,17 +36,20 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string) first = type == SERVER_FALLBACK ? m->fallback_servers : m->system_servers; - FOREACH_WORD_QUOTED(word, length, string, state) { - char buffer[length+1]; + for (;;) { + _cleanup_free_ char *word = NULL; bool found = false; ServerName *n; - memcpy(buffer, word, length); - buffer[length] = 0; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse timesyncd server syntax \"%s\": %m", string); + if (r == 0) + break; /* Filter out duplicates */ LIST_FOREACH(names, n, first) - if (streq_ptr(n->string, buffer)) { + if (streq_ptr(n->string, word)) { found = true; break; } @@ -53,7 +57,7 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string) if (found) continue; - r = server_name_new(m, NULL, type, buffer); + r = server_name_new(m, NULL, type, word); if (r < 0) return r; } @@ -96,8 +100,8 @@ int config_parse_servers( int manager_parse_config_file(Manager *m) { assert(m); - return config_parse_many("/etc/systemd/timesyncd.conf", - CONF_DIRS_NULSTR("systemd/timesyncd.conf"), + return config_parse_many(PKGSYSCONFDIR "/timesyncd.conf", + CONF_PATHS_NULSTR("systemd/timesyncd.conf.d"), "Time\0", config_item_perf_lookup, timesyncd_gperf_lookup, false, m); diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index 40e0fd31fe..8dca538b3b 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -19,31 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> -#include <time.h> #include <math.h> #include <netinet/in.h> #include <netinet/ip.h> +#include <resolv.h> +#include <stdlib.h> +#include <sys/socket.h> #include <sys/timerfd.h> #include <sys/timex.h> -#include <sys/socket.h> -#include <resolv.h> #include <sys/types.h> +#include <time.h> -#include "missing.h" -#include "util.h" -#include "sparse-endian.h" -#include "log.h" -#include "socket-util.h" +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "list.h" +#include "log.h" +#include "missing.h" +#include "network-util.h" #include "ratelimit.h" +#include "socket-util.h" +#include "sparse-endian.h" +#include "string-util.h" #include "strv.h" -#include "sd-daemon.h" -#include "network-util.h" +#include "time-util.h" #include "timesyncd-conf.h" #include "timesyncd-manager.h" -#include "time-util.h" +#include "util.h" #ifndef ADJ_SETOFFSET #define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */ @@ -365,7 +370,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) { r = clock_adjtime(CLOCK_REALTIME, &tmx); if (r < 0) - return r; + return -errno; touch("/var/lib/systemd/clock"); @@ -662,7 +667,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re m->sync = true; r = manager_adjust_clock(m, offset, leap_sec); if (r < 0) - log_error_errno(errno, "Failed to call clock_adjtime(): %m"); + log_error_errno(r, "Failed to call clock_adjtime(): %m"); } log_debug("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s", diff --git a/src/timesync/timesyncd-server.c b/src/timesync/timesyncd-server.c index ec3fe1fc4e..f98e6b4cf0 100644 --- a/src/timesync/timesyncd-server.c +++ b/src/timesync/timesyncd-server.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "timesyncd-server.h" int server_address_new( diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 3cb7d435cd..7f70eaaea0 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -19,15 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-event.h" #include "sd-daemon.h" -#include "capability.h" +#include "sd-event.h" + +#include "capability-util.h" #include "clock-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "network-util.h" #include "signal-util.h" - -#include "timesyncd-manager.h" #include "timesyncd-conf.h" +#include "timesyncd-manager.h" +#include "user-util.h" static int load_clock_timestamp(uid_t uid, gid_t gid) { _cleanup_close_ int fd = -1; @@ -57,12 +60,12 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) { /* Try to fix the access mode, so that we can still touch the file after dropping priviliges */ - fchmod(fd, 0644); - fchown(fd, uid, gid); + (void) fchmod(fd, 0644); + (void) fchown(fd, uid, gid); } else /* create stamp file with the compiled-in date */ - touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644); + (void) touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644); ct = now(CLOCK_REALTIME); if (ct < min) { @@ -150,7 +153,7 @@ int main(int argc, char *argv[]) { /* if we got an authoritative time, store it in the file system */ if (m->sync) - touch("/var/lib/systemd/clock"); + (void) touch("/var/lib/systemd/clock"); sd_event_get_exit_code(m->event, &r); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index d219764bc6..74b6b91593 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -39,22 +39,39 @@ #include <unistd.h> #include "acl-util.h" +#include "alloc-util.h" #include "btrfs-util.h" -#include "capability.h" +#include "capability-util.h" +#include "chattr-util.h" #include "conf-files.h" #include "copy.h" +#include "def.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "glob-util.h" +#include "io-util.h" #include "label.h" #include "log.h" #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" +#include "parse-util.h" #include "path-util.h" #include "rm-rf.h" #include "selinux-util.h" #include "set.h" #include "specifier.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" +#include "umask-util.h" +#include "user-util.h" #include "util.h" /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates @@ -69,6 +86,8 @@ typedef enum ItemType { CREATE_DIRECTORY = 'd', TRUNCATE_DIRECTORY = 'D', CREATE_SUBVOLUME = 'v', + CREATE_SUBVOLUME_INHERIT_QUOTA = 'q', + CREATE_SUBVOLUME_NEW_QUOTA = 'Q', CREATE_FIFO = 'p', CREATE_SYMLINK = 'L', CREATE_CHAR_DEVICE = 'c', @@ -140,7 +159,7 @@ static char **arg_include_prefixes = NULL; static char **arg_exclude_prefixes = NULL; static char *arg_root = NULL; -static const char conf_file_dirs[] = CONF_DIRS_NULSTR("tmpfiles"); +static const char conf_file_dirs[] = CONF_PATHS_NULSTR("tmpfiles.d"); #define MAX_DEPTH 256 @@ -180,6 +199,8 @@ static bool takes_ownership(ItemType t) { CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, + CREATE_SUBVOLUME_INHERIT_QUOTA, + CREATE_SUBVOLUME_NEW_QUOTA, CREATE_FIFO, CREATE_SYMLINK, CREATE_CHAR_DEVICE, @@ -1198,16 +1219,16 @@ static int create_item(Item *i) { case CREATE_DIRECTORY: case TRUNCATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: RUN_WITH_UMASK(0000) mkdir_parents_label(i->path, 0755); - if (i->type == CREATE_SUBVOLUME) - RUN_WITH_UMASK((~i->mode) & 0777) { + if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) { + RUN_WITH_UMASK((~i->mode) & 0777) r = btrfs_subvol_make(i->path); - log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path); - } - else + } else r = 0; if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) @@ -1236,6 +1257,28 @@ static int create_item(Item *i) { log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path); + if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) { + r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA); + if (r == -ENOTTY) { + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path); + return 0; + } + if (r == -EROFS) { + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path); + return 0; + } + if (r == -ENOPROTOOPT) { + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path); + if (r > 0) + log_debug("Adjusted quota for subvolume \"%s\".", i->path); + if (r == 0) + log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path); + } + r = path_set_perms(i, i->path); if (r < 0) return r; @@ -1492,6 +1535,8 @@ static int remove_item(Item *i) { case TRUNCATE_FILE: case CREATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: case CREATE_FIFO: case CREATE_SYMLINK: case CREATE_CHAR_DEVICE: @@ -1561,8 +1606,7 @@ static int clean_item_instance(Item *i, const char* instance) { if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) return log_error_errno(errno, "stat(%s/..) failed: %m", i->path); - mountpoint = s.st_dev != ps.st_dev || - (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino); + mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino; log_debug("Cleanup threshold for %s \"%s\" is %s", mountpoint ? "mount point" : "directory", @@ -1583,6 +1627,8 @@ static int clean_item(Item *i) { switch (i->type) { case CREATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: case TRUNCATE_DIRECTORY: case IGNORE_PATH: case COPY_FILES: @@ -1819,6 +1865,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { case CREATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: case TRUNCATE_DIRECTORY: case CREATE_FIFO: case IGNORE_PATH: @@ -1983,8 +2031,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { i.mode = m; i.mode_set = true; } else - i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY) - ? 0755 : 0644; + i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644; if (!isempty(age) && !streq(age, "-")) { const char *a = age; @@ -2075,7 +2122,7 @@ static int parse_argv(int argc, char *argv[]) { {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -2118,12 +2165,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - free(arg_root); - arg_root = path_make_absolute_cwd(optarg); - if (!arg_root) - return log_oom(); - - path_kill_slashes(arg_root); + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case '?': @@ -2186,7 +2230,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) { continue; ORDERED_HASHMAP_FOREACH(j, items, iter) { - if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME) + if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) continue; if (path_equal(j->path, i->path)) { diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 93cce186f0..8cfe10330d 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -32,14 +32,19 @@ #include <sys/un.h> #include <unistd.h> +#include "alloc-util.h" #include "ask-password-api.h" #include "conf-parser.h" #include "def.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "io-util.h" #include "mkdir.h" #include "path-util.h" #include "process-util.h" #include "signal-util.h" #include "socket-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "util.h" @@ -120,23 +125,30 @@ static int ask_password_plymouth( y = now(CLOCK_MONOTONIC); - if (y > until) - return -ETIME; + if (y > until) { + r = -ETIME; + goto finish; + } sleep_for = (int) ((until - y) / USEC_PER_MSEC); } - if (flag_file && access(flag_file, F_OK) < 0) - return -errno; + if (flag_file && access(flag_file, F_OK) < 0) { + r = -errno; + goto finish; + } j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); if (j < 0) { if (errno == EINTR) continue; - return -errno; - } else if (j == 0) - return -ETIME; + r = -errno; + goto finish; + } else if (j == 0) { + r = -ETIME; + goto finish; + } if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) flush_fd(notify); @@ -149,9 +161,12 @@ static int ask_password_plymouth( if (errno == EINTR || errno == EAGAIN) continue; - return -errno; - } else if (k == 0) - return -EIO; + r = -errno; + goto finish; + } else if (k == 0) { + r = -EIO; + goto finish; + } p += k; @@ -166,12 +181,14 @@ static int ask_password_plymouth( * with a normal password request */ packet = mfree(packet); - if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) - return -ENOMEM; + if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) { + r = -ENOMEM; + goto finish; + } r = loop_write(fd, packet, n+1, true); if (r < 0) - return r; + goto finish; flags &= ~ASK_PASSWORD_ACCEPT_CACHED; p = 0; @@ -179,7 +196,8 @@ static int ask_password_plymouth( } /* No password, because UI not shown */ - return -ENOENT; + r = -ENOENT; + goto finish; } else if (buffer[0] == 2 || buffer[0] == 9) { uint32_t size; @@ -191,32 +209,43 @@ static int ask_password_plymouth( memcpy(&size, buffer+1, sizeof(size)); size = le32toh(size); - if (size + 5 > sizeof(buffer)) - return -EIO; + if (size + 5 > sizeof(buffer)) { + r = -EIO; + goto finish; + } if (p-5 < size) continue; l = strv_parse_nulstr(buffer + 5, size); - if (!l) - return -ENOMEM; + if (!l) { + r = -ENOMEM; + goto finish; + } *ret = l; break; - } else + } else { /* Unknown packet */ - return -EIO; + r = -EIO; + goto finish; + } } - return 0; + r = 0; + +finish: + memory_erase(buffer, sizeof(buffer)); + return r; } static int parse_password(const char *filename, char **wall) { _cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL; + bool accept_cached = false, echo = false; + size_t packet_length = 0; uint64_t not_after = 0; unsigned pid = 0; - bool accept_cached = false, echo = false; const ConfigTableItem items[] = { { "Ask", "Socket", config_parse_string, 0, &socket_name }, @@ -270,7 +299,6 @@ static int parse_password(const char *filename, char **wall) { } else { union sockaddr_union sa = {}; - size_t packet_length = 0; _cleanup_close_ int socket_fd = -1; assert(arg_action == ACTION_QUERY || @@ -284,7 +312,7 @@ static int parse_password(const char *filename, char **wall) { } if (arg_plymouth) { - _cleanup_strv_free_ char **passwords = NULL; + _cleanup_strv_free_erase_ char **passwords = NULL; r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords); if (r >= 0) { @@ -308,7 +336,7 @@ static int parse_password(const char *filename, char **wall) { } } else { - _cleanup_free_ char *password = NULL; + _cleanup_string_free_erase_ char *password = NULL; int tty_fd = -1; if (arg_console) { @@ -340,26 +368,36 @@ static int parse_password(const char *filename, char **wall) { } } - if (IN_SET(r, -ETIME, -ENOENT)) + if (IN_SET(r, -ETIME, -ENOENT)) { /* If the query went away, that's OK */ - return 0; - - if (r < 0) - return log_error_errno(r, "Failed to query password: %m"); + r = 0; + goto finish; + } + if (r < 0) { + log_error_errno(r, "Failed to query password: %m"); + goto finish; + } socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (socket_fd < 0) - return log_error_errno(errno, "socket(): %m"); + if (socket_fd < 0) { + r = log_error_errno(errno, "socket(): %m"); + goto finish; + } sa.un.sun_family = AF_UNIX; strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)); + memory_erase(packet, packet_length); if (r < 0) return log_error_errno(errno, "Failed to send: %m"); } return 0; + +finish: + memory_erase(packet, packet_length); + return r; } static int wall_tty_block(void) { @@ -381,7 +419,7 @@ static int wall_tty_block(void) { fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); if (fd < 0) - return log_error_errno(errno, "Failed to open %s: %m", p); + return log_debug_errno(errno, "Failed to open %s: %m", p); return fd; } @@ -437,7 +475,7 @@ static int show_passwords(void) { if (errno == ENOENT) return 0; - return log_error_errno(errno, "Failed top open /run/systemd/ask-password: %m"); + return log_error_errno(errno, "Failed to open /run/systemd/ask-password: %m"); } FOREACH_DIRENT_ALL(de, d, return log_error_errno(errno, "Failed to read directory: %m")) { diff --git a/src/udev/.gitignore b/src/udev/.gitignore index ba112ce218..f5d8be3dc1 100644 --- a/src/udev/.gitignore +++ b/src/udev/.gitignore @@ -1,5 +1,4 @@ /udev.pc /keyboard-keys-from-name.gperf /keyboard-keys-from-name.h -/keyboard-keys-to-name.h /keyboard-keys-list.txt diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c index 1d1798dd10..1e414664ce 100644 --- a/src/udev/ata_id/ata_id.c +++ b/src/udev/ata_id/ata_id.c @@ -19,28 +19,30 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> #include <ctype.h> -#include <string.h> #include <errno.h> +#include <fcntl.h> #include <getopt.h> +#include <linux/bsg.h> +#include <linux/hdreg.h> #include <scsi/scsi.h> -#include <scsi/sg.h> #include <scsi/scsi_ioctl.h> +#include <scsi/sg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> -#include <sys/types.h> #include <sys/stat.h> -#include <linux/hdreg.h> -#include <linux/bsg.h> +#include <sys/types.h> +#include <unistd.h> #include "libudev.h" + +#include "fd-util.h" #include "libudev-private.h" -#include "udev-util.h" #include "log.h" +#include "udev-util.h" #define COMMAND_TIMEOUT_MSEC (30 * 1000) diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c index 001bae7a24..72f284f710 100644 --- a/src/udev/cdrom_id/cdrom_id.c +++ b/src/udev/cdrom_id/cdrom_id.c @@ -17,24 +17,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <limits.h> -#include <fcntl.h> #include <errno.h> +#include <fcntl.h> #include <getopt.h> -#include <time.h> +#include <limits.h> +#include <linux/cdrom.h> #include <scsi/sg.h> -#include <sys/types.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> #include <sys/stat.h> #include <sys/time.h> -#include <sys/ioctl.h> -#include <linux/cdrom.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> #include "libudev.h" + #include "libudev-private.h" #include "random-util.h" diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c index b3a1f0bca1..b6c95cd452 100644 --- a/src/udev/collect/collect.c +++ b/src/udev/collect/collect.c @@ -19,13 +19,15 @@ * */ -#include <stdio.h> -#include <stddef.h> #include <errno.h> #include <getopt.h> +#include <stddef.h> +#include <stdio.h> +#include "alloc-util.h" #include "libudev-private.h" #include "macro.h" +#include "string-util.h" #define BUFSIZE 16 #define UDEV_ALARM_TIMEOUT 180 diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c index a4b05d1bec..0647008d90 100644 --- a/src/udev/net/ethtool-util.c +++ b/src/udev/net/ethtool-util.c @@ -19,17 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/ioctl.h> #include <net/if.h> +#include <sys/ioctl.h> #include <linux/ethtool.h> #include <linux/sockios.h> +#include "conf-parser.h" #include "ethtool-util.h" - +#include "log.h" +#include "string-table.h" #include "strxcpyx.h" #include "util.h" -#include "log.h" -#include "conf-parser.h" static const char* const duplex_table[_DUP_MAX] = { [DUP_FULL] = "full", diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 4b8c5053a4..776674e994 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -22,22 +22,28 @@ #include <netinet/ether.h> #include <linux/netdevice.h> +#include "sd-netlink.h" -#include "missing.h" -#include "link-config.h" +#include "alloc-util.h" +#include "conf-files.h" +#include "conf-parser.h" #include "ethtool-util.h" - +#include "fd-util.h" #include "libudev-private.h" -#include "sd-netlink.h" -#include "util.h" +#include "link-config.h" #include "log.h" -#include "strv.h" -#include "path-util.h" -#include "conf-parser.h" -#include "conf-files.h" +#include "missing.h" #include "netlink-util.h" #include "network-internal.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "random-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" struct link_config_ctx { LIST_HEAD(link_config, links); diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index c52db2ce55..4fcbee8b92 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -21,10 +21,11 @@ #pragma once -#include "ethtool-util.h" +#include "libudev.h" + #include "condition.h" +#include "ethtool-util.h" #include "list.h" -#include "libudev.h" typedef struct link_config_ctx link_config_ctx; typedef struct link_config link_config; diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c index adb91869df..4655691642 100644 --- a/src/udev/scsi_id/scsi_id.c +++ b/src/udev/scsi_id/scsi_id.c @@ -16,22 +16,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <signal.h> #include <stdarg.h> #include <stdbool.h> -#include <unistd.h> -#include <signal.h> -#include <fcntl.h> -#include <errno.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <ctype.h> -#include <getopt.h> #include <sys/stat.h> +#include <unistd.h> #include "libudev.h" + +#include "fd-util.h" #include "libudev-private.h" #include "scsi_id.h" +#include "string-util.h" #include "udev-util.h" static const struct option options[] = { diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c index de3b4f7581..c7ef783684 100644 --- a/src/udev/scsi_id/scsi_serial.c +++ b/src/udev/scsi_id/scsi_serial.c @@ -17,27 +17,29 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <stdio.h> #include <errno.h> -#include <string.h> #include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> #include <inttypes.h> +#include <linux/bsg.h> +#include <linux/types.h> #include <scsi/scsi.h> #include <scsi/sg.h> -#include <linux/types.h> -#include <linux/bsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> #include "libudev.h" + #include "libudev-private.h" +#include "random-util.h" #include "scsi.h" #include "scsi_id.h" -#include "random-util.h" +#include "string-util.h" /* * A priority based list of id, naa, and binary/ascii for the identifier diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index b8066ea6e9..d0e47ec6d8 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -18,18 +18,22 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <blkid/blkid.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> -#include <blkid/blkid.h> #include "sd-id128.h" -#include "gpt.h" + +#include "alloc-util.h" #include "efivars.h" +#include "fd-util.h" +#include "gpt.h" +#include "string-util.h" #include "udev.h" static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) { diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 3352821567..cfaa463804 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -17,15 +17,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <fcntl.h> +#include <stdlib.h> #include <sys/ioctl.h> #ifdef HAVE_LINUX_BTRFS_H #include <linux/btrfs.h> #endif +#include "fd-util.h" #include "missing.h" +#include "string-util.h" #include "udev.h" static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test) { diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c index 72109d93d2..f4a065a97d 100644 --- a/src/udev/udev-builtin-hwdb.c +++ b/src/udev/udev-builtin-hwdb.c @@ -17,16 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> #include <fnmatch.h> #include <getopt.h> +#include <stdio.h> +#include <stdlib.h> -#include "udev.h" #include "sd-hwdb.h" +#include "alloc-util.h" #include "hwdb-util.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" static sd_hwdb *hwdb; diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index e3fa4bc162..fddafbd4dc 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -21,15 +21,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> #include <string.h> -#include <errno.h> +#include <unistd.h> #include <linux/limits.h> #include <linux/input.h> +#include "fd-util.h" +#include "string-util.h" #include "udev.h" #include "util.h" diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index d63a8e2760..aa10beafb0 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -18,11 +18,15 @@ ***/ #include <stdio.h> -#include <string.h> #include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <linux/input.h> +#include "fd-util.h" +#include "parse-util.h" +#include "stdio-util.h" +#include "string-util.h" #include "udev.h" static const struct key *keyboard_lookup_key(const char *str, unsigned len); diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c index 81e78a8aa3..9665f678fd 100644 --- a/src/udev/udev-builtin-kmod.c +++ b/src/udev/udev-builtin-kmod.c @@ -18,12 +18,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> #include <errno.h> #include <libkmod.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include "string-util.h" #include "udev.h" static struct kmod_ctx *ctx = NULL; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 589f1f7822..bf5c9c6b77 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -27,7 +27,7 @@ * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames * * Two character prefixes based on the type of interface: - * en -- ethernet + * en -- Ethernet * sl -- serial line IP (slip) * wl -- wlan * ww -- wwan @@ -53,17 +53,17 @@ * exported. * The usual USB configuration == 1 and interface == 0 values are suppressed. * - * PCI ethernet card with firmware index "1": + * PCI Ethernet card with firmware index "1": * ID_NET_NAME_ONBOARD=eno1 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1 * - * PCI ethernet card in hotplug slot with firmware index number: + * PCI Ethernet card in hotplug slot with firmware index number: * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1 * ID_NET_NAME_MAC=enx000000000466 * ID_NET_NAME_PATH=enp5s0 * ID_NET_NAME_SLOT=ens1 * - * PCI ethernet multi-function card with 2 ports: + * PCI Ethernet multi-function card with 2 ports: * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0 * ID_NET_NAME_MAC=enx78e7d1ea46da * ID_NET_NAME_PATH=enp2s0f0 @@ -87,19 +87,21 @@ * ID_NET_NAME_PATH=enp0s29u1u2 */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> #include <errno.h> +#include <fcntl.h> #include <net/if.h> #include <net/if_arp.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #include <linux/pci_regs.h> -#include "udev.h" +#include "fd-util.h" #include "fileio.h" +#include "string-util.h" +#include "udev.h" enum netname_type{ NET_UNDEF, diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index d4589470fb..f72894b5c5 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "link-config.h" -#include "udev.h" #include "log.h" +#include "udev.h" static link_config_ctx *ctx = NULL; diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 01e2c659ae..aa18c7e420 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -19,17 +19,19 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> -#include <string.h> #include <ctype.h> -#include <fcntl.h> -#include <errno.h> #include <dirent.h> +#include <errno.h> +#include <fcntl.h> #include <getopt.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "alloc-util.h" +#include "string-util.h" #include "udev.h" _printf_(2,3) @@ -591,31 +593,23 @@ static struct udev_device *handle_bcma(struct udev_device *parent, char **path) return parent; } -static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) { - struct udev_device *scsi_dev; +/* Handle devices of AP bus in System z platform. */ +static struct udev_device *handle_ap(struct udev_device *parent, char **path) { + const char *type, *func; assert(parent); - assert(dev); assert(path); - scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device"); - if (scsi_dev != NULL) { - const char *wwpn; - const char *lun; - const char *hba_id; - - hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id"); - wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn"); - lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun"); - if (hba_id != NULL && lun != NULL && wwpn != NULL) { - path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun); - goto out; - } - } + type = udev_device_get_sysattr_value(parent, "type"); + func = udev_device_get_sysattr_value(parent, "ap_functions"); - path_prepend(path, "ccw-%s", udev_device_get_sysname(parent)); + if (type != NULL && func != NULL) { + path_prepend(path, "ap-%s-%s", type, func); + goto out; + } + path_prepend(path, "ap-%s", udev_device_get_sysname(parent)); out: - parent = skip_subsystem(parent, "ccw"); + parent = skip_subsystem(parent, "ap"); return parent; } @@ -627,13 +621,6 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool assert(dev); - /* S390 ccw bus */ - parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL); - if (parent != NULL) { - handle_ccw(parent, dev, &path); - goto out; - } - /* walk up the chain of devices and compose path */ parent = dev; while (parent != NULL) { @@ -681,6 +668,25 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool parent = skip_subsystem(parent, "scm"); supported_transport = true; supported_parent = true; + } else if (streq(subsys, "ccw")) { + path_prepend(&path, "ccw-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "ccw"); + supported_transport = true; + supported_parent = true; + } else if (streq(subsys, "ccwgroup")) { + path_prepend(&path, "ccwgroup-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "ccwgroup"); + supported_transport = true; + supported_parent = true; + } else if (streq(subsys, "ap")) { + parent = handle_ap(parent, &path); + supported_transport = true; + supported_parent = true; + } else if (streq(subsys, "iucv")) { + path_prepend(&path, "iucv-%s", udev_device_get_sysname(parent)); + parent = skip_subsystem(parent, "iucv"); + supported_transport = true; + supported_parent = true; } if (parent) @@ -703,7 +709,6 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool if (streq(udev_device_get_subsystem(dev), "block") && !supported_transport) path = mfree(path); -out: if (path != NULL) { char tag[UTIL_NAME_SIZE]; size_t i; diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index 7bf4e7f24d..bbda9de08c 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -22,7 +22,9 @@ #include <stdlib.h> #include <errno.h> -#include "systemd/sd-login.h" +#include "sd-login.h" + +#include "login-util.h" #include "logind-acl.h" #include "udev.h" #include "util.h" @@ -56,7 +58,7 @@ static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool r = devnode_acl(path, true, false, 0, true, uid); if (r < 0) { - log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path); + log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path); goto finish; } diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c index d309dc31cb..587649eff0 100644 --- a/src/udev/udev-builtin-usb_id.c +++ b/src/udev/udev-builtin-usb_id.c @@ -20,15 +20,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> #include <string.h> -#include <ctype.h> -#include <fcntl.h> -#include <errno.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "string-util.h" #include "udev.h" static void set_usb_iftype(char *to, int if_class_num, size_t len) { diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index 4f625251d6..e6b36f124f 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -17,10 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <getopt.h> #include <stdio.h> #include <string.h> -#include <getopt.h> +#include "string-util.h" #include "udev.h" static bool initialized; diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 56277f551f..1e05be51a5 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -18,8 +18,10 @@ #include <sys/socket.h> #include <sys/un.h> -#include "socket-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "socket-util.h" #include "udev.h" /* wire protocol magic must match */ diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 1e34cbc2f5..5d6542d3ad 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -15,26 +15,29 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> #include <ctype.h> -#include <string.h> +#include <errno.h> +#include <fcntl.h> #include <net/if.h> -#include <sys/prctl.h> #include <poll.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/epoll.h> -#include <sys/wait.h> +#include <sys/prctl.h> #include <sys/signalfd.h> +#include <sys/wait.h> +#include <unistd.h> -#include "netlink-util.h" +#include "alloc-util.h" #include "event-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "netlink-util.h" #include "process-util.h" #include "signal-util.h" +#include "string-util.h" #include "udev.h" typedef struct Spawn { @@ -438,9 +441,7 @@ static int spawn_exec(struct udev_event *event, execve(argv[0], argv, envp); /* exec failed */ - log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd); - - return -errno; + return log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd); } static void spawn_read(struct udev_event *event, diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index e730fb45f1..c2edf2c5cd 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -15,20 +15,22 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <string.h> -#include <stdio.h> -#include <stddef.h> -#include <stdbool.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> #include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> #include <sys/stat.h> +#include <unistd.h> -#include "udev.h" -#include "smack-util.h" -#include "selinux-util.h" #include "formats-util.h" +#include "fs-util.h" +#include "selinux-util.h" +#include "smack-util.h" +#include "string-util.h" +#include "udev.h" static int node_symlink(struct udev_device *dev, const char *node, const char *slink) { struct stat stats; @@ -261,8 +263,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, mode |= S_IFCHR; if (lstat(devnode, &stats) != 0) { - err = -errno; - log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode); + err = log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode); goto out; } diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 10bf3880b0..c06ace09cf 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -15,27 +15,34 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stddef.h> -#include <limits.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include <stdio.h> -#include <fcntl.h> #include <ctype.h> -#include <unistd.h> -#include <errno.h> #include <dirent.h> +#include <errno.h> +#include <fcntl.h> #include <fnmatch.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <time.h> +#include <unistd.h> -#include "udev.h" -#include "path-util.h" +#include "alloc-util.h" #include "conf-files.h" +#include "escape.h" +#include "fd-util.h" +#include "glob-util.h" +#include "path-util.h" +#include "stat-util.h" #include "strbuf.h" +#include "string-util.h" #include "strv.h" -#include "util.h" #include "sysctl-util.h" +#include "udev.h" +#include "user-util.h" +#include "util.h" #define PREALLOC_TOKEN 2048 @@ -51,7 +58,8 @@ static const char* const rules_dirs[] = { "/etc/udev/rules.d", "/run/udev/rules.d", UDEVLIBEXECDIR "/rules.d", - NULL}; + NULL +}; struct udev_rules { struct udev *udev; diff --git a/src/udev/udev.h b/src/udev/udev.h index d17fc8c1ea..1f9c8120c0 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -18,16 +18,17 @@ #pragma once -#include <sys/types.h> #include <sys/param.h> +#include <sys/types.h> -#include "macro.h" -#include "sd-netlink.h" #include "libudev.h" -#include "libudev-private.h" -#include "util.h" +#include "sd-netlink.h" + #include "label.h" +#include "libudev-private.h" +#include "macro.h" #include "strv.h" +#include "util.h" struct udev_event { struct udev *udev; diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 00609e31b5..031a099d77 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -17,18 +17,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <ctype.h> #include <getopt.h> +#include <stdlib.h> #include <string.h> -#include <ctype.h> -#include "util.h" -#include "strbuf.h" +#include "alloc-util.h" #include "conf-files.h" - -#include "udev.h" +#include "fileio.h" +#include "fs-util.h" #include "hwdb-internal.h" #include "hwdb-util.h" +#include "strbuf.h" +#include "string-util.h" +#include "udev.h" +#include "util.h" /* * Generic udev properties, key/value database based on modalias strings. diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index b3d5565c48..7182668f23 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -15,19 +15,21 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <string.h> -#include <stdio.h> -#include <stddef.h> #include <ctype.h> -#include <unistd.h> #include <dirent.h> #include <errno.h> -#include <getopt.h> #include <fcntl.h> +#include <getopt.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> #include <sys/stat.h> +#include <unistd.h> -#include "udev.h" +#include "fd-util.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" #include "udevadm-util.h" static bool skip_attribute(const char *name) { diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index 5e93955186..30aa53feb2 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -25,9 +25,10 @@ #include <sys/time.h> #include <sys/epoll.h> -#include "udev.h" -#include "udev-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "udev-util.h" +#include "udev.h" static bool udev_exit; diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 3d6ca7a985..c25071b0fe 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -26,6 +26,7 @@ #include <getopt.h> #include <poll.h> +#include "parse-util.h" #include "udev.h" #include "util.h" diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index 35a7349439..0b180d03eb 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -15,12 +15,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stddef.h> -#include <stdio.h> #include <errno.h> #include <getopt.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include "string-util.h" #include "udev.h" static void help(struct udev *udev) { diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index d04e618d0d..ff427cf292 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -16,17 +16,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> #include <errno.h> -#include <signal.h> #include <getopt.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> #include <sys/signalfd.h> +#include <unistd.h> -#include "udev.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" static void help(void) { diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 7af9665f8a..9d52345d92 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -15,16 +15,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> #include <stddef.h> -#include <string.h> #include <stdio.h> +#include <string.h> #include <unistd.h> -#include <getopt.h> -#include <errno.h> -#include <fcntl.h> -#include "udev.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" #include "udevadm-util.h" #include "util.h" diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index 3f0e45e26c..3539c1d6ab 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -15,6 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "string-util.h" #include "udevadm-util.h" struct udev_device *find_device(struct udev *udev, diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index b86d8921f3..60f122ebda 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -16,12 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stddef.h> #include <errno.h> #include <getopt.h> +#include <stddef.h> +#include <stdio.h> #include "selinux-util.h" +#include "string-util.h" #include "udev.h" static int adm_version(struct udev *udev, int argc, char *argv[]) { diff --git a/src/udev/udevd.c b/src/udev/udevd.c index e4d2f47745..5364b92a57 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -43,20 +43,29 @@ #include "sd-daemon.h" #include "sd-event.h" +#include "alloc-util.h" #include "cgroup-util.h" #include "cpu-set-util.h" #include "dev-setup.h" #include "event-util.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" #include "hashmap.h" +#include "io-util.h" #include "netlink-util.h" +#include "parse-util.h" +#include "proc-cmdline.h" #include "process-util.h" #include "selinux-util.h" #include "signal-util.h" +#include "socket-util.h" +#include "string-util.h" #include "terminal-util.h" #include "udev-util.h" #include "udev.h" +#include "user-util.h" static bool arg_debug = false; static int arg_daemonize = false; @@ -1549,7 +1558,7 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg r = sd_event_default(&manager->event); if (r < 0) - return log_error_errno(errno, "could not allocate event loop: %m"); + return log_error_errno(r, "could not allocate event loop: %m"); r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager); if (r < 0) diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c index 5c57db44c1..607d78a019 100644 --- a/src/udev/v4l_id/v4l_id.c +++ b/src/udev/v4l_id/v4l_id.c @@ -26,6 +26,7 @@ #include <sys/ioctl.h> #include <linux/videodev2.h> +#include "fd-util.h" #include "util.h" int main(int argc, char *argv[]) { diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 01bbde8455..4c44d50613 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "fd-util.h" +#include "io-util.h" #include "selinux-util.h" +#include "util.h" #define MESSAGE \ "This file was created by systemd-update-done. Its only \n" \ diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index bcabf65a36..d50063cbcd 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -29,15 +29,16 @@ #include "sd-bus.h" +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" +#include "formats-util.h" #include "log.h" #include "macro.h" -#include "util.h" #include "special.h" -#include "utmp-wtmp.h" -#include "bus-util.h" -#include "bus-error.h" #include "unit-name.h" -#include "formats-util.h" +#include "util.h" +#include "utmp-wtmp.h" typedef struct Context { sd_bus *bus; diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 7c736c44d2..252cbdb26c 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -19,12 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> +#include <unistd.h> +#include "fileio.h" #include "log.h" +#include "string-util.h" #include "util.h" -#include "fileio.h" int main(int argc, char*argv[]) { diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 6353579283..a5f4529cfd 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -19,25 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> #include <errno.h> #include <fcntl.h> -#include <stdbool.h> #include <limits.h> -#include <sys/ioctl.h> -#include <linux/tiocl.h> #include <linux/kd.h> +#include <linux/tiocl.h> #include <linux/vt.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <unistd.h> -#include "util.h" -#include "log.h" -#include "virt.h" +#include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" +#include "locale-util.h" +#include "log.h" #include "process-util.h" -#include "terminal-util.h" #include "signal-util.h" +#include "string-util.h" +#include "terminal-util.h" +#include "util.h" +#include "virt.h" static bool is_vconsole(int fd) { unsigned char data[1]; @@ -270,7 +275,7 @@ int main(int argc, char **argv) { fd = open_terminal(vc, O_RDWR|O_CLOEXEC); if (fd < 0) { - log_error_errno(errno, "Failed to open %s: %m", vc); + log_error_errno(fd, "Failed to open %s: %m", vc); return EXIT_FAILURE; } diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh index d97fbe24d4..b6b474393d 100755 --- a/test/TEST-01-BASIC/test.sh +++ b/test/TEST-01-BASIC/test.sh @@ -53,7 +53,7 @@ Description=Testsuite service After=multi-user.target [Service] -ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;' +ExecStart=/bin/sh -x -c 'systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok' Type=oneshot EOF diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh index 4be2365e2f..2997da06ff 100755 --- a/test/TEST-02-CRYPTSETUP/test.sh +++ b/test/TEST-02-CRYPTSETUP/test.sh @@ -59,7 +59,7 @@ Description=Testsuite service After=multi-user.target [Service] -ExecStart=/bin/bash -c 'set -x; systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok; while : ;do systemd-cat echo "testsuite service waiting for /var/log/journal" ; echo "testsuite service waiting for journal to move to /var/log/journal" > /dev/console ; for i in /var/log/journal/*;do [ -d "\$i" ] && echo "\$i" && break 2; done; sleep 1; done; sleep 1; exit 0;' +ExecStart=/bin/sh -x -c 'systemctl --failed --no-legend --no-pager > /failed ; echo OK > /testok' Type=oneshot EOF diff --git a/test/TEST-03-JOBS/test-jobs.sh b/test/TEST-03-JOBS/test-jobs.sh index 6f32c240cd..42d475fe2f 100755 --- a/test/TEST-03-JOBS/test-jobs.sh +++ b/test/TEST-03-JOBS/test-jobs.sh @@ -23,7 +23,7 @@ grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1 grep 'hello\.service' /root/list-jobs.txt && exit 1 systemctl stop sleep.service hello-after-sleep.target || exit 1 -# Test for a crash when enqueueing a JOB_NOP when other job already exists +# Test for a crash when enqueuing a JOB_NOP when other job already exists systemctl start --no-block hello-after-sleep.target || exit 1 # hello.service should still be waiting, so these try-restarts will collapse # into NOPs. diff --git a/test/end.service b/test/end.service new file mode 100644 index 0000000000..6e1996fd02 --- /dev/null +++ b/test/end.service @@ -0,0 +1,10 @@ +[Unit] +Description=End the test +After=testsuite.service +OnFailure=poweroff.target +OnFailureJobMode=replace-irreversibly + +[Service] +Type=oneshot +ExecStart=/bin/sh -x -c 'systemctl poweroff --no-block' +TimeoutStartSec=5m diff --git a/test/end.service.in b/test/end.service.in deleted file mode 100644 index 4857ffe02b..0000000000 --- a/test/end.service.in +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=End the test -After=testsuite.service - -[Service] -ExecStart=@SYSTEMCTL@ poweroff --no-block diff --git a/test/exec-environment-empty.service b/test/exec-environment-empty.service deleted file mode 100644 index 0219ca4fd7..0000000000 --- a/test/exec-environment-empty.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Test for Environment - -[Service] -ExecStart=/bin/sh -c 'exit $(test ! "$VAR1" = "word1 word2") && $(test ! "$VAR2" = word3) && $(test ! "$VAR3" = \'$word 5 6\')' -Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" -Environment= diff --git a/test/exec-environment.service b/test/exec-environment.service deleted file mode 100644 index 4586b4c4a9..0000000000 --- a/test/exec-environment.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for Environment - -[Service] -ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = \'$word 5 6\')' -Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" diff --git a/test/exec-group.service b/test/exec-group.service deleted file mode 100644 index 1aa04b5bd2..0000000000 --- a/test/exec-group.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for Group - -[Service] -ExecStart=/bin/sh -c 'exit $(test $(id -n -g) = nobody)' -Group=nobody diff --git a/test/exec-umask-0177.service b/test/exec-umask-0177.service deleted file mode 100644 index af9295888e..0000000000 --- a/test/exec-umask-0177.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=Test for UMask - -[Service] -ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "600")' -UMask=0177 -PrivateTmp=yes diff --git a/test/exec-umask-default.service b/test/exec-umask-default.service deleted file mode 100644 index 41e20a60a1..0000000000 --- a/test/exec-umask-default.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for UMask default - -[Service] -ExecStart=/bin/sh -c 'touch /tmp/test-exec-umask; s=$(stat -c %a /tmp/test-exec-umask); echo $s; exit $(test $s = "644")' -PrivateTmp=yes diff --git a/test/exec-user.service b/test/exec-user.service deleted file mode 100644 index 2ca08ebb42..0000000000 --- a/test/exec-user.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Test for User - -[Service] -ExecStart=/bin/sh -c 'exit $(test "$USER" = nobody)' -User=nobody diff --git a/test/paths.target b/test/paths.target deleted file mode 120000 index e9939c9801..0000000000 --- a/test/paths.target +++ /dev/null @@ -1 +0,0 @@ -../units/paths.target
\ No newline at end of file diff --git a/test/test-execute/exec-capabilityboundingset-invert.service b/test/test-execute/exec-capabilityboundingset-invert.service new file mode 100644 index 0000000000..fd5d248702 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-invert.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "^Bounding set .*cap_chown"); test -z "$$c"' +Type=oneshot +CapabilityBoundingSet=~CAP_CHOWN diff --git a/test/test-execute/exec-capabilityboundingset-merge.service b/test/test-execute/exec-capabilityboundingset-merge.service new file mode 100644 index 0000000000..5c7fcaf437 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-merge.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_chown,cap_fowner,cap_kill"' +Type=oneshot +CapabilityBoundingSet=CAP_FOWNER +CapabilityBoundingSet=CAP_KILL CAP_CHOWN diff --git a/test/test-execute/exec-capabilityboundingset-reset.service b/test/test-execute/exec-capabilityboundingset-reset.service new file mode 100644 index 0000000000..d7d3320204 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-reset.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set ="' +Type=oneshot +CapabilityBoundingSet=CAP_FOWNER CAP_KILL +CapabilityBoundingSet= diff --git a/test/test-execute/exec-capabilityboundingset-simple.service b/test/test-execute/exec-capabilityboundingset-simple.service new file mode 100644 index 0000000000..bf1a7f575a --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-simple.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(capsh --print | grep "Bounding set "); test "$$c" = "Bounding set =cap_fowner,cap_kill"' +Type=oneshot +CapabilityBoundingSet=CAP_FOWNER CAP_KILL diff --git a/test/test-execute/exec-environment-empty.service b/test/test-execute/exec-environment-empty.service new file mode 100644 index 0000000000..9c92d4bc81 --- /dev/null +++ b/test/test-execute/exec-environment-empty.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for Environment + +[Service] +ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' +Type=oneshot +Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" +Environment= diff --git a/test/exec-environment-multiple.service b/test/test-execute/exec-environment-multiple.service index 479005a5d8..b9bc225635 100644 --- a/test/exec-environment-multiple.service +++ b/test/test-execute/exec-environment-multiple.service @@ -2,6 +2,7 @@ Description=Test for Environment [Service] -ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = foobar)' +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = foobar' +Type=oneshot Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" Environment="VAR3=foobar" diff --git a/test/test-execute/exec-environment.service b/test/test-execute/exec-environment.service new file mode 100644 index 0000000000..06e77af220 --- /dev/null +++ b/test/test-execute/exec-environment.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Environment + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" diff --git a/test/test-execute/exec-environmentfile.service b/test/test-execute/exec-environmentfile.service new file mode 100644 index 0000000000..f6b8462719 --- /dev/null +++ b/test/test-execute/exec-environmentfile.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for EnvironmentFile + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +EnvironmentFile=/tmp/test-exec_environmentfile.conf diff --git a/test/test-execute/exec-group.service b/test/test-execute/exec-group.service new file mode 100644 index 0000000000..be7c796912 --- /dev/null +++ b/test/test-execute/exec-group.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for Group + +[Service] +ExecStart=/bin/sh -x -c 'test "$$(id -n -g)" = "nobody"' +Type=oneshot +Group=nobody diff --git a/test/exec-ignoresigpipe-no.service b/test/test-execute/exec-ignoresigpipe-no.service index 69b2e9d8a8..73addf5f05 100644 --- a/test/exec-ignoresigpipe-no.service +++ b/test/test-execute/exec-ignoresigpipe-no.service @@ -2,6 +2,6 @@ Description=Test for IgnoreSIGPIPE=no [Service] -ExecStart=/bin/sh -c 'kill -PIPE 0' +ExecStart=/bin/sh -x -c 'kill -PIPE 0' Type=oneshot IgnoreSIGPIPE=no diff --git a/test/exec-ignoresigpipe-yes.service b/test/test-execute/exec-ignoresigpipe-yes.service index 877ec8aed0..f81c01719e 100644 --- a/test/exec-ignoresigpipe-yes.service +++ b/test/test-execute/exec-ignoresigpipe-yes.service @@ -2,6 +2,6 @@ Description=Test for IgnoreSIGPIPE=yes [Service] -ExecStart=/bin/sh -c 'kill -PIPE 0' +ExecStart=/bin/sh -x -c 'kill -PIPE 0' Type=oneshot IgnoreSIGPIPE=yes diff --git a/test/test-execute/exec-ioschedulingclass-best-effort.service b/test/test-execute/exec-ioschedulingclass-best-effort.service new file mode 100644 index 0000000000..29bb8510b4 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-best-effort.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=best-effort + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "best-effort"' +Type=oneshot +IOSchedulingClass=best-effort diff --git a/test/test-execute/exec-ioschedulingclass-idle.service b/test/test-execute/exec-ioschedulingclass-idle.service new file mode 100644 index 0000000000..87dbed14c1 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-idle.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=idle + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "idle"' +Type=oneshot +IOSchedulingClass=idle diff --git a/test/test-execute/exec-ioschedulingclass-none.service b/test/test-execute/exec-ioschedulingclass-none.service new file mode 100644 index 0000000000..b6af122a1e --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-none.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=none + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "none"' +Type=oneshot +IOSchedulingClass=none diff --git a/test/test-execute/exec-ioschedulingclass-realtime.service b/test/test-execute/exec-ioschedulingclass-realtime.service new file mode 100644 index 0000000000..d920d5c687 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-realtime.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=realtime + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(LC_ALL=C ionice); test "$${c%%:*}" = "realtime"' +Type=oneshot +IOSchedulingClass=realtime diff --git a/test/test-execute/exec-oomscoreadjust-negative.service b/test/test-execute/exec-oomscoreadjust-negative.service new file mode 100644 index 0000000000..2234c53c3f --- /dev/null +++ b/test/test-execute/exec-oomscoreadjust-negative.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for OOMScoreAdjust + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq -100' +Type=oneshot +OOMScoreAdjust=-100 diff --git a/test/test-execute/exec-oomscoreadjust-positive.service b/test/test-execute/exec-oomscoreadjust-positive.service new file mode 100644 index 0000000000..456a8f80cf --- /dev/null +++ b/test/test-execute/exec-oomscoreadjust-positive.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for OOMScoreAdjust + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(cat /proc/self/oom_score_adj); test "$$c" -eq 100' +Type=oneshot +OOMScoreAdjust=100 diff --git a/test/test-execute/exec-passenvironment-absent.service b/test/test-execute/exec-passenvironment-absent.service new file mode 100644 index 0000000000..7d5e32a4eb --- /dev/null +++ b/test/test-execute/exec-passenvironment-absent.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for PassEnvironment with variables absent from the execution environment + +[Service] +ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' +Type=oneshot +PassEnvironment=VAR1 VAR2 VAR3 diff --git a/test/test-execute/exec-passenvironment-empty.service b/test/test-execute/exec-passenvironment-empty.service new file mode 100644 index 0000000000..c93c197c10 --- /dev/null +++ b/test/test-execute/exec-passenvironment-empty.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for PassEnvironment and erasing the variable list + +[Service] +ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2-unset}" = "unset" && test "$${VAR3-unset}" = "unset"' +Type=oneshot +PassEnvironment=VAR1 VAR2 VAR3 +PassEnvironment= diff --git a/test/test-execute/exec-passenvironment-repeated.service b/test/test-execute/exec-passenvironment-repeated.service new file mode 100644 index 0000000000..5e8c56f26a --- /dev/null +++ b/test/test-execute/exec-passenvironment-repeated.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for PassEnvironment with a variable name repeated + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +PassEnvironment=VAR1 VAR2 +PassEnvironment=VAR1 VAR3 diff --git a/test/test-execute/exec-passenvironment.service b/test/test-execute/exec-passenvironment.service new file mode 100644 index 0000000000..b4a9909682 --- /dev/null +++ b/test/test-execute/exec-passenvironment.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for PassEnvironment + +[Service] +ExecStart=/bin/sh -x -c 'test "$$VAR1" = "word1 word2" && test "$$VAR2" = word3 && test "$$VAR3" = "\\$$word 5 6"' +Type=oneshot +PassEnvironment=VAR1 VAR2 VAR3 diff --git a/test/exec-personality-s390.service b/test/test-execute/exec-personality-s390.service index f3c3b03e3d..89f7de89d0 100644 --- a/test/exec-personality-s390.service +++ b/test/test-execute/exec-personality-s390.service @@ -2,6 +2,6 @@ Description=Test for Personality=s390 [Service] -ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "s390")' +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "s390"' Type=oneshot Personality=s390 diff --git a/test/exec-personality-x86-64.service b/test/test-execute/exec-personality-x86-64.service index 5bb5d910d0..433e69a6d1 100644 --- a/test/exec-personality-x86-64.service +++ b/test/test-execute/exec-personality-x86-64.service @@ -2,6 +2,6 @@ Description=Test for Personality=x86-64 [Service] -ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "x86_64")' +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "x86_64"' Type=oneshot Personality=x86-64 diff --git a/test/exec-personality-x86.service b/test/test-execute/exec-personality-x86.service index 0b370a6480..a623a08cbe 100644 --- a/test/exec-personality-x86.service +++ b/test/test-execute/exec-personality-x86.service @@ -2,6 +2,6 @@ Description=Test for Personality=x86 [Service] -ExecStart=/bin/sh -c 'echo $(uname -m); exit $(test $(uname -m) = "i686")' +ExecStart=/bin/sh -x -c 'c=$$(uname -m); test "$$c" = "i686"' Type=oneshot Personality=x86 diff --git a/test/exec-privatedevices-no.service b/test/test-execute/exec-privatedevices-no.service index cf4f275fb6..77aeb951b5 100644 --- a/test/exec-privatedevices-no.service +++ b/test/test-execute/exec-privatedevices-no.service @@ -2,6 +2,6 @@ Description=Test for PrivateDev=no [Service] -ExecStart=/bin/sh -c 'exit $(test -c /dev/mem)' +ExecStart=/bin/sh -x -c 'test -c /dev/mem' Type=oneshot PrivateDevices=no diff --git a/test/exec-privatedevices-yes.service b/test/test-execute/exec-privatedevices-yes.service index 85b3f4f981..ab958b646e 100644 --- a/test/exec-privatedevices-yes.service +++ b/test/test-execute/exec-privatedevices-yes.service @@ -2,6 +2,6 @@ Description=Test for PrivateDev=yes [Service] -ExecStart=/bin/sh -c 'exit $(test ! -c /dev/mem)' +ExecStart=/bin/sh -c 'test ! -c /dev/mem' Type=oneshot PrivateDevices=yes diff --git a/test/test-execute/exec-privatenetwork-yes.service b/test/test-execute/exec-privatenetwork-yes.service new file mode 100644 index 0000000000..3df543ec93 --- /dev/null +++ b/test/test-execute/exec-privatenetwork-yes.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for PrivateNetwork + +[Service] +ExecStart=/bin/sh -x -c 'i=$$(ip link | grep ": " | grep -v ": lo:"); test -z "$$i"' +Type=oneshot +PrivateNetwork=yes diff --git a/test/exec-privatetmp-no.service b/test/test-execute/exec-privatetmp-no.service index d69e552a63..59f60f4755 100644 --- a/test/exec-privatetmp-no.service +++ b/test/test-execute/exec-privatetmp-no.service @@ -2,6 +2,6 @@ Description=Test for PrivateTmp=no [Service] -ExecStart=/bin/sh -c 'exit $(test -f /tmp/test-exec_privatetmp)' +ExecStart=/bin/sh -x -c 'test -f /tmp/test-exec_privatetmp' Type=oneshot PrivateTmp=no diff --git a/test/exec-privatetmp-yes.service b/test/test-execute/exec-privatetmp-yes.service index 881a040b87..907c291b81 100644 --- a/test/exec-privatetmp-yes.service +++ b/test/test-execute/exec-privatetmp-yes.service @@ -2,6 +2,6 @@ Description=Test for PrivateTmp=yes [Service] -ExecStart=/bin/sh -c 'exit $(test ! -f /tmp/test-exec_privatetmp)' +ExecStart=/bin/sh -x -c 'test ! -f /tmp/test-exec_privatetmp' Type=oneshot PrivateTmp=yes diff --git a/test/exec-runtimedirectory-mode.service b/test/test-execute/exec-runtimedirectory-mode.service index ba6d7ee39f..842721d5c2 100644 --- a/test/exec-runtimedirectory-mode.service +++ b/test/test-execute/exec-runtimedirectory-mode.service @@ -2,7 +2,7 @@ Description=Test for RuntimeDirectoryMode [Service] -ExecStart=/bin/sh -c 's=$(stat -c %a /tmp/test-exec_runtimedirectory-mode); echo $s; exit $(test $s = "750")' +ExecStart=/bin/sh -x -c 'mode=$$(stat -c %%a /tmp/test-exec_runtimedirectory-mode); test "$$mode" = "750"' Type=oneshot RuntimeDirectory=test-exec_runtimedirectory-mode RuntimeDirectoryMode=0750 diff --git a/test/exec-runtimedirectory-owner.service b/test/test-execute/exec-runtimedirectory-owner.service index 077e08d1c5..1f438c182e 100644 --- a/test/exec-runtimedirectory-owner.service +++ b/test/test-execute/exec-runtimedirectory-owner.service @@ -2,7 +2,7 @@ Description=Test for RuntimeDirectory owner (must not be the default group of the user if Group is set) [Service] -ExecStart=/bin/sh -c 'f=/tmp/test-exec_runtimedirectory-owner;g=$(stat -c %G $f); echo "$g"; exit $(test $g = "nobody")' +ExecStart=/bin/sh -x -c 'group=$$(stat -c %%G /tmp/test-exec_runtimedirectory-owner); test "$$group" = "nobody"' Type=oneshot Group=nobody User=root diff --git a/test/exec-runtimedirectory.service b/test/test-execute/exec-runtimedirectory.service index c12a6c63d6..ec46c9d49b 100644 --- a/test/exec-runtimedirectory.service +++ b/test/test-execute/exec-runtimedirectory.service @@ -2,6 +2,6 @@ Description=Test for RuntimeDirectory [Service] -ExecStart=/bin/sh -c 'exit $(test -d /tmp/test-exec_runtimedirectory)' +ExecStart=/bin/sh -x -c 'test -d /tmp/test-exec_runtimedirectory' Type=oneshot RuntimeDirectory=test-exec_runtimedirectory diff --git a/test/exec-systemcallerrornumber.service b/test/test-execute/exec-systemcallerrornumber.service index 255a8b231a..ff7da3c1a4 100644 --- a/test/exec-systemcallerrornumber.service +++ b/test/test-execute/exec-systemcallerrornumber.service @@ -2,6 +2,7 @@ Description=Test for SystemCallErrorNumber [Service] -ExecStart=/usr/bin/uname -a +ExecStart=/bin/sh -x -c 'uname -a' +Type=oneshot SystemCallFilter=~uname SystemCallErrorNumber=EACCES diff --git a/test/exec-systemcallfilter-failing.service b/test/test-execute/exec-systemcallfilter-failing.service index c6ce9368c9..5c6422f0fd 100644 --- a/test/exec-systemcallfilter-failing.service +++ b/test/test-execute/exec-systemcallfilter-failing.service @@ -3,6 +3,7 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "This should not be seen" +Type=oneshot SystemCallFilter=ioperm SystemCallFilter=~ioperm SystemCallFilter=ioperm diff --git a/test/exec-systemcallfilter-failing2.service b/test/test-execute/exec-systemcallfilter-failing2.service index b7f7c2aff9..3516078e1f 100644 --- a/test/exec-systemcallfilter-failing2.service +++ b/test/test-execute/exec-systemcallfilter-failing2.service @@ -3,4 +3,5 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "This should not be seen" +Type=oneshot SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST diff --git a/test/exec-systemcallfilter-not-failing.service b/test/test-execute/exec-systemcallfilter-not-failing.service index feb206ab6d..c794b67edd 100644 --- a/test/exec-systemcallfilter-not-failing.service +++ b/test/test-execute/exec-systemcallfilter-not-failing.service @@ -3,6 +3,7 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "Foo bar" +Type=oneshot SystemCallFilter=~read write open execve ioperm SystemCallFilter=ioctl SystemCallFilter=read write open execve diff --git a/test/exec-systemcallfilter-not-failing2.service b/test/test-execute/exec-systemcallfilter-not-failing2.service index cca469aa3d..a62c81bd48 100644 --- a/test/exec-systemcallfilter-not-failing2.service +++ b/test/test-execute/exec-systemcallfilter-not-failing2.service @@ -3,4 +3,5 @@ Description=Test for SystemCallFilter [Service] ExecStart=/bin/echo "Foo bar" +Type=oneshot SystemCallFilter= diff --git a/test/test-execute/exec-umask-0177.service b/test/test-execute/exec-umask-0177.service new file mode 100644 index 0000000000..a5e8fc4dbc --- /dev/null +++ b/test/test-execute/exec-umask-0177.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for UMask + +[Service] +ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "600"' +Type=oneshot +UMask=0177 +PrivateTmp=yes diff --git a/test/test-execute/exec-umask-default.service b/test/test-execute/exec-umask-default.service new file mode 100644 index 0000000000..487f5e9b94 --- /dev/null +++ b/test/test-execute/exec-umask-default.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for UMask default + +[Service] +ExecStart=/bin/sh -x -c 'touch /tmp/test-exec-umask; mode=$$(stat -c %%a /tmp/test-exec-umask); test "$$mode" = "644"' +Type=oneshot +PrivateTmp=yes diff --git a/test/test-execute/exec-user.service b/test/test-execute/exec-user.service new file mode 100644 index 0000000000..0a00c1abc4 --- /dev/null +++ b/test/test-execute/exec-user.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for User + +[Service] +ExecStart=/bin/sh -x -c 'test "$$USER" = "nobody"' +Type=oneshot +User=nobody diff --git a/test/exec-workingdirectory.service b/test/test-execute/exec-workingdirectory.service index 10855d682a..fe3c420d2d 100644 --- a/test/exec-workingdirectory.service +++ b/test/test-execute/exec-workingdirectory.service @@ -2,6 +2,6 @@ Description=Test for WorkingDirectory [Service] -ExecStart=/bin/sh -c 'echo $PWD; exit $(test $PWD = "/tmp/test-exec_workingdirectory")' +ExecStart=/bin/sh -x -c 'test "$$PWD" = "/tmp/test-exec_workingdirectory"' Type=oneshot WorkingDirectory=/tmp/test-exec_workingdirectory diff --git a/test/test-functions b/test/test-functions index 8272e52e17..2f5ec9b93f 100644 --- a/test/test-functions +++ b/test/test-functions @@ -260,7 +260,7 @@ install_dbus() { inst $ROOTLIBDIR/system/dbus.service find \ - /etc/dbus-1 -xtype f \ + /etc/dbus-1 /usr/share/dbus-1 -xtype f \ | while read file; do inst $file done @@ -305,7 +305,7 @@ install_terminfo() { setup_testsuite() { cp $TEST_BASE_DIR/testsuite.target $initdir/etc/systemd/system/ - sed "s#@SYSTEMCTL@#$(type -P systemctl)#g" $TEST_BASE_DIR/end.service.in > $initdir/etc/systemd/system/end.service + cp $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/ mkdir -p $initdir/etc/systemd/system/testsuite.target.wants ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service diff --git a/test/test-path/basic.target b/test/test-path/basic.target new file mode 120000 index 0000000000..a882b72cc9 --- /dev/null +++ b/test/test-path/basic.target @@ -0,0 +1 @@ +../../units/basic.target
\ No newline at end of file diff --git a/test/path-changed.path b/test/test-path/path-changed.path index e58bdd925f..e58bdd925f 100644 --- a/test/path-changed.path +++ b/test/test-path/path-changed.path diff --git a/test/path-changed.service b/test/test-path/path-changed.service index 8bdf178830..8bdf178830 120000 --- a/test/path-changed.service +++ b/test/test-path/path-changed.service diff --git a/test/path-directorynotempty.path b/test/test-path/path-directorynotempty.path index 17e599fc0e..17e599fc0e 100644 --- a/test/path-directorynotempty.path +++ b/test/test-path/path-directorynotempty.path diff --git a/test/path-directorynotempty.service b/test/test-path/path-directorynotempty.service index 8bdf178830..8bdf178830 120000 --- a/test/path-directorynotempty.service +++ b/test/test-path/path-directorynotempty.service diff --git a/test/path-exists.path b/test/test-path/path-exists.path index c4c9105af4..c4c9105af4 100644 --- a/test/path-exists.path +++ b/test/test-path/path-exists.path diff --git a/test/path-exists.service b/test/test-path/path-exists.service index 8bdf178830..8bdf178830 120000 --- a/test/path-exists.service +++ b/test/test-path/path-exists.service diff --git a/test/path-existsglob.path b/test/test-path/path-existsglob.path index a058599605..a058599605 100644 --- a/test/path-existsglob.path +++ b/test/test-path/path-existsglob.path diff --git a/test/path-existsglob.service b/test/test-path/path-existsglob.service index 8bdf178830..8bdf178830 120000 --- a/test/path-existsglob.service +++ b/test/test-path/path-existsglob.service diff --git a/test/path-makedirectory.path b/test/test-path/path-makedirectory.path index 9408479c0f..9408479c0f 100644 --- a/test/path-makedirectory.path +++ b/test/test-path/path-makedirectory.path diff --git a/test/path-makedirectory.service b/test/test-path/path-makedirectory.service index 8bdf178830..8bdf178830 120000 --- a/test/path-makedirectory.service +++ b/test/test-path/path-makedirectory.service diff --git a/test/path-modified.path b/test/test-path/path-modified.path index 18363227ba..18363227ba 100644 --- a/test/path-modified.path +++ b/test/test-path/path-modified.path diff --git a/test/path-modified.service b/test/test-path/path-modified.service index 8bdf178830..8bdf178830 120000 --- a/test/path-modified.service +++ b/test/test-path/path-modified.service diff --git a/test/path-mycustomunit.service b/test/test-path/path-mycustomunit.service index 172ac0d0d5..172ac0d0d5 100644 --- a/test/path-mycustomunit.service +++ b/test/test-path/path-mycustomunit.service diff --git a/test/path-service.service b/test/test-path/path-service.service index f8499ec619..f8499ec619 100644 --- a/test/path-service.service +++ b/test/test-path/path-service.service diff --git a/test/path-unit.path b/test/test-path/path-unit.path index 95e572d6d5..95e572d6d5 100644 --- a/test/path-unit.path +++ b/test/test-path/path-unit.path diff --git a/test/test-path/paths.target b/test/test-path/paths.target new file mode 120000 index 0000000000..b402796cb9 --- /dev/null +++ b/test/test-path/paths.target @@ -0,0 +1 @@ +../../units/paths.target
\ No newline at end of file diff --git a/test/test-path/sysinit.target b/test/test-path/sysinit.target new file mode 120000 index 0000000000..9d10e5b2e2 --- /dev/null +++ b/test/test-path/sysinit.target @@ -0,0 +1 @@ +../../units/sysinit.target
\ No newline at end of file diff --git a/test/unstoppable.service b/test/unstoppable.service index 24fb0a25e1..56b72c98f7 100644 --- a/test/unstoppable.service +++ b/test/unstoppable.service @@ -1,5 +1,5 @@ [Service] Type=oneshot RemainAfterExit=yes -ExecStart=/bin/echo 'I'm unstoppable!' +ExecStart=/bin/echo "I'm unstoppable!" ExecStop=/bin/systemctl start --no-block unstoppable.service diff --git a/tmpfiles.d/home.conf b/tmpfiles.d/home.conf index aa652b197f..9f25b83392 100644 --- a/tmpfiles.d/home.conf +++ b/tmpfiles.d/home.conf @@ -7,5 +7,5 @@ # See tmpfiles.d(5) for details -v /home 0755 - - - -v /srv 0755 - - - +Q /home 0755 - - - +q /srv 0755 - - - diff --git a/tmpfiles.d/systemd-nspawn.conf b/tmpfiles.d/systemd-nspawn.conf index 5a3124a0fc..9fa3878d6b 100644 --- a/tmpfiles.d/systemd-nspawn.conf +++ b/tmpfiles.d/systemd-nspawn.conf @@ -7,7 +7,7 @@ # See tmpfiles.d(5) for details -v /var/lib/machines 0700 - - - +Q /var/lib/machines 0700 - - - # Remove old temporary snapshots, but only at boot. Ideally we'd have # "self-destroying" btrfs snapshots that go away if the last last diff --git a/tmpfiles.d/tmp.conf b/tmpfiles.d/tmp.conf index ffdd82fd9c..6bbd1aa341 100644 --- a/tmpfiles.d/tmp.conf +++ b/tmpfiles.d/tmp.conf @@ -8,8 +8,8 @@ # See tmpfiles.d(5) for details # Clear tmp directories separately, to make them easier to override -v /tmp 1777 root root 10d -v /var/tmp 1777 root root 30d +q /tmp 1777 root root 10d +q /var/tmp 1777 root root 30d # Exclude namespace mountpoints created with PrivateTmp=yes x /tmp/systemd-private-%b-* diff --git a/tmpfiles.d/var.conf b/tmpfiles.d/var.conf index 472680c3bf..ae7952e77a 100644 --- a/tmpfiles.d/var.conf +++ b/tmpfiles.d/var.conf @@ -7,7 +7,7 @@ # See tmpfiles.d(5) for details -v /var 0755 - - - +q /var 0755 - - - L /var/run - - - - ../run diff --git a/units/.gitignore b/units/.gitignore index 883f51f73c..c89740df05 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -78,4 +78,5 @@ /systemd-update-utmp.service /systemd-user-sessions.service /systemd-vconsole-setup.service +/tmp.mount /user@.service diff --git a/units/system.slice b/units/system.slice index c0e3df9d0f..841f049b58 100644 --- a/units/system.slice +++ b/units/system.slice @@ -10,5 +10,5 @@ Description=System Slice Documentation=man:systemd.special(7) DefaultDependencies=no Before=slices.target -Wants=-.slice +Requires=-.slice After=-.slice diff --git a/units/systemd-networkd.socket b/units/systemd-networkd.socket index 2c20935d83..9e4e9dd338 100644 --- a/units/systemd-networkd.socket +++ b/units/systemd-networkd.socket @@ -14,7 +14,7 @@ Before=sockets.target [Socket] ReceiveBuffer=8M -ListenNetlink=route 273 +ListenNetlink=route 1361 PassCredentials=yes [Install] diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in index 03349931d9..2e79adff44 100644 --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@ -39,6 +39,7 @@ DeviceAllow=char-pts rw # implement the --image= option. Add these here, too. DeviceAllow=/dev/loop-control rw DeviceAllow=block-loop rw +DeviceAllow=block-blkext rw [Install] WantedBy=machines.target diff --git a/units/tmp.mount b/units/tmp.mount.m4 index 00a0d28722..00a0d28722 100644 --- a/units/tmp.mount +++ b/units/tmp.mount.m4 diff --git a/units/user/exit.target b/units/user/exit.target index b0ad24c488..e8148b78c7 100644 --- a/units/user/exit.target +++ b/units/user/exit.target @@ -12,6 +12,3 @@ DefaultDependencies=no Requires=systemd-exit.service After=systemd-exit.service AllowIsolate=yes - -[Install] -Alias=ctrl-alt-del.target |