diff options
995 files changed, 33720 insertions, 21338 deletions
diff --git a/.gitignore b/.gitignore index 605d109dfa..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 @@ -96,7 +95,6 @@ /systemd-kmsg-syslogd /systemd-localed /systemd-logind -/systemd-machine-id-commit /systemd-machine-id-setup /systemd-machined /systemd-modules-load @@ -136,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 @@ -184,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 @@ -230,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 @@ -245,15 +247,15 @@ /test-replace-var /test-resolve /test-ring -/test-netlink -/test-netlink-manual /test-sched-prio /test-set /test-sigbus +/test-siphash24 /test-sleep /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 diff --git a/CODING_STYLE b/CODING_STYLE index 98d99dcdaa..8b945cd3c1 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -321,3 +321,54 @@ parse values the same way on all architectures and cannot expose off_t values over D-Bus. To avoid any confusion regarding conversion and ABIs, always use simply uint64_t directly. + +- Commit message subject lines should be prefixed with an appropriate + component name of some kind. For example "journal: ", "nspawn: " and + so on. + +- Do not use "Signed-Off-By:" in your commit messages. That's a kernel + thing we don't do in the systemd project. + +- Avoid leaving long-running child processes around, i.e. fork()s that + are not followed quickly by an execv() in the child. Resource + management is unclear in this case, and memory CoW will result in + unexpected penalties in the parent much much later on. + +- Don't block execution for arbitrary amounts of time using usleep() + or a similar call, unless you really know what you do. Just "giving + something some time", or so is a lazy excuse. Always wait for the + proper event, instead of doing time-based poll loops. + +- To determine the length of a constant string "foo", don't bother + with sizeof("foo")-1, please use strlen("foo") directly. gcc knows + strlen() anyway and turns it into a constant expression if possible. + +- 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 3b8038611b..56aa0fff1b 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -102,7 +102,6 @@ MANPAGES += \ man/systemd-inhibit.1 \ man/systemd-initctl.service.8 \ man/systemd-journald.service.8 \ - man/systemd-machine-id-commit.1 \ man/systemd-machine-id-commit.service.8 \ man/systemd-machine-id-setup.1 \ man/systemd-notify.1 \ @@ -292,6 +291,8 @@ MANPAGES_ALIAS += \ man/sd_bus_open_system_remote.3 \ man/sd_bus_open_user.3 \ man/sd_bus_path_decode.3 \ + man/sd_bus_path_decode_many.3 \ + man/sd_bus_path_encode_many.3 \ man/sd_bus_ref.3 \ man/sd_bus_release_name.3 \ man/sd_bus_unref.3 \ @@ -354,6 +355,7 @@ MANPAGES_ALIAS += \ man/sd_journal_set_data_threshold.3 \ man/sd_journal_test_cursor.3 \ man/sd_journal_wait.3 \ + man/sd_listen_fds_with_names.3 \ man/sd_machine_get_ifindices.3 \ man/sd_notifyf.3 \ man/sd_pid_notify.3 \ @@ -372,6 +374,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 \ @@ -578,6 +581,8 @@ man/sd_bus_open_system_machine.3: man/sd_bus_default.3 man/sd_bus_open_system_remote.3: man/sd_bus_default.3 man/sd_bus_open_user.3: man/sd_bus_default.3 man/sd_bus_path_decode.3: man/sd_bus_path_encode.3 +man/sd_bus_path_decode_many.3: man/sd_bus_path_encode.3 +man/sd_bus_path_encode_many.3: man/sd_bus_path_encode.3 man/sd_bus_ref.3: man/sd_bus_new.3 man/sd_bus_release_name.3: man/sd_bus_request_name.3 man/sd_bus_unref.3: man/sd_bus_new.3 @@ -640,6 +645,7 @@ man/sd_journal_sendv.3: man/sd_journal_print.3 man/sd_journal_set_data_threshold.3: man/sd_journal_get_data.3 man/sd_journal_test_cursor.3: man/sd_journal_get_cursor.3 man/sd_journal_wait.3: man/sd_journal_get_fd.3 +man/sd_listen_fds_with_names.3: man/sd_listen_fds.3 man/sd_machine_get_ifindices.3: man/sd_machine_get_class.3 man/sd_notifyf.3: man/sd_notify.3 man/sd_pid_notify.3: man/sd_notify.3 @@ -658,6 +664,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 @@ -1124,6 +1131,12 @@ man/sd_bus_open_user.html: man/sd_bus_default.html man/sd_bus_path_decode.html: man/sd_bus_path_encode.html $(html-alias) +man/sd_bus_path_decode_many.html: man/sd_bus_path_encode.html + $(html-alias) + +man/sd_bus_path_encode_many.html: man/sd_bus_path_encode.html + $(html-alias) + man/sd_bus_ref.html: man/sd_bus_new.html $(html-alias) @@ -1310,6 +1323,9 @@ man/sd_journal_test_cursor.html: man/sd_journal_get_cursor.html man/sd_journal_wait.html: man/sd_journal_get_fd.html $(html-alias) +man/sd_listen_fds_with_names.html: man/sd_listen_fds.html + $(html-alias) + man/sd_machine_get_ifindices.html: man/sd_machine_get_class.html $(html-alias) @@ -1364,6 +1380,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) @@ -1798,11 +1817,16 @@ endif if ENABLE_RFKILL MANPAGES += \ - man/systemd-rfkill@.service.8 + man/systemd-rfkill.service.8 MANPAGES_ALIAS += \ - man/systemd-rfkill.8 -man/systemd-rfkill.8: man/systemd-rfkill@.service.8 -man/systemd-rfkill.html: man/systemd-rfkill@.service.html + man/systemd-rfkill.8 \ + man/systemd-rfkill.socket.8 +man/systemd-rfkill.8: man/systemd-rfkill.service.8 +man/systemd-rfkill.socket.8: man/systemd-rfkill.service.8 +man/systemd-rfkill.html: man/systemd-rfkill.service.html + $(html-alias) + +man/systemd-rfkill.socket.html: man/systemd-rfkill.service.html $(html-alias) endif @@ -2341,7 +2365,6 @@ EXTRA_DIST += \ man/systemd-localed.service.xml \ man/systemd-logind.service.xml \ man/systemd-machine-id-commit.service.xml \ - man/systemd-machine-id-commit.xml \ man/systemd-machine-id-setup.xml \ man/systemd-machined.service.xml \ man/systemd-modules-load.service.xml \ @@ -2354,7 +2377,7 @@ EXTRA_DIST += \ man/systemd-random-seed.service.xml \ man/systemd-remount-fs.service.xml \ man/systemd-resolved.service.xml \ - man/systemd-rfkill@.service.xml \ + man/systemd-rfkill.service.xml \ man/systemd-run.xml \ man/systemd-sleep.conf.xml \ man/systemd-socket-proxyd.xml \ diff --git a/Makefile.am b/Makefile.am index e9ad72333b..51548bb289 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,9 +42,9 @@ LIBUDEV_CURRENT=7 LIBUDEV_REVISION=4 LIBUDEV_AGE=6 -LIBSYSTEMD_CURRENT=11 +LIBSYSTEMD_CURRENT=12 LIBSYSTEMD_REVISION=0 -LIBSYSTEMD_AGE=11 +LIBSYSTEMD_AGE=12 # The following four libraries only exist for compatibility reasons, # their version info should not be bumped anymore @@ -397,7 +397,6 @@ rootlibexec_PROGRAMS = \ systemd-remount-fs \ systemd-reply-password \ systemd-fsck \ - systemd-machine-id-commit \ systemd-ac-power \ systemd-sysctl \ systemd-sleep \ @@ -617,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 += \ @@ -762,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 \ @@ -781,6 +782,44 @@ 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 \ src/basic/lockfile-util.h \ src/basic/path-util.c \ @@ -789,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 \ @@ -805,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 \ @@ -836,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 \ @@ -862,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 \ @@ -897,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 \ @@ -918,7 +966,6 @@ libbasic_la_CFLAGS = \ libbasic_la_LIBADD = \ $(SELINUX_LIBS) \ $(CAP_LIBS) \ - -ldl \ -lrt \ -lm @@ -938,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 \ @@ -1228,7 +1274,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) @@ -1395,11 +1441,16 @@ tests += \ test-path \ test-path-util \ test-strxcpyx \ + test-siphash24 \ test-unit-name \ test-unit-file \ 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 \ @@ -1465,7 +1516,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 \ @@ -1479,43 +1529,58 @@ 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-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 \ @@ -1684,6 +1749,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 @@ -2009,6 +2098,12 @@ test_execute_CFLAGS = \ test_execute_LDADD = \ libcore.la +test_siphash24_SOURCES = \ + src/test/test-siphash24.c + +test_siphash24_LDADD = \ + libshared.la + test_strxcpyx_SOURCES = \ src/test/test-strxcpyx.c @@ -2331,6 +2426,9 @@ systemd_machine_id_setup_SOURCES = \ systemd_machine_id_setup_LDADD = \ libshared.la +SYSINIT_TARGET_WANTS += \ + systemd-machine-id-commit.service + # ------------------------------------------------------------------------------ systemd_sysctl_SOURCES = \ src/sysctl/sysctl.c @@ -2353,18 +2451,6 @@ systemd_fsck_LDADD = \ libshared.la # ------------------------------------------------------------------------------ -systemd_machine_id_commit_SOURCES = \ - src/machine-id-commit/machine-id-commit.c \ - src/core/machine-id-setup.c \ - src/core/machine-id-setup.h - -systemd_machine_id_commit_LDADD = \ - libshared.la - -SYSINIT_TARGET_WANTS += \ - systemd-machine-id-commit.service - -# ------------------------------------------------------------------------------ systemd_ac_power_SOURCES = \ src/ac-power/ac-power.c @@ -3216,10 +3302,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 \ @@ -3235,10 +3320,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 \ @@ -3314,23 +3400,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 @@ -3362,13 +3440,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 @@ -3484,7 +3559,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 }' < $< > $@ @@ -3492,9 +3567,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 @@ -3521,7 +3593,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 += \ @@ -3832,6 +3903,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 += \ @@ -3846,7 +3918,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 @@ -4185,6 +4256,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 @@ -4471,7 +4543,10 @@ rootlibexec_PROGRAMS += \ systemd-rfkill nodist_systemunit_DATA += \ - units/systemd-rfkill@.service + units/systemd-rfkill.service + +dist_systemunit_DATA += \ + units/systemd-rfkill.socket systemd_rfkill_SOURCES = \ src/rfkill/rfkill.c @@ -4481,7 +4556,7 @@ systemd_rfkill_LDADD = \ endif EXTRA_DIST += \ - units/systemd-rfkill@.service.in + units/systemd-rfkill.service.in # ------------------------------------------------------------------------------ if HAVE_LIBCRYPTSETUP @@ -5146,7 +5221,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 @@ -5232,6 +5308,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 \ @@ -13,33 +13,196 @@ CHANGES WITH 227: stopped having this file around as anything else than a symlink to /proc/self/mounts. - * Support for the "pids" cgroup controller has been added. - It allows accounting the number of tasks in a cgroup and + * Support for the "pids" cgroup controller has been added. It + allows accounting the number of tasks in a cgroup and enforcing limits on it. This adds two new setting TasksAccounting= and TasksMax= to each unit, as well as a - gloabl option DefaultTasksAccounting=. + global option DefaultTasksAccounting=. * Support for the "net_cls" cgroup controller has been added. - It allows assigning a net class ID to each task in the cgroup, - which can then be used in firewall rules and traffic shaping - configurations. Note that the kernel netfilter code does not - currently work reliably for ingress packets on unestablished - sockets. + It allows assigning a net class ID to each task in the + cgroup, which can then be used in firewall rules and traffic + shaping configurations. Note that the kernel netfilter net + class code does not currently work reliably for ingress + packets on unestablished sockets. This adds a new config directive called NetClass= to CGroup - enabled units. Allowed values are positive numbers for fix + enabled units. Allowed values are positive numbers for fixed assignments and "auto" for picking a free value automatically. - * The PrivateTmp, PrivateDevices, PrivateNetwork, - NoNewPrivileges, TTYPath, WorkingDirectory and RootDirectory - properties can now be set for transient units. - - * Galician and Turkish translations were added. - - Contributions from: + * 'systemctl is-system-running' now returns 'offline' if the + system is not booted with systemd. This command can now be + used as a substitute for 'systemd-notify --booted'. + + * Watchdog timeouts have been increased to 3 minutes for all + in-tree service files. Apparently, disk IO issues are more + frequent than we hoped, and user reported >1 minute waiting + for disk IO. + + * 'machine-id-commit' functionality has been merged into + 'machine-id-setup --commit'. The separate binary has been + removed. + + * The WorkingDirectory= directive in unit files may now be set + to the special value '~'. In this case, the working + directory is set to the home directory of the user + configured in User=. + + * "machinectl shell" will now open the shell in the home + directory of the selected user by default. + + * The CrashChVT= configuration file setting is renamed to + CrashChangeVT=, following our usual logic of not + abbreviating unnecessarily. The old directive is still + supported for compat reasons. Also, this directive now takes + an integer value between 1 and 63, or a boolean value. The + formerly supported '-1' value for disabling stays around for + compat reasons. + + * The PrivateTmp=, PrivateDevices=, PrivateNetwork=, + NoNewPrivileges=, TTYPath=, WorkingDirectory= and + RootDirectory= properties can now be set for transient + units. - -- Berlin, 2015-09-xx + * The systemd-analyze tool gained a new "set-log-target" verb + to change the logging target the system manager logs to + dynamically during runtime. This is similar to how + "systemd-analyze set-log-level" already changes the log + level. + + * In nspawn /sys is now mounted as tmpfs, with only a selected + set of subdirectories mounted in from the real sysfs. This + enhances security slightly, and is useful for ensuring user + namespaces work correctly. + + * Support for USB FunctionFS activation has been added. This + allows implementation of USB gadget services that are + activated as soon as they are requested, so that they don't + have to run continously, similar to classic socket + activation. + + * The "systemctl exit" command now optionally takes an + additional parameter that sets the exit code to return from + the systemd manager when exiting. This is only relevant when + running the systemd user instance, or when running the + system instance in a container. + + * sd-bus gained the new API calls sd_bus_path_encode_many() + and sd_bus_path_decode_many() that allow easy encoding and + decoding of multiple identifier strings inside a D-Bus + object path. Another new call sd_bus_default_flush_close() + has been added to flush and close per-thread default + connections. + + * systemd-cgtop gained support for a -M/--machine= switch to + show the control groups within a certain container only. + + * "systemctl kill" gained support for an optional --fail + switch. If specified the requested operation will fail of no + processes have been killed, because the unit had no + processes attached, or similar. + + * A new systemd.crash_reboot=1 kernel command line option has + been added that triggers a reboot after crashing. This can + also be set through CrashReboot= in systemd.conf. + + * The RuntimeDirectory= setting now understands unit + specifiers like %i or %f. + + * A new (still internal) libary API sd-ipv4acd has been added, + that implements address conflict detection for IPv4. It's + based on code from sd-ipv4ll, and will be useful for + detecting DHCP address conflicts. + + * 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 overridden, + either in the .socket file using the FileDescriptorName= + parameter, or by passing FDNAME= when storing the file + descriptors using sd_notify(). + + * systemd-networkd gained support for: + + - Setting the IPv6 Router Advertisment settings via + IPv6AcceptRouterAdvertisements= in .network files. + + - Configuring the HelloTimeSec=, MaxAgeSec= and + ForwardDelaySec= bridge parameters in .netdev files. + + - Configuring PreferredSource= for static routes in + .network files. + + * The "ask-password" framework used to query for LUKS harddisk + passwords or SSL passwords during boot gained support for + caching passwords in the kernel keyring, if it is + available. This makes sure that the user only has to type in + a passphrase once if there are multiple objects to unlock + with the same one. Previously, such password caching was + available only when Plymouth was used; this moves the + caching logic into the systemd codebase itself. The + "systemd-ask-password" utility gained a new --keyname= + switch to control which kernel keyring key to use for + caching a password in. This functionality is also useful for + enabling display managers such as gdm to automatically + unlock the user's GNOME keyring if its passphrase, the + user's password and the harddisk password are the same, if + gdm-autologin is used. + + * When downloading tar or raw images using "machinectl + pull-tar" or "machinectl pull-raw", a matching ".nspawn" + file is now also downloaded, if it is available and stored + next to the image file. + + * Units of type ".socket" gained a new boolean setting + Writable= which is only useful in conjunction with + ListenSpecial=. If true, enables opening the specified + special file in O_RDWR mode rather than O_RDONLY mode. + + * systemd-rfkill has been reworked to become a singleton + service that is activated through /dev/rfkill on each rfkill + state change and saves the settings to disk. This way, + systemd-rfkill is now compatible with devices that exist + only intermittendly, and even restores state if the previous + system shutdown was abrupt rather than clean. + + * The journal daemon gained support for vacuuming old journal + files controlled by the number of files that shall remain, + in addition to the already existing control by size and by + date. This is useful as journal interleaving performance + degrades with too many seperate journal files, and allows + putting an effective limit on them. The new setting defaults + to 100, but this may be changed by setting SystemMaxFiles= + and RuntimeMaxFiles= in journald.conf. Also, the + "journalctl" tool gained the new --vacuum-files= switch to + manually vacuum journal files to leave only the specified + number of files in place. + + * udev will now create /dev/disk/by-path links for ATA devices + on kernels where that is supported. + + * Galician, Serbian, Turkish and Korean translations were added. + + Contributions from: Aaro Koskinen, Alban Crequy, Beniamino + Galvani, Benjamin Robin, Branislav Blaskovic, Chen-Han Hsiao + (Stanley), Daniel Buch, Daniel Machon, Daniel Mack, David + Herrmann, David Milburn, doubleodoug, Evgeny Vereshchagin, + Felipe Franciosi, Filipe Brandenburger, Fran Dieguez, Gabriel + de Perthuis, Georg Müller, Hans de Goede, Hendrik Brueckner, + Ivan Shapovalov, Jacob Keller, Jan Engelhardt, Jan Janssen, + Jan Synacek, Jens Kuske, Karel Zak, Kay Sievers, Krzesimir + Nowak, Krzysztof Kotlenga, Lars Uebernickel, Lennart + Poettering, Lukas Nykryn, Łukasz Stelmach, Maciej Wereski, + Marcel Holtmann, Marius Thesing, Martin Pitt, Michael Biebl, + Michael Gebetsroither, Michal Schmidt, Michal Sekletar, Mike + Gilbert, Muhammet Kara, nazgul77, Nicolas Cornu, NoXPhasma, + Olof Johansson, Patrik Flykt, Pawel Szewczyk, reverendhomer, + Ronny Chevalier, Sangjung Woo, Seong-ho Cho, Susant Sahani, + Sylvain Plantefève, Thomas Haller, Thomas Hindoe Paaboel + Andersen, Tom Gundersen, Tom Lyon, Viktar Vauchkevich, + Zbigniew Jędrzejewski-Szmek, Марко М. Костић + + -- Berlin, 2015-10-07 CHANGES WITH 226: @@ -993,7 +1156,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. @@ -1001,7 +1164,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 @@ -1025,7 +1188,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. @@ -1035,7 +1198,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. @@ -1046,7 +1209,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, @@ -1099,9 +1262,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. @@ -1140,7 +1303,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 @@ -1473,7 +1636,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 @@ -1689,7 +1852,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. @@ -1771,8 +1934,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. @@ -1872,14 +2035,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 @@ -2581,7 +2744,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 @@ -4111,8 +4274,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 @@ -5152,7 +5315,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) @@ -24,16 +24,25 @@ External: * 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: -* add "requires=" deps on slices from services, not just "wants=" +* do something about "/control" subcgroups in the unified cgroup hierarchy -* add a concept of RemainAfterExit= to scope units +* when we detect that there are waiting jobs but no running jobs, do something -* add sd_booted() check into "systemctl is-system-running", and return - a new state "foreign" or so if we are not running on systemd. +* push CPUAffinity also into the "cpuset" cgroup controller -* add journal vacuum by max number of files +* add a concept of RemainAfterExit= to scope units * add a new command "systemctl revert" or so, that removes all dropin snippets in /run and /etc, and all unit files with counterparts in @@ -139,9 +148,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. @@ -164,15 +170,9 @@ Features: that are not supported... http://lists.freedesktop.org/archives/systemd-devel/2015-February/028076.html -* Introduce $LISTEN_NAMES to complement $LISTEN_FDS, containing a - colon separated list of identifiers for the fds passed. - * maybe introduce WantsMountsFor=? Usecase: http://lists.freedesktop.org/archives/systemd-devel/2015-January/027729.html -* rework kexec logic to use new kexec_file_load() syscall, so that we - don't have to call kexec tool anymore. - * The udev blkid built-in should expose a property that reflects whether media was sensed in USB CF/SD card readers. This should then be used to control SYSTEMD_READY=1/0 so that USB card readers aren't @@ -187,14 +187,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 @@ -233,8 +231,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 @@ -276,8 +272,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 @@ -565,9 +559,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. @@ -885,7 +876,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: diff --git a/catalog/systemd.sr.catalog b/catalog/systemd.sr.catalog new file mode 100644 index 0000000000..cf700c477b --- /dev/null +++ b/catalog/systemd.sr.catalog @@ -0,0 +1,262 @@ +# 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 +# Serbian translation + +# Формат каталога је документован на +# 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) + +Услуга је уписала сувише порука за једно време. Поруке +од услуге су одбачене. + +Знајте да су само поруке од ове услуге одбачене, друге +услуге нису захваћене овим. + +Ограничења која подешавају начин на који се поруке одбацују се могу подесити +помоћу „RateLimitInterval=“ и „RateLimitBurst=“ параметара унутар датотеке +/etc/systemd/journald.conf. Погледајте journald.conf(5) за појединости. + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: Журналске поруке су изгубљене +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Поруке кернела су изгубљене јер журналски систем није могао да их +обради довољно брзо. + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: Процес @COREDUMP_PID@ (@COREDUMP_COMM@) је избацио своје језгро +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Процес @COREDUMP_PID@ (@COREDUMP_COMM@) је пао и избацио своје језгро. + +Ово обично значи да постоји грешка у програму који је пао и ова +грешка треба да се пријави продавцу. + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: Нова сесија @SESSION_ID@ је направљена за корисника @USER_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Нова сесија са ИБ-ом @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 + +Сесија са ИБ-ом @SESSION_ID@ је окончана. + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: Ново седиште @SEAT_ID@ је сада доступно +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Ново седиште @SEAT_ID@ је исподешавано и сада је доступно. + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: Седиште @SEAT_ID@ је сада уклоњено +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Седиште @SEAT_ID@ је сада уклоњено и више није доступно. + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: Време је промењено +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Системски сат је сада подешен на @REALTIME@ микросекунде након 1. јануара 1970. године. + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: Временска зона је промењена на @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Временска зона је промењена на @TIMEZONE@. + +-- b07a249cd024414a82dd00cd181378ff +Subject: Подизање система је сада готово +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Све системске услуге које су заказане за подизање су успешно покренуте. +Знајте да ово не значи да је машина сада беспослена јер услуге могу +и даље бити заузете завршавањем покретања система. + +Подизање кернела је трајало @KERNEL_USEC@ микросекунде. + +Подизање почетног РАМ диска је трајало @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: Једна или више порука није могло бити прослеђено системском записнику +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Једна или више порука није могло бити прослеђено „syslog“ услузи +која ради упоредно са журнал-деом. Ово обично значи да спроведена +„syslog“ услуга није могла да издржи брзину свих надолазећих +порука у реду. + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: Тачка качења није празна +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Директоријум @WHERE@ је наведен као тачка качења (друго поље у +/etc/fstab датотеци или у „Where=“ пољу систем-де јединичне датотеке) +и он није празан. Ово не утиче на качење али ће већ постојеће датотеке у +овом директоријуму постати недоступне. Да бисте видели ове недоступне +датотеке, ручно прикачите основни систем датотека у другу +путању. + +-- 24d8d4452573402496068381a6312df2 +Subject: Виртуелна машина или контејнер је покренут(а) +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Виртуелна машина @NAME@ са водећим ПИБ-ом @LEADER@ је +покренута и сада је спремна за коришћење. + +-- 58432bd3bace477cb514b56381b8a758 +Subject: Виртуелна машина или контејнер је окончан(а) +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Виртуелна машина @NAME@ са водећим ПИБ-ом @LEADER@ је +угашена. 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/coccinelle/strempty.cocci b/coccinelle/strempty.cocci new file mode 100644 index 0000000000..e3bd0a1f56 --- /dev/null +++ b/coccinelle/strempty.cocci @@ -0,0 +1,10 @@ +@@ +expression s; +@@ +- s ?: "" ++ strempty(s) +@@ +expression s; +@@ +- s ? s : "" ++ strempty(s) diff --git a/configure.ac b/configure.ac index d75a02623b..c96b9fb1d9 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_PREREQ([2.64]) AC_INIT([systemd], - [226], + [227], [http://github.com/systemd/systemd/issues], [systemd], [http://www.freedesktop.org/wiki/Software/systemd]) @@ -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,11 +292,12 @@ 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]) AC_CHECK_FUNCS([__secure_getenv secure_getenv]) -AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, LO_FLAGS_PARTSCAN], +AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, keyctl, key_serial_t, LO_FLAGS_PARTSCAN], [], [], [[ #include <sys/types.h> #include <unistd.h> @@ -321,6 +320,7 @@ AC_CHECK_DECLS([IFLA_INET6_ADDR_GEN_MODE, IFLA_GRE_ENCAP_DPORT, IFLA_BRIDGE_VLAN_INFO, IFLA_BRPORT_LEARNING_SYNC, + IFLA_BR_PRIORITY, NDA_IFINDEX, IFA_FLAGS], [], [], [[ @@ -530,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"]) # ------------------------------------------------------------------------------ @@ -556,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"]) @@ -790,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 @@ -1106,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, @@ -1285,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 5a7f28729d..a825e744e1 100644 --- a/hwdb/20-bluetooth-vendor-product.hwdb +++ b/hwdb/20-bluetooth-vendor-product.hwdb @@ -829,7 +829,7 @@ bluetooth:v0111* ID_VENDOR_FROM_DATABASE=Steelseries ApS bluetooth:v0112* - ID_VENDOR_FROM_DATABASE=vyzybl Inc. + ID_VENDOR_FROM_DATABASE=Visybl Inc. bluetooth:v0113* ID_VENDOR_FROM_DATABASE=Openbrain Technologies, Co., Ltd. @@ -1931,3 +1931,138 @@ bluetooth:v0280* bluetooth:v0281* ID_VENDOR_FROM_DATABASE=StoneL + +bluetooth:v0282* + ID_VENDOR_FROM_DATABASE=Sonova AG + +bluetooth:v0283* + ID_VENDOR_FROM_DATABASE=Maven Machines, Inc. + +bluetooth:v0284* + ID_VENDOR_FROM_DATABASE=Synapse Electronics + +bluetooth:v0285* + ID_VENDOR_FROM_DATABASE=Standard Innovation Inc. + +bluetooth:v0286* + ID_VENDOR_FROM_DATABASE=RF Code, Inc. + +bluetooth:v0287* + ID_VENDOR_FROM_DATABASE=Wally Ventures S.L. + +bluetooth:v0288* + ID_VENDOR_FROM_DATABASE=Willowbank Electronics Ltd + +bluetooth:v0289* + ID_VENDOR_FROM_DATABASE=SK Telecom + +bluetooth:v028A* + ID_VENDOR_FROM_DATABASE=Jetro AS + +bluetooth:v028B* + ID_VENDOR_FROM_DATABASE=Code Gears LTD + +bluetooth:v028C* + ID_VENDOR_FROM_DATABASE=NANOLINK APS + +bluetooth:v028D* + ID_VENDOR_FROM_DATABASE=IF, LLC + +bluetooth:v028E* + ID_VENDOR_FROM_DATABASE=RF Digital Corp + +bluetooth:v028F* + ID_VENDOR_FROM_DATABASE=Church & Dwight Co., Inc + +bluetooth:v0290* + ID_VENDOR_FROM_DATABASE=Multibit Oy + +bluetooth:v0291* + ID_VENDOR_FROM_DATABASE=CliniCloud Inc + +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-keyboard.hwdb b/hwdb/60-keyboard.hwdb index 3e49449ae9..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 ########################################################### 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 ca933645a9..a783a9f3b5 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> @@ -437,13 +439,11 @@ <varlistentry> <term><option>-t</option></term> - <term><option>--identifier=<replaceable>SYSLOG_IDENTIFIER</replaceable>|<replaceable>PATTERN</replaceable></option></term> + <term><option>--identifier=<replaceable>SYSLOG_IDENTIFIER</replaceable></option></term> <listitem><para>Show messages for the specified syslog - identifier <replaceable>SYSLOG_IDENTIFIER</replaceable>, or - for any of the messages with a - <literal>SYSLOG_IDENTIFIER</literal> matched by - <replaceable>PATTERN</replaceable>.</para> + identifier + <replaceable>SYSLOG_IDENTIFIER</replaceable>.</para> <para>This parameter can be specified multiple times.</para></listitem> @@ -520,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> @@ -536,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 @@ -649,24 +651,34 @@ <varlistentry> <term><option>--vacuum-size=</option></term> <term><option>--vacuum-time=</option></term> + <term><option>--vacuum-files=</option></term> <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). 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 former only operates on archived - journal files. <option>--vacuum-size=</option> and - <option>--vacuum-time=</option> may be combined in a single - invocation to enforce both a size and time limit on the - archived journal files.</para></listitem> + <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 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 + files. <option>--vacuum-size=</option>, + <option>--vacuum-time=</option> and + <option>--vacuum-files=</option> may be combined in a single + invocation to enforce any combination of a size, a time and a + number of files limit on the archived journal + files. Specifying any of these three parameters as zero is + equivalent to not enforcing the specific limit, and is thus + redundant.</para></listitem> </varlistentry> <varlistentry> @@ -760,13 +772,19 @@ <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> </varlistentry> + <varlistentry> + <term><option>--rotate</option></term> + + <listitem><para>Asks the journal daemon to rotate journal files. + </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" /> diff --git a/man/journald.conf.xml b/man/journald.conf.xml index d6fe45d40c..a9690e8138 100644 --- a/man/journald.conf.xml +++ b/man/journald.conf.xml @@ -173,9 +173,11 @@ <term><varname>SystemMaxUse=</varname></term> <term><varname>SystemKeepFree=</varname></term> <term><varname>SystemMaxFileSize=</varname></term> + <term><varname>SystemMaxFiles=</varname></term> <term><varname>RuntimeMaxUse=</varname></term> <term><varname>RuntimeKeepFree=</varname></term> <term><varname>RuntimeMaxFileSize=</varname></term> + <term><varname>RuntimeMaxFiles=</varname></term> <listitem><para>Enforce size limits on the journal files stored. The options prefixed with <literal>System</literal> @@ -197,12 +199,11 @@ names not ending with <literal>.journal</literal> or <literal>.journal~</literal>, so only such files, located in the appropriate directories, are taken into account when - calculating current disk usage. - </para> + calculating current disk usage.</para> <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. @@ -210,31 +211,42 @@ and use the smaller of the two values.</para> <para>The first pair defaults to 10% and the second to 15% of - the size of the respective file system. If the file system is - nearly full and either <varname>SystemKeepFree=</varname> or - <varname>RuntimeKeepFree=</varname> is violated when - systemd-journald is started, the value will be raised to + the size of the respective file system, but each value is + capped to 4G. If the file system is nearly full and either + <varname>SystemKeepFree=</varname> or + <varname>RuntimeKeepFree=</varname> are violated when + systemd-journald is started, the limit will be raised to the percentage that is actually free. This means that if there was 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 go reduce footprint either.</para> + 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 <varname>SystemMaxUse=</varname> and <varname>RuntimeMaxUse=</varname>, so that usually seven - rotated journal files are kept as history.</para></listitem> + 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 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 + around in total than this limit after a vacuuming operation is + complete. This setting defaults to 100.</para></listitem> </varlistentry> <varlistentry> @@ -333,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> @@ -363,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 eb73727027..2f81746b5e 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -79,8 +79,9 @@ <term><varname>systemd.unit=</varname></term> <term><varname>rd.systemd.unit=</varname></term> <term><varname>systemd.dump_core=</varname></term> - <term><varname>systemd.crash_shell=</varname></term> <term><varname>systemd.crash_chvt=</varname></term> + <term><varname>systemd.crash_shell=</varname></term> + <term><varname>systemd.crash_reboot=</varname></term> <term><varname>systemd.confirm_spawn=</varname></term> <term><varname>systemd.show_status=</varname></term> <term><varname>systemd.log_target=</varname></term> 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-id.xml b/man/machine-id.xml index 92d67a3869..db72c2a01c 100644 --- a/man/machine-id.xml +++ b/man/machine-id.xml @@ -63,7 +63,7 @@ <para>The machine ID is usually generated from a random source during system installation and stays constant for all subsequent boots. Optionally, for stateless systems, it is generated during - runtime at boot if it is found to be empty.</para> + runtime at early boot if it is found to be empty.</para> <para>The machine ID does not change based on user configuration or when hardware is replaced.</para> @@ -119,7 +119,7 @@ id[8] = (id[8] & 0x3F) | 0x80;</programlisting> <filename>/etc/machine-id</filename> originates in the <filename>/var/lib/dbus/machine-id</filename> file introduced by D-Bus. In fact, this latter file might be a symlink to - <varname>/etc/machine-id</varname>.</para> + <filename>/etc/machine-id</filename>.</para> </refsect1> <refsect1> 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..d1da7f60a6 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> @@ -356,7 +356,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 +381,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 +414,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 +422,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 +433,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 +509,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 +526,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 +537,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 +552,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 +626,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 +656,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 +676,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 +698,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 +729,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 +801,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 +833,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 +847,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 +877,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 +914,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 +943,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 +956,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 +987,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 +1010,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 +1020,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/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 21c22a8f7c..3088243e45 100644 --- a/man/sd_bus_path_encode.xml +++ b/man/sd_bus_path_encode.xml @@ -44,7 +44,9 @@ <refnamediv> <refname>sd_bus_path_encode</refname> + <refname>sd_bus_path_encode_many</refname> <refname>sd_bus_path_decode</refname> + <refname>sd_bus_path_decode_many</refname> <refpurpose>Convert an external identifier into an object path and back</refpurpose> </refnamediv> @@ -61,11 +63,25 @@ </funcprototype> <funcprototype> + <funcdef>int <function>sd_bus_path_encode_many</function></funcdef> + <paramdef>char **<parameter>out</parameter></paramdef> + <paramdef>const char *<parameter>path_template</parameter></paramdef> + <paramdef>...</paramdef> + </funcprototype> + + <funcprototype> <funcdef>int <function>sd_bus_path_decode</function></funcdef> <paramdef>const char *<parameter>path</parameter></paramdef> <paramdef>const char *<parameter>prefix</parameter></paramdef> <paramdef>char **<parameter>ret_external_id</parameter></paramdef> </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_bus_path_decode_many</function></funcdef> + <paramdef>const char *<parameter>path</parameter></paramdef> + <paramdef>const char *<parameter>path_template</parameter></paramdef> + <paramdef>...</paramdef> + </funcprototype> </funcsynopsis> </refsynopsisdiv> @@ -109,6 +125,28 @@ invalid in a bus object path by <literal>_</literal>, followed by a hexadecimal value. As a special case, the empty string will be replaced by a lone <literal>_</literal>.</para> + + <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 + according to its embedded directives. For each + <literal>%</literal> character found in the template, the caller + 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 + template, the caller must provide an output storage + (<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 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> <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 9b9705eb2e..93bf8d853f 100644 --- a/man/sd_listen_fds.xml +++ b/man/sd_listen_fds.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"> @@ -45,6 +45,7 @@ <refnamediv> <refname>sd_listen_fds</refname> + <refname>sd_listen_fds_with_names</refname> <refname>SD_LISTEN_FDS_START</refname> <refpurpose>Check for file descriptors passed by the system manager</refpurpose> </refnamediv> @@ -59,23 +60,26 @@ <funcdef>int <function>sd_listen_fds</function></funcdef> <paramdef>int <parameter>unset_environment</parameter></paramdef> </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_listen_fds_with_names</function></funcdef> + <paramdef>int <parameter>unset_environment</parameter></paramdef> + <paramdef>char*** <parameter>names</parameter></paramdef> + </funcprototype> </funcsynopsis> </refsynopsisdiv> <refsect1> <title>Description</title> - <para><function>sd_listen_fds()</function> shall be called by a - daemon to check for file descriptors passed by the init system as - part of the socket-based activation logic.</para> - - <para>If the <parameter>unset_environment</parameter> parameter is - non-zero, <function>sd_listen_fds()</function> will unset the - <varname>$LISTEN_FDS</varname> and <varname>$LISTEN_PID</varname> - environment variables before returning (regardless of whether the - function call itself succeeded or not). Further calls to - <function>sd_listen_fds()</function> will then fail, but the - variables are no longer inherited by child processes.</para> + <para><function>sd_listen_fds()</function> may be invoked by a + 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 + at file descriptor number 3 + (i.e. <constant>SD_LISTEN_FDS_START</constant>), the remaining + descriptors follow at 4, 5, 6, ..., if any.</para> <para>If a daemon receives more than one file descriptor, they will be passed in the same order as configured in the systemd @@ -100,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 @@ -108,12 +112,86 @@ <literal>FDSTORE=1</literal> messages, these file descriptors are passed last, in arbitrary order, and with duplicates removed.</para> + + <para>If the <parameter>unset_environment</parameter> parameter is + non-zero, <function>sd_listen_fds()</function> will unset the + <varname>$LISTEN_FDS</varname>, <varname>$LISTEN_PID</varname> and + <varname>$LISTEN_FDNAMES</varname> environment variables before + returning (regardless of whether the function call itself + succeeded or not). Further calls to + <function>sd_listen_fds()</function> will then return zero, but the + 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 + an array of strings with identification names for the passed file + 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 + socket-activated services, these names may be configured with the + <varname>FileDescriptorName=</varname> setting in socket unit + 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 + <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 + descriptors which are not recognizable with functions like + <function>sd_is_socket()</function> alone, and thus require + identification via a name. It is recommended to rely on named file + descriptors only if identification via + <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 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 + <function>sd_listen_fds()</function>.</para> + + <para>Under specific conditions, the following automatic file + descriptor names are returned: + + <table> + <title> + <command>Special names</command> + </title> + + <tgroup cols='2'> + <thead> + <row> + <entry>Name</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry><literal>unknown</literal></entry> + <entry>The process received no name for the specific file descriptor from the service manager.</entry> + </row> + + <row> + <entry><literal>stored</literal></entry> + <entry>The file descriptor originates in the service manager's per-service file descriptor store, and the <varname>FDNAME=</varname> field was absent when the file descriptor was submitted to the service manager.</entry> + </row> + + <row> + <entry><literal>connection</literal></entry> + <entry>The service was activated in per-connection style using <varname>Accept=yes</varname> in the socket unit file, and the file descriptor is the connection socket.</entry> + </row> + </tbody> + </tgroup> + </table> + </para> </refsect1> <refsect1> <title>Return Value</title> - <para>On failure, this call returns a negative errno-style error + <para>On failure, these calls returns a negative errno-style error code. If <varname>$LISTEN_FDS</varname>/<varname>$LISTEN_PID</varname> was not set or was not correctly set for this daemon and hence no file @@ -128,13 +206,16 @@ <xi:include href="libsystemd-pkgconfig.xml" xpointer="pkgconfig-text"/> - <para>Internally, this function checks whether the - <varname>$LISTEN_PID</varname> environment variable equals the - daemon PID. If not, it returns immediately. Otherwise, it parses - the number passed in the <varname>$LISTEN_FDS</varname> + <para>Internally, <function>sd_listen_fds()</function> checks + whether the <varname>$LISTEN_PID</varname> environment variable + equals the daemon PID. If not, it returns immediately. Otherwise, + it parses the number passed in the <varname>$LISTEN_FDS</varname> environment variable, then sets the FD_CLOEXEC flag for the parsed number of file descriptors starting from SD_LISTEN_FDS_START. - Finally, it returns the parsed number.</para> + Finally, it returns the parsed + number. <function>sd_listen_fds_with_names()</function> does the + same but also parses <varname>$LISTEN_FDNAMES</varname> if + set.</para> </refsect1> <refsect1> @@ -144,15 +225,14 @@ <varlistentry> <term><varname>$LISTEN_PID</varname></term> <term><varname>$LISTEN_FDS</varname></term> + <term><varname>$LISTEN_FDNAMES</varname></term> - <listitem><para>Set by the init system - for supervised processes that use - socket-based activation. This - environment variable specifies the - data - <function>sd_listen_fds()</function> - parses. See above for - details.</para></listitem> + <listitem><para>Set by the service manager for supervised + processes that use socket-based activation. This environment + variable specifies the data + <function>sd_listen_fds()</function> and + <function>sd_listen_fds_with_names()</function> parses. See + above for details.</para></listitem> </varlistentry> </variablelist> </refsect1> @@ -167,6 +247,7 @@ <citerefentry><refentrytitle>sd_is_socket</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_is_socket_inet</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_is_socket_unix</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_pid_notify_with_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry> 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 14030f56b1..dbf6330453 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.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"> @@ -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> @@ -229,6 +229,27 @@ below.</para></listitem> </varlistentry> + <varlistentry> + <term>FDNAME=...</term> + + <listitem><para>When used in combination with + <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 + 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 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> + </varlistentry> + </variablelist> <para>It is recommended to prefix variable names that are not @@ -253,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> @@ -290,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 @@ -356,9 +377,9 @@ <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", &fd, 1);</programlisting> + <programlisting>sd_pid_notify_with_fds(0, 0, "FDSTORE=1\nFDNAME=foobar", &fd, 1);</programlisting> </example> </refsect1> @@ -367,9 +388,11 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> </para> </refsect1> 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 c1359d1678..2fe24fd139 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -101,10 +101,14 @@ <term><option>--state=</option></term> <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> - to show only failed units.</para> + <para>The argument should be a comma-separated list of unit + LOAD, SUB, or ACTIVE states. When listing units, show only + 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 + <option>help</option>, a list of allowed values will be + printed and the program will exit.</para> </listitem> </varlistentry> @@ -130,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>, @@ -355,7 +359,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> @@ -454,7 +458,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> @@ -514,7 +518,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> @@ -596,7 +600,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> @@ -825,7 +831,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>, @@ -845,7 +851,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 @@ -977,7 +983,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> @@ -1120,9 +1126,9 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <tgroup cols='3'> <thead> <row> - <entry>Printed string</entry> - <entry>Meaning</entry> - <entry>Return value</entry> + <entry>Name</entry> + <entry>Description</entry> + <entry>Exit Code</entry> </row> </thead> <tbody> @@ -1137,7 +1143,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <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'>1</entry> + <entry morerows='1'>> 0</entry> </row> <row> <entry><literal>linked-runtime</literal></entry> @@ -1145,25 +1151,25 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <row> <entry><literal>masked</literal></entry> <entry morerows='1'>Disabled entirely (permanently or just in <filename>/run</filename>).</entry> - <entry morerows='1'>1</entry> + <entry morerows='1'>> 0</entry> </row> <row> <entry><literal>masked-runtime</literal></entry> </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>1</entry> + <entry>The unit file is not enabled.</entry> + <entry>> 0</entry> </row> </tbody> </tgroup> @@ -1221,12 +1227,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> @@ -1242,8 +1248,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> @@ -1255,8 +1261,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>). @@ -1264,7 +1270,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> @@ -1436,7 +1442,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 @@ -1474,22 +1480,25 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <listitem> <para>Checks whether the system is operational. This - returns success when the system is fully up and running, - meaning not in startup, shutdown or maintenance - mode. Failure is returned otherwise. In addition, the + returns success (exit code 0) when the system is fully up + and running, specifically not in startup, shutdown or + 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> - <title>Manager Operational States</title> - <tgroup cols='2'> - <colspec colname='name' /> - <colspec colname='description' /> + <title><command>is-system-running</command> output</title> + <tgroup cols='3'> + <colspec colname='name'/> + <colspec colname='description'/> + <colspec colname='exit-code'/> <thead> <row> <entry>Name</entry> <entry>Description</entry> + <entry>Exit Code</entry> </row> </thead> <tbody> @@ -1499,32 +1508,53 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <filename>basic.target</filename> is reached or the <varname>maintenance</varname> state entered. </para></entry> + <entry>> 0</entry> </row> <row> <entry><varname>starting</varname></entry> <entry><para>Late bootup, before the job queue becomes idle for the first time, or one of the rescue targets are reached.</para></entry> + <entry>> 0</entry> </row> <row> <entry><varname>running</varname></entry> <entry><para>The system is fully operational.</para></entry> + <entry>0</entry> </row> <row> <entry><varname>degraded</varname></entry> <entry><para>The system is operational but one or more units failed.</para></entry> + <entry>> 0</entry> </row> <row> <entry><varname>maintenance</varname></entry> <entry><para>The rescue or emergency target is active.</para></entry> + <entry>> 0</entry> </row> <row> <entry><varname>stopping</varname></entry> <entry><para>The manager is shutting down.</para></entry> + <entry>> 0</entry> + </row> + <row> + <entry><varname>offline</varname></entry> + <entry><para>The manager is not + running. Specifically, this is the operational + state if an incompatible program is running as + system manager (PID 1).</para></entry> + <entry>> 0</entry> + </row> + <row> + <entry><varname>unknown</varname></entry> + <entry><para>The operational state could not be + determined, due to lack of resources or another + error cause.</para></entry> + <entry>> 0</entry> </row> </tbody> </tgroup> @@ -1654,7 +1684,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 3b854fd8ec..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> @@ -115,6 +115,16 @@ </para></listitem> </varlistentry> + <varlistentry> + <term><option>--fdname=</option><replaceable>NAME</replaceable></term> + + <listitem><para>Specify a name for the activation file + descriptors. This is equivalent to setting + <varname>FileDescriptorName=</varname> in socket unit files, and + enables use of + <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + </varlistentry> + <xi:include href="standard-options.xml" xpointer="help" /> <xi:include href="standard-options.xml" xpointer="version" /> </variablelist> @@ -126,6 +136,7 @@ <varlistentry> <term><varname>$LISTEN_FDS</varname></term> <term><varname>$LISTEN_PID</varname></term> + <term><varname>$LISTEN_FDNAMES</varname></term> <listitem><para>See <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> @@ -153,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> @@ -165,6 +176,8 @@ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>cat</refentrytitle><manvolnum>1</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 198315052f..f55c6fb7f3 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -93,7 +93,13 @@ <command>systemd-analyze</command> <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="plain">set-log-level</arg> - <arg choice="opt"><replaceable>LEVEL</replaceable></arg> + <arg choice="plain"><replaceable>LEVEL</replaceable></arg> + </cmdsynopsis> + <cmdsynopsis> + <command>systemd-analyze</command> + <arg choice="opt" rep="repeat">OPTIONS</arg> + <arg choice="plain">set-log-target</arg> + <arg choice="plain"><replaceable>TARGET</replaceable></arg> </cmdsynopsis> <cmdsynopsis> <command>systemd-analyze</command> @@ -168,6 +174,13 @@ <option>--log-level=</option> described in <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para> + <para><command>systemd-analyze set-log-target + <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 + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para> + <para><command>systemd-analyze verify</command> will load unit files and print warnings if any errors are detected. Files specified on the command line will be loaded, but also any other diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml index 877c71af53..6fb322e849 100644 --- a/man/systemd-ask-password.xml +++ b/man/systemd-ask-password.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"> @@ -72,17 +72,28 @@ plugged in or at boot, entering an SSL certificate passphrase for web and VPN servers.</para> - <para>Existing agents are: a boot-time password agent asking the - user for passwords using Plymouth; a boot-time password agent - querying the user directly on the console; an agent requesting - password input via a - <citerefentry project='man-pages'><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry> - message; an agent suitable for running in a GNOME session; a - command line agent which can be started temporarily to process - queued password requests; a TTY agent that is temporarily spawned - during - <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> - invocations.</para> + <para>Existing agents are: + <itemizedlist> + + <listitem><para>A boot-time password agent asking the user for + passwords using Plymouth</para></listitem> + + <listitem><para>A boot-time password agent querying the user + directly on the console</para></listitem> + + <listitem><para>An agent requesting password input via a + <citerefentry + project='man-pages'><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry> + message</para></listitem> + + <listitem><para>A command line agent which can be started + temporarily to process queued password + requests</para></listitem> + + <listitem><para>A TTY agent that is temporarily spawned during + <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> + invocations</para></listitem> + </itemizedlist></para> <para>Additional password agents may be implemented according to the <ulink @@ -112,6 +123,38 @@ </varlistentry> <varlistentry> + <term><option>--id=</option></term> + <listitem><para>Specify an identifier for this password + query. This identifier is freely choosable and allows + recognition of queries by involved agents. It should include + the subsystem doing the query and the specific object the + query is done for. Example: + <literal>--id=cryptsetup:/dev/sda5</literal>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><option>--keyname=</option></term> + <listitem><para>Configure a kernel keyring key name to use as + 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 + 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 + cached key will have a timeout of 2.5min set, after which it + will be purged from the kernel keyring. Note that it is + possible to cache multiple passwords under the same keyname, + in which case they will be stored as NUL-separated list of + passwords. Use + <citerefentry><refentrytitle>keyctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> + to access the cached key via the kernel keyring + directly. Example: <literal>--keyname=cryptsetup</literal></para></listitem> + </varlistentry> + + <varlistentry> <term><option>--timeout=</option></term> <listitem><para>Specify the query timeout in seconds. Defaults @@ -138,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> @@ -166,6 +209,7 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>keyctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry project='die-net'><refentrytitle>plymouth</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>wall</refentrytitle><manvolnum>1</manvolnum></citerefentry> </para> 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..3997e10c43 100644 --- a/man/systemd-detect-virt.xml +++ b/man/systemd-detect-virt.xml @@ -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> @@ -139,7 +139,7 @@ </row> <row> - <entry morerows="5">container</entry> + <entry morerows="5">Container</entry> <entry><varname>openvz</varname></entry> <entry>OpenVZ/Virtuozzo</entry> </row> @@ -163,6 +163,11 @@ <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> </table> @@ -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 dae6ee6042..21fd684b8b 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> @@ -99,7 +101,10 @@ reboot. To make the data persistent, it is sufficient to create <filename>/var/log/journal/</filename> where <filename>systemd-journald</filename> will then store the - data.</para> + data:</para> + + <programlisting>mkdir -p /var/log/journal +systemd-tmpfiles --create --prefix /var/log/journal</programlisting> <para><filename>systemd-journald</filename> will forward all received log messages to the @@ -227,7 +232,20 @@ <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> diff --git a/man/systemd-machine-id-commit.service.xml b/man/systemd-machine-id-commit.service.xml index 7c8fc0874e..39da1922cc 100644 --- a/man/systemd-machine-id-commit.service.xml +++ b/man/systemd-machine-id-commit.service.xml @@ -42,55 +42,50 @@ <refnamediv> <refname>systemd-machine-id-commit.service</refname> - <refpurpose>Commit transient machine-id to disk</refpurpose> + <refpurpose>Commit a transient machine ID to disk</refpurpose> </refnamediv> <refsynopsisdiv> <para><filename>systemd-machine-id-commit.service</filename></para> - <para><filename>/usr/lib/systemd/systemd-machine-id-commit</filename></para> </refsynopsisdiv> <refsect1> <title>Description</title> - <para><filename>systemd-machine-id-commit.service</filename> is a - service responsible for committing any transient - <filename>/etc/machine-id</filename> file to a writable file + <para><filename>systemd-machine-id-commit.service</filename> is an + 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> - for more information about this file.</para> - - <para>This service is started shortly after - <filename>local-fs.target</filename> if - <filename>/etc/machine-id</filename> is an independent mount point - (probably a tmpfs one) and /etc is writable. - <command>systemd-machine-id-commit</command> will then write - current machine ID to disk and unmount the transient + for more information about machine IDs.</para> + + <para>This service is started after + <filename>local-fs.target</filename> in case + <filename>/etc/machine-id</filename> is a mount point of its own + (usually from a memory file system such as + <literal>tmpfs</literal>) and /etc is writable. The service will + invoke <command>systemd-machine-id-setup --commit</command>, which + writes the current transient machine ID to disk and unmount the <filename>/etc/machine-id</filename> file in a race-free manner to - ensure that file is always valid for other processes.</para> - - <para>Note that the traditional way to initialize the machine ID - in <filename>/etc/machine-id</filename> is to use - <command>systemd-machine-id-setup</command> by system installer - tools. You can also use - <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> - to initialize the machine ID on mounted (but not booted) system - images. The main use case for that service is - <filename>/etc/machine-id</filename> being an empty file at boot - and initrd chaining to systemd giving it a read only file system - that will be turned read-write later during the boot - process.</para> - - <para>There is no consequence if that service fails other than a - newer machine-id will be generated during next system boot. - </para> + ensure that file is always valid and accessible for other + processes. See + <citerefentry><refentrytitle>systemd-machine-id-setup</refentrytitle><manvolnum>1</manvolnum></citerefentry> + for details.</para> + + <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 + 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 + as <filename>/etc</filename> has been remounted writable and the + ID may thus be committed to disk to make it permanent.</para> </refsect1> <refsect1> <title>See Also</title> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-machine-id-commit</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-machine-id-setup</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> diff --git a/man/systemd-machine-id-commit.xml b/man/systemd-machine-id-commit.xml deleted file mode 100644 index d216aa0745..0000000000 --- a/man/systemd-machine-id-commit.xml +++ /dev/null @@ -1,123 +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 2014 Didier Roche - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. ---> - -<refentry id="systemd-machine-id-commit" - xmlns:xi="http://www.w3.org/2001/XInclude"> - - <refentryinfo> - <title>systemd-machine-id-commit</title> - <productname>systemd</productname> - - <authorgroup> - <author> - <contrib>Developer</contrib> - <firstname>Didier</firstname> - <surname>Roche</surname> - <email>didrocks@ubuntu.com</email> - </author> - </authorgroup> - </refentryinfo> - - <refmeta> - <refentrytitle>systemd-machine-id-commit</refentrytitle> - <manvolnum>1</manvolnum> - </refmeta> - - <refnamediv> - <refname>systemd-machine-id-commit</refname> - <refpurpose>Commit transient machine ID to /etc/machine-id</refpurpose> - </refnamediv> - - <refsynopsisdiv> - <cmdsynopsis> - <command>systemd-machine-id-commit</command> - </cmdsynopsis> - </refsynopsisdiv> - - <refsect1> - <title>Description</title> - - <para><command>systemd-machine-id-commit</command> may be used to - write on disk any transient machine ID mounted as a temporary file - system in <filename>/etc/machine-id</filename> at boot time. See - <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> - for more information about this file.</para> - - <para>This tool will execute no operation if - <filename>/etc/machine-id</filename> doesn't contain any valid - machine ID, isn't mounted as an independent temporary file system, - or <filename>/etc</filename> is read-only. If those conditions are - met, it will then write current machine ID to disk and unmount the - transient <filename>/etc/machine-id</filename> file in a race-free - manner to ensure that this file is always valid for other - processes.</para> - - <para>Note that the traditional way to initialize the machine ID - in <filename>/etc/machine-id</filename> is to use - <command>systemd-machine-id-setup</command> by system installer - tools. You can also use - <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> - to initialize the machine ID on mounted (but not booted) system - images.</para> - </refsect1> - - <refsect1> - <title>Options</title> - - <para>The following options are understood:</para> - - <variablelist> - <varlistentry> - <term><option>--root=<replaceable>root</replaceable></option></term> - <listitem><para>Takes a directory path - as an argument. All paths will be - prefixed with the given alternate - <replaceable>root</replaceable> path, - including config search paths. - </para></listitem> - </varlistentry> - <xi:include href="standard-options.xml" xpointer="help" /> - <xi:include href="standard-options.xml" xpointer="version" /> - </variablelist> - - </refsect1> - - <refsect1> - <title>Exit status</title> - - <para>On success, 0 is returned, a non-zero failure code - otherwise.</para> - </refsect1> - - <refsect1> - <title>See Also</title> - <para> - <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-machine-id-commit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-machine-id-setup</refentrytitle><manvolnum>1</manvolnum></citerefentry>, - <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> - </para> - </refsect1> - -</refentry> diff --git a/man/systemd-machine-id-setup.xml b/man/systemd-machine-id-setup.xml index 182717f524..bfcd74f436 100644 --- a/man/systemd-machine-id-setup.xml +++ b/man/systemd-machine-id-setup.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"> @@ -35,6 +35,12 @@ <surname>Poettering</surname> <email>lennart@poettering.net</email> </author> + <author> + <contrib>Developer</contrib> + <firstname>Didier</firstname> + <surname>Roche</surname> + <email>didrocks@ubuntu.com</email> + </author> </authorgroup> </refentryinfo> @@ -59,30 +65,43 @@ <para><command>systemd-machine-id-setup</command> may be used by system installer tools to initialize the machine ID stored in - <filename>/etc/machine-id</filename> at install time with a - randomly generated ID. See + <filename>/etc/machine-id</filename> at install time, with a + provisioned or randomly generated ID. See <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> for more information about this file.</para> - <para>This tool will execute no operation if - <filename>/etc/machine-id</filename> is already - initialized.</para> - - <para>If a valid D-Bus machine ID is already configured for the - system, the D-Bus machine ID is copied and used to initialize the - machine ID in <filename>/etc/machine-id</filename>.</para> - - <para>If run inside a KVM virtual machine and a UUID is passed via - the <option>-uuid</option> option, this UUID is used to initialize - the machine ID instead of a randomly generated one. The caller - must ensure that the UUID passed is sufficiently unique and is - different for every booted instanced of the VM.</para> - - <para>Similar, if run inside a Linux container environment and a - UUID is set 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> + <para>If the tool is invoked without the <option>--commit</option> + 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> + + <orderedlist> + <listitem><para>If a valid D-Bus machine ID is already + configured for the system, the D-Bus machine ID is copied and + used to initialize the machine ID in + <filename>/etc/machine-id</filename>.</para></listitem> + + <listitem><para>If run inside a KVM virtual machine and a UUID + is was configured (via the <option>-uuid</option> + option), this UUID is used to initialize the machine ID. The + caller must ensure that the UUID passed is sufficiently unique + and is different for every booted instance of the + VM.</para></listitem> + + <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 + generated.</para></listitem> + </orderedlist> + + <para>The <option>--commit</option> switch may be used to commit a + transient machined ID to disk, making it persistent. For details, + see below.</para> <para>Use <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> @@ -97,13 +116,41 @@ <para>The following options are understood:</para> <variablelist> + <varlistentry> <term><option>--root=<replaceable>root</replaceable></option></term> - <listitem><para>Takes a directory path as an argument. All - paths will be prefixed with the given alternate - <replaceable>root</replaceable> path, including config search - paths. </para></listitem> + <listitem><para>Takes a directory path as argument. All paths + operated will be prefixed with the given alternate + <replaceable>root</replaceable> path, including the path for + <filename>/etc/machine-id</filename> itself.</para></listitem> </varlistentry> + + <varlistentry> + <term><option>--commit</option></term> + <listitem><para>Commit a transient machine ID to disk. This + command may be used to convert a transient machine ID into a + persistent one. A transient machine ID file is one that was + bind mounted from a memory file system (usually + <literal>tmpfs</literal>) to + <filename>/etc/machine-id</filename> during the early phase of + the boot process. This may happen because + <filename>/etc</filename> is initially read-only and was + missing a valid machine ID file at that point.</para> + + <para>This command will execute no operation if + <filename>/etc/machine-id</filename> is not mounted from a + memory file system, or if <filename>/etc</filename> is + read-only. The command will write the current transient + machine ID to disk and unmount the + <filename>/etc/machine-id</filename> mount point in a + race-free manner to ensure that this file is always valid and + accessible for other processes.</para> + + <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> + </varlistentry> + <xi:include href="standard-options.xml" xpointer="help" /> <xi:include href="standard-options.xml" xpointer="version" /> </variablelist> @@ -122,6 +169,7 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd-machine-id-commit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, <citerefentry project='dbus'><refentrytitle>dbus-uuidgen</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry> </para> 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 06d5ae5319..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 @@ -124,7 +124,12 @@ systemd, non-zero otherwise. If this option is passed, no 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>.</para></listitem> + <citerefentry><refentrytitle>sd_booted</refentrytitle><manvolnum>3</manvolnum></citerefentry>. An + 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 + with systemd. </para></listitem> </varlistentry> <xi:include href="standard-options.xml" xpointer="help" /> @@ -156,12 +161,12 @@ mkfifo /tmp/waldo systemd-notify --ready --status="Waiting for data..." while : ; do - read a < /tmp/waldo - systemd-notify --status="Processing $a" + read a < /tmp/waldo + systemd-notify --status="Processing $a" - # Do something with $a ... + # Do something with $a ... - systemd-notify --status="Waiting for data..." + systemd-notify --status="Waiting for data..." done</programlisting> </example> </refsect1> diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 4b0e72113e..4725604c03 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> @@ -458,7 +458,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 +575,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 +599,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 +630,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 +693,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 +752,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 +786,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 +850,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-rfkill@.service.xml b/man/systemd-rfkill.service.xml index 709b09d818..f464842700 100644 --- a/man/systemd-rfkill@.service.xml +++ b/man/systemd-rfkill.service.xml @@ -19,10 +19,10 @@ 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-rfkill@.service" conditional='ENABLE_RFKILL'> +<refentry id="systemd-rfkill.service" conditional='ENABLE_RFKILL'> <refentryinfo> - <title>systemd-rfkill@.service</title> + <title>systemd-rfkill.service</title> <productname>systemd</productname> <authorgroup> @@ -36,27 +36,29 @@ </refentryinfo> <refmeta> - <refentrytitle>systemd-rfkill@.service</refentrytitle> + <refentrytitle>systemd-rfkill.service</refentrytitle> <manvolnum>8</manvolnum> </refmeta> <refnamediv> - <refname>systemd-rfkill@.service</refname> + <refname>systemd-rfkill.service</refname> + <refname>systemd-rfkill.socket</refname> <refname>systemd-rfkill</refname> - <refpurpose>Load and save the RF kill switch state at boot and shutdown</refpurpose> + <refpurpose>Load and save the RF kill switch state at boot and change</refpurpose> </refnamediv> <refsynopsisdiv> - <para><filename>systemd-rfkill@.service</filename></para> + <para><filename>systemd-rfkill.service</filename></para> + <para><filename>systemd-rfkill.socket</filename></para> <para><filename>/usr/lib/systemd/systemd-rfkill</filename></para> </refsynopsisdiv> <refsect1> <title>Description</title> - <para><filename>systemd-rfkill@.service</filename> is a service + <para><filename>systemd-rfkill.service</filename> is a service that restores the RF kill switch state at early boot and saves it - at shutdown. On disk, the RF kill switch state is stored in + on each change. On disk, the RF kill switch state is stored in <filename>/var/lib/systemd/rfkill/</filename>.</para> </refsect1> 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 d4c1a7ebe3..55c8953722 100644 --- a/man/systemd-sysctl.service.xml +++ b/man/systemd-sysctl.service.xml @@ -54,7 +54,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 a4ba0959ea..54ce992b85 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -90,9 +90,10 @@ <term><varname>LogColor=</varname></term> <term><varname>LogLocation=</varname></term> <term><varname>DumpCore=yes</varname></term> + <term><varname>CrashChangeVT=no</varname></term> <term><varname>CrashShell=no</varname></term> + <term><varname>CrashReboot=no</varname></term> <term><varname>ShowStatus=yes</varname></term> - <term><varname>CrashChVT=1</varname></term> <term><varname>DefaultStandardOutput=journal</varname></term> <term><varname>DefaultStandardError=inherit</varname></term> @@ -108,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> @@ -339,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..26a0f291dd 100644 --- a/man/systemd.automount.xml +++ b/man/systemd.automount.xml @@ -137,7 +137,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.exec.xml b/man/systemd.exec.xml index 7633948645..96298f11ed 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -84,22 +84,27 @@ <varlistentry> <term><varname>WorkingDirectory=</varname></term> - <listitem><para>Takes an absolute directory path. Sets the - working directory for executed processes. 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.</para></listitem> + <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 + 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> </varlistentry> <varlistentry> <term><varname>RootDirectory=</varname></term> <listitem><para>Takes an absolute directory path. Sets the - root directory for executed processes, with the - <citerefentry project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry> + root directory for executed processes, with the <citerefentry + project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call. If this is used, it must be ensured that the - process and all its auxiliary files are available in the - <function>chroot()</function> jail.</para></listitem> + process binary and all its auxiliary files are available in + the <function>chroot()</function> jail.</para></listitem> </varlistentry> <varlistentry> @@ -118,8 +123,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 @@ -152,7 +157,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 @@ -163,10 +168,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> @@ -212,8 +217,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 @@ -235,7 +242,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 @@ -486,7 +493,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>, @@ -505,7 +512,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 @@ -561,7 +568,9 @@ 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).</para></listitem> <table> <title>Limit directives and their equivalent with ulimit</title> @@ -678,7 +687,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. @@ -699,7 +708,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> @@ -740,7 +749,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 @@ -843,7 +852,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 @@ -944,15 +953,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> @@ -987,7 +996,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 @@ -1043,7 +1052,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> @@ -1079,7 +1088,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>, 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.journal-fields.xml b/man/systemd.journal-fields.xml index 49f44d2922..494f97aad1 100644 --- a/man/systemd.journal-fields.xml +++ b/man/systemd.journal-fields.xml @@ -258,6 +258,16 @@ <variablelist> <varlistentry> <term> + <option>audit</option> + </term> + <listitem> + <para>for those read from the kernel audit subsystem + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term> <option>driver</option> </term> <listitem> 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 b630ef7a17..29b837834c 100644 --- a/man/systemd.link.xml +++ b/man/systemd.link.xml @@ -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,11 +228,17 @@ <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> </varlistentry> + <varlistentry> + <term><literal>none</literal></term> + <listitem> + <para>Keeps the MAC address assigned by the kernel.</para> + </listitem> + </varlistentry> </variablelist> </listitem> </varlistentry> @@ -383,7 +389,7 @@ <refsect1> <title>Example</title> <example> - <title>/etc/systemd/network/wireless.link</title> + <title>/etc/systemd/network/25-wireless.link</title> <programlisting>[Match] MACAddress=12:34:56:78:9a:bc diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index ffffc56936..dd6b7a51a8 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -180,7 +180,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 +192,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 +212,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 +220,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 @@ -324,6 +324,18 @@ </varlistentry> <varlistentry> + <term><varname>SmackFileSystemRootLabel=</varname></term> + <listitem><para>Takes a string for the SMACK label. + This option specifies the label to assign the root of the + file system if it lacks the SMACK extended attribute. + Note that this option will be ignored if kernel does not + support the SMACK feature. + See <ulink + url="https://www.kernel.org/doc/Documentation/security/Smack.txt">Smack.txt</ulink> + for details. </para></listitem> + </varlistentry> + + <varlistentry> <term><varname>TimeoutSec=</varname></term> <listitem><para>Configures the time to wait for the mount command to finish. If a command does not exit within the diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 05bbad7f65..76dee8ea34 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> @@ -277,6 +277,43 @@ </variablelist> </refsect1> + <refsect1> + <title>[Bridge] Section Options</title> + + <para>The <literal>[Bridge]</literal> section only applies for + netdevs of kind <literal>bridge</literal>, and accepts the + following keys:</para> + + <variablelist class='network-directives'> + <varlistentry> + <term><varname>HelloTimeSec=</varname></term> + <listitem> + <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> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>MaxAgeSec=</varname></term> + <listitem> + <para>MaxAgeSec specifies the number of seconds of maximum message age. + If the last seen (received) hello packet is more than this number of + seconds old, the bridge in question will start the takeover procedure + in attempt to become the Root Bridge itself.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>ForwardDelaySec=</varname></term> + <listitem> + <para>ForwardDelaySec specifies the number of seconds spent in each + of the Listening and Learning states before the Forwarding state is entered.</para> + </listitem> + </varlistentry> + </variablelist> + + </refsect1> + <refsect1> <title>[VLAN] Section Options</title> @@ -377,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> @@ -393,13 +430,13 @@ <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>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> @@ -412,40 +449,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> @@ -486,7 +523,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> @@ -496,9 +533,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> @@ -512,14 +549,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> @@ -543,14 +580,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 @@ -565,7 +602,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> @@ -578,7 +615,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> @@ -614,7 +651,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> @@ -740,9 +777,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> @@ -751,8 +788,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> @@ -760,13 +797,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> @@ -780,8 +817,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> @@ -801,7 +838,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. @@ -816,8 +853,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> @@ -831,8 +868,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> @@ -843,7 +880,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> @@ -853,10 +890,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> @@ -866,11 +903,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> @@ -879,8 +916,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 @@ -909,7 +946,7 @@ <refsect1> <title>Example</title> <example> - <title>/etc/systemd/network/bridge.netdev</title> + <title>/etc/systemd/network/25-bridge.netdev</title> <programlisting>[NetDev] Name=bridge0 @@ -917,7 +954,7 @@ Kind=bridge</programlisting> </example> <example> - <title>/etc/systemd/network/vlan1.netdev</title> + <title>/etc/systemd/network/25-vlan1.netdev</title> <programlisting>[Match] Virtualization=no @@ -930,7 +967,7 @@ Kind=vlan Id=1</programlisting> </example> <example> - <title>/etc/systemd/network/ipip.netdev</title> + <title>/etc/systemd/network/25-ipip.netdev</title> <programlisting>[NetDev] Name=ipip-tun Kind=ipip @@ -942,7 +979,7 @@ Remote=192.169.224.239 TTL=64</programlisting> </example> <example> - <title>/etc/systemd/network/tap.netdev</title> + <title>/etc/systemd/network/25-tap.netdev</title> <programlisting>[NetDev] Name=tap-test Kind=tap @@ -952,7 +989,7 @@ MultiQueue=true PacketInfo=true</programlisting> </example> <example> - <title>/etc/systemd/network/sit.netdev</title> + <title>/etc/systemd/network/25-sit.netdev</title> <programlisting>[NetDev] Name=sit-tun Kind=sit @@ -964,7 +1001,7 @@ Remote=10.65.223.239</programlisting> </example> <example> - <title>/etc/systemd/network/gre.netdev</title> + <title>/etc/systemd/network/25-gre.netdev</title> <programlisting>[NetDev] Name=gre-tun Kind=gre @@ -976,7 +1013,7 @@ Remote=10.65.223.239</programlisting> </example> <example> - <title>/etc/systemd/network/vti.netdev</title> + <title>/etc/systemd/network/25-vti.netdev</title> <programlisting>[NetDev] Name=vti-tun @@ -989,7 +1026,7 @@ Remote=10.65.223.239</programlisting> </example> <example> - <title>/etc/systemd/network/veth.netdev</title> + <title>/etc/systemd/network/25-veth.netdev</title> <programlisting>[NetDev] Name=veth-test Kind=veth @@ -999,7 +1036,7 @@ Name=veth-peer</programlisting> </example> <example> - <title>/etc/systemd/network/bond.netdev</title> + <title>/etc/systemd/network/25-bond.netdev</title> <programlisting>[NetDev] Name=bond1 Kind=bond @@ -1013,7 +1050,7 @@ LACPTransmitRate=fast </example> <example> - <title>/etc/systemd/network/dummy.netdev</title> + <title>/etc/systemd/network/25-dummy.netdev</title> <programlisting>[NetDev] Name=dummy-test Kind=dummy diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 629088ea81..50f3810ce0 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,7 @@ <literal>yes</literal>, <literal>no</literal>, <literal>ipv4</literal>, or <literal>ipv6</literal>.</para> - <para>Please note that by default the domain name + <para>Please 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 +263,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 +271,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> @@ -357,7 +357,7 @@ <varlistentry> <term><varname>IPForward=</varname></term> <listitem><para>Configures IP forwarding for the network - interface. If enabled incoming packets on 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>, @@ -384,7 +384,7 @@ <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 +398,37 @@ 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. + 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> @@ -519,7 +535,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,24 +543,32 @@ <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> </varlistentry> + <varlistentry> + <term><varname>PreferredSource=</varname></term> + <listitem> + <para>The preferred source address of the route. The address + must be in the format described in + <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + </listitem> + </varlistentry> </variablelist> </refsect1> @@ -624,7 +648,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> @@ -701,7 +725,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 @@ -717,7 +741,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 @@ -737,7 +761,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 @@ -746,9 +770,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> @@ -759,7 +783,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 @@ -778,7 +802,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> @@ -820,7 +844,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> @@ -836,7 +860,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> @@ -861,8 +885,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> @@ -893,7 +917,7 @@ DHCP=yes</programlisting> </example> <example> - <title>/etc/systemd/network/bridge-static.network</title> + <title>/etc/systemd/network/25-bridge-static.network</title> <programlisting>[Match] Name=bridge0 @@ -905,7 +929,7 @@ DNS=192.168.0.1</programlisting> </example> <example> - <title>/etc/systemd/network/bridge-slave-interface.network</title> + <title>/etc/systemd/network/25-bridge-slave-interface.network</title> <programlisting>[Match] Name=enp2s0 @@ -914,7 +938,7 @@ Name=enp2s0 Bridge=bridge0</programlisting> </example> <example> - <title>/etc/systemd/network/ipip.network</title> + <title>/etc/systemd/network/25-ipip.network</title> <programlisting>[Match] Name=em1 @@ -924,7 +948,7 @@ Tunnel=ipip-tun</programlisting> </example> <example> - <title>/etc/systemd/network/sit.network</title> + <title>/etc/systemd/network/25-sit.network</title> <programlisting>[Match] Name=em1 @@ -934,7 +958,7 @@ Tunnel=sit-tun</programlisting> </example> <example> - <title>/etc/systemd/network/gre.network</title> + <title>/etc/systemd/network/25-gre.network</title> <programlisting>[Match] Name=em1 @@ -944,7 +968,7 @@ Tunnel=gre-tun</programlisting> </example> <example> - <title>/etc/systemd/network/vti.network</title> + <title>/etc/systemd/network/25-vti.network</title> <programlisting>[Match] Name=em1 @@ -954,7 +978,7 @@ Tunnel=vti-tun</programlisting> </example> <example> - <title>/etc/systemd/network/bond.network</title> + <title>/etc/systemd/network/25-bond.network</title> <programlisting>[Match] Name=bond1 diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 7bfafb424f..c2b7a40ec1 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 @@ -326,7 +326,7 @@ <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 +337,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.resource-control.xml b/man/systemd.resource-control.xml index 98f4d75ddb..164adb938a 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -189,7 +189,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 +226,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 +240,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 +255,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 +281,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 +305,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 +412,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 +457,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.service.xml b/man/systemd.service.xml index 642d95a029..4e5098f0e1 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -254,7 +254,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,11 +283,11 @@ <term><varname>ExecStart=</varname></term> <listitem><para>Commands with their arguments that are executed when this service is started. The value is split into - zero or more command lines is according to the rules described + zero or more command lines according to the rules described below (see section "Command Lines" below). </para> - <para>When <varname>Type</varname> is not + <para>When <varname>Type=</varname> is not <option>oneshot</option>, only one command may and must be given. When <varname>Type=oneshot</varname> is used, zero or more commands may be specified. This can be specified by @@ -343,7 +343,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 +403,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> @@ -421,7 +421,7 @@ <varname>ExecStop=</varname> defined, or where the service exited unexpectedly. This argument takes multiple command lines, following the same scheme as described for - <varname>ExecStart</varname>. Use of these settings is + <varname>ExecStart=</varname>. Use of these settings is optional. Specifier and environment variable substitution is supported.</para></listitem> </varlistentry> @@ -486,7 +486,7 @@ "keep-alive ping"). If the time between two such calls is larger than the configured time, then the service is placed in a failed state and it will be terminated with - <varname>SIGABRT</varname>. By setting + <constant>SIGABRT</constant>. By setting <varname>Restart=</varname> to <option>on-failure</option> or <option>always</option>, the service will be automatically restarted. The time configured here will be passed to the @@ -628,7 +628,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 +646,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 +679,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 +699,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 +779,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 +789,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 +859,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 @@ -905,18 +905,23 @@ <varlistentry> <term><varname>USBFunctionDescriptors=</varname></term> - <listitem><para>Configure the location of file containing - FunctionFS descriptors. This is is used only when socket with - <varname>ListenUSBFunction</varname> line want to activate this service. Content of - this file is writen to ep0 file after it is opened. This is required - for socket activation using <varname>ListenUSBFunction</varname> - (i.e. for passing all ffs endpoints to service).</para></listitem> + <listitem><para>Configure the location of a file containing + <ulink + url="https://www.kernel.org/doc/Documentation/usb/functionfs.txt">USB + FunctionFS</ulink> descriptors, for implementation of USB + gadget functions. This is used only in conjunction with a + socket unit with <varname>ListenUSBFunction=</varname> + configured. The contents of this file are written to the + <filename>ep0</filename> file after it is + opened.</para></listitem> </varlistentry> <varlistentry> <term><varname>USBFunctionStrings=</varname></term> - <listitem><para>Configure the location of file containing FunctionFS strings. - Behavior is similar to <varname>USBFunctionDescriptors</varname>.</para></listitem> + <listitem><para>Configure the location of a file containing + USB FunctionFS strings. Behavior is similar to + <varname>USBFunctionDescriptors=</varname> + above.</para></listitem> </varlistentry> </variablelist> @@ -987,8 +992,8 @@ 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. - For this type of expansion, quotes and respected when splitting + 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> <para>Example:</para> @@ -1170,7 +1175,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 @@ -1189,10 +1194,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> @@ -1209,9 +1214,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> @@ -1222,11 +1227,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> @@ -1261,7 +1266,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 @@ -1276,7 +1281,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 @@ -1319,7 +1324,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 @@ -1361,7 +1366,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.socket.xml b/man/systemd.socket.xml index 7f884aa1be..410886f841 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.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"> @@ -194,7 +194,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 @@ -262,13 +262,18 @@ <varlistentry> <term><varname>ListenUSBFunction=</varname></term> - <listitem><para>Specifies a functionfs endpoint location - to listen on. This expects an absolute file system path as - argument. Behavior otherwise is very similar to the - <varname>ListenFIFO=</varname> directive above. Use this to - open functionfs endpoint ep0. When using this option, activated - service has to have <varname>USBFunctionDescriptors</varname> - and <varname>USBFunctionStrings</varname> options set.</para></listitem> + <listitem><para>Specifies a <ulink + url="https://www.kernel.org/doc/Documentation/usb/functionfs.txt">USB + FunctionFS</ulink> endpoint location to listen on, for + 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 the FunctionFS endpoint + <filename>ep0</filename>. When using this option, the + activated service has to have the + <varname>USBFunctionDescriptors=</varname> and + <varname>USBFunctionStrings=</varname> options set. + </para></listitem> </varlistentry> <varlistentry> @@ -370,10 +375,18 @@ 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> + <term><varname>Writable=</varname></term> + <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> </varlistentry> <varlistentry> @@ -405,7 +418,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> @@ -419,7 +432,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 @@ -430,7 +443,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 @@ -735,6 +748,22 @@ list.</para></listitem> </varlistentry> + <varlistentry> + <term><varname>FileDescriptorName=</varname></term> + <listitem><para>Assigns a name to all file descriptors this + socket unit encapsulates. This is useful to help activated + services 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 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 + socket unit, including its <filename>.socket</filename> + suffix.</para></listitem> + </varlistentry> + </variablelist> <para>Check @@ -755,9 +784,10 @@ <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, - <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry> + <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_listen_fds_with_names</refentrytitle><manvolnum>3</manvolnum></citerefentry> </para> - <para> For more extensive descriptions see the "systemd for Developers" series: <ulink url="http://0pointer.de/blog/projects/socket-activation.html">Socket Activation</ulink>, diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 6e0dff9b47..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> @@ -215,20 +215,19 @@ <term><filename>exit.target</filename></term> <listitem> <para>A special service unit for shutting down the system or - user service manager. It also works in containers and is - equivalent to <filename>poweroff.target</filename> on - non-container systems.</para> + user service manager. It is equivalent to + <filename>poweroff.target</filename> on non-container + systems, and also works in containers.</para> - <para>Applications wanting to terminate the user service - manager should start this unit. If systemd receives + <para>systemd will start this unit when it receives a + request to shut down over D-Bus or a <constant>SIGTERM</constant> or <constant>SIGINT</constant> - when running as user service daemon, it will start this - unit.</para> + signal when running as user service daemon.</para> - <para>Normally, this pulls in - <filename>shutdown.target</filename> which in turn should be - conflicted by all units that want to be shut down on user - service manager exit.</para> + <para>Normally, this (indirectly) pulls in + <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> </varlistentry> <varlistentry> diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml index d9a39577d5..bc9ef826e1 100644 --- a/man/systemd.swap.xml +++ b/man/systemd.swap.xml @@ -111,7 +111,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 +120,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 +132,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 +177,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.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.unit.xml b/man/systemd.unit.xml index 015deab4bb..5c74318fec 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -186,8 +186,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 @@ -209,7 +209,7 @@ 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 @@ -263,10 +263,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 +363,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 +422,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,7 +430,7 @@ <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> @@ -668,7 +666,7 @@ <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 +728,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 +779,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 +854,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 +886,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 +1026,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,19 +1044,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 - <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> - .</para></listitem> - </varlistentry> </variablelist> </refsect1> diff --git a/man/systemd.xml b/man/systemd.xml index 479f55de76..08ce99d0cc 100644 --- a/man/systemd.xml +++ b/man/systemd.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"> @@ -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 @@ -131,17 +131,48 @@ <varlistentry> <term><option>--dump-core</option></term> - <listitem><para>Dump core on crash. This switch has no effect - when run as user instance.</para></listitem> + <listitem><para>Enable core dumping on crash. This switch has + no effect when running as user instance. This setting may also + be enabled during boot on the kernel command line via the + <varname>systemd.dump_core=</varname> option, see + below.</para></listitem> </varlistentry> + + <varlistentry> + <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 + 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 + switch is attempted. This switch has no effect when running as + user instance. This setting may also be enabled during boot, + on the kernel command line via the + <varname>systemd.crash_vt=</varname> option, see + below.</para></listitem> + </varlistentry> + <varlistentry> <term><option>--crash-shell</option></term> - <listitem><para>Run shell on - crash. This switch has no effect when - run as user - instance.</para></listitem> + <listitem><para>Run a shell on crash. This switch has no + effect when running as user instance. This setting may also be + enabled during boot, on the kernel command line via the + <varname>systemd.crash_shell=</varname> option, see + below.</para></listitem> </varlistentry> + + <varlistentry> + <term><option>--crash-reboot</option></term> + + <listitem><para>Automatically reboot the system on crash. This + switch has no effect when running as user instance. This + setting may also be enabled during boot, on the kernel command + line via the <varname>systemd.crash_reboot=</varname> option, + see below.</para></listitem> + </varlistentry> + <varlistentry> <term><option>--confirm-spawn</option></term> @@ -258,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 @@ -275,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 @@ -290,7 +321,7 @@ <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 + information, see <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem> <listitem><para>Timer units are useful for triggering activation @@ -348,7 +379,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 @@ -417,7 +448,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 @@ -531,9 +562,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> @@ -575,7 +606,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> @@ -804,6 +835,7 @@ <varlistentry> <term><varname>$LISTEN_PID</varname></term> <term><varname>$LISTEN_FDS</varname></term> + <term><varname>$LISTEN_FDNAMES</varname></term> <listitem><para>Set by systemd for supervised processes during socket-based activation. See @@ -854,50 +886,66 @@ <term><varname>systemd.dump_core=</varname></term> <listitem><para>Takes a boolean argument. If - <option>true</option>, systemd dumps core when it crashes. - Otherwise, no core dump is created. Defaults to - <option>true</option>.</para></listitem> + <option>yes</option>, the systemd manager (PID 1) dumps core + when it crashes. Otherwise, no core dump is created. Defaults + to <option>yes</option>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>systemd.crash_chvt=</varname></term> + + <listitem><para>Takes a positive integer, or a boolean + argument. If a positive integer (in the range 1–63) is + specified, the system manager (PID 1) will activate the specified + 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 + kernel messages are written to is selected.</para></listitem> </varlistentry> <varlistentry> <term><varname>systemd.crash_shell=</varname></term> <listitem><para>Takes a boolean argument. If - <option>true</option>, systemd spawns a shell when it crashes. - Otherwise, no shell is spawned. Defaults to - <option>false</option>, for security reasons, as the shell is - not protected by any password + <option>yes</option>, the system manager (PID 1) spawns a + shell when it crashes, after a 10s delay. Otherwise, no shell + is spawned. Defaults to <option>no</option>, for security + reasons, as the shell is not protected by password authentication.</para></listitem> </varlistentry> <varlistentry> - <term><varname>systemd.crash_chvt=</varname></term> + <term><varname>systemd.crash_reboot=</varname></term> - <listitem><para>Takes an integer argument. If positive systemd - activates the specified virtual terminal when it crashes. - Defaults to <constant>-1</constant>.</para></listitem> + <listitem><para>Takes a boolean argument. If + <option>yes</option>, the system manager (PID 1) will reboot + the machine automatically when it crashes, after a 10s delay. + Otherwise, the system will hang indefinitely. Defaults to + <option>no</option>, in order to avoid a reboot loop. If + combined with <varname>systemd.crash_shell=</varname>, the + system is rebooted after the shell exits.</para></listitem> </varlistentry> <varlistentry> <term><varname>systemd.confirm_spawn=</varname></term> <listitem><para>Takes a boolean argument. If - <option>true</option>, asks for confirmation when spawning - processes. Defaults to - <option>false</option>.</para></listitem> + <option>yes</option>, the system manager (PID 1) asks for + confirmation when spawning processes. Defaults to + <option>no</option>.</para></listitem> </varlistentry> <varlistentry> <term><varname>systemd.show_status=</varname></term> <listitem><para>Takes a boolean argument or the constant - <constant>auto</constant>. If <option>true</option>, shows - terse service status updates on the console during bootup. - <constant>auto</constant> behaves like <option>false</option> - until a service fails or there is a significant delay in boot. - Defaults to <option>true</option>, unless - <option>quiet</option> is passed as kernel command line option - in which case it defaults to + <constant>auto</constant>. If <option>yes</option>, the + systemd manager (PID 1) shows terse service status updates on + the console during bootup. <constant>auto</constant> behaves + 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 <constant>auto</constant>.</para></listitem> </varlistentry> @@ -1013,7 +1061,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 9a86c4126a..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> @@ -178,11 +178,11 @@ protected by a different access policy.</para> <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 + with this command, another unrelated system service might + 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 3d6a03e421..2774a3228f 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -10,8 +10,11 @@ pt_BR ru uk sv +sr es +zh_CN zh_TW be be@latin tr +da diff --git a/po/da.po b/po/da.po new file mode 100644 index 0000000000..a5be57940f --- /dev/null +++ b/po/da.po @@ -0,0 +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)" @@ -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/sr.po b/po/sr.po new file mode 100644 index 0000000000..7f9b2b31cd --- /dev/null +++ b/po/sr.po @@ -0,0 +1,606 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n" +"POT-Creation-Date: 2015-10-03 18:14+0200\n" +"PO-Revision-Date: 2015-10-03 21:01+0200\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 1.8.4\n" +"Last-Translator: Марко М. Костић (Marko M. Kostić) <marko.m.kostic@gmail." +"com>\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Language: sr\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 "Поново учитајте стање систем-деа" + +#: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10 +msgid "Authentication is required to reload the systemd state." +msgstr "" +"Потребно је да се идентификујете да бисте поново учитали стање систем-деа." + +#: ../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 "Поставите статички назив машине" + +#: ../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 "" +"Потребно је да се идентификујете да бисте поставили статички назив машине и " +"да бисте поставили леп назив машине." + +#: ../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 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" +"Дозволите програмима да спрече систему да уради било шта приликом заклапања " +"екрана" + +#: ../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 "" +"Потребно је да се идентификујете да бисте дозволили програму да спречи " +"систему да уради било шта приликом заклапања екрана." + +#: ../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 "Дозволите качење уређаја на седишта" + +#: ../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 +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 "Добијте приступ шкољци унутар локалног контејнера" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "" +"Потребно је да се идентификујете да бисте добили приступ шкољци унутар " +"локалног контејнера." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "Добијте приступ шкољци на локалном домаћину" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "" +"Потребно је да се идентификујете да бисте добили приступ шкољци на локалном " +"домаћину." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Добијте приступ псеудо писаћој машини унутар локалног контејнера" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" +"Потребно је да се идентификујете да бисте добили приступ псеудо писаћој " +"машини унутар локалног контејнера." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Добијте приступ псеудо писаћој машини на локалном домаћину" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "" +"Потребно је да се идентификујете да бисте добили приступ псеудо писаћој " +"машини на локалном домаћину." + +#: ../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 "Поставите RTC на локалну временску зону или 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 "" +"Потребно је да се идентификујете да бисте подесили да ли RTC чува локално " +"или 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:428 +msgid "Authentication is required to start '$(unit)'." +msgstr "Потребно је да се идентификујете да бисте покренули „$(unit)“." + +#: ../src/core/dbus-unit.c:429 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Потребно је да се идентификујете да бисте зауставили „$(unit)“." + +#: ../src/core/dbus-unit.c:430 +msgid "Authentication is required to reload '$(unit)'." +msgstr "Потребно је да се идентификујете да бисте поново учитали „$(unit)“." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Потребно је да се идентификујете да бисте поново покренули „$(unit)“." + +#: ../src/core/dbus-unit.c:535 +msgid "Authentication is required to kill '$(unit)'." +msgstr "Потребно је да се идентификујете да бисте убили „$(unit)“." + +#: ../src/core/dbus-unit.c:565 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" +"Потребно је да се идентификујете да бисте поново поставили „неуспешно“ стање " +"за „$(unit)“." + +#: ../src/core/dbus-unit.c:597 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "" +"Потребно је да се идентификујете да бисте поставили својства за „$(unit)“." 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/rules/99-systemd.rules.in b/rules/99-systemd.rules.in index 10b90b8133..5c2cda51ec 100644 --- a/rules/99-systemd.rules.in +++ b/rules/99-systemd.rules.in @@ -57,7 +57,8 @@ SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="pa # Pull in rfkill save/restore for all rfkill devices -SUBSYSTEM=="rfkill", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/rfkill/devices/%k", ENV{SYSTEMD_WANTS}+="systemd-rfkill@$name.service" +SUBSYSTEM=="rfkill", IMPORT{builtin}="path_id" +SUBSYSTEM=="misc", KERNEL=="rfkill", TAG+="systemd", ENV{SYSTEMD_WANTS}+="systemd-rfkill.socket" # Asynchronously mount file systems implemented by these modules as soon as they are loaded. SUBSYSTEM=="module", KERNEL=="fuse", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount" 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 bb2bb25deb..056cdbce70 100644 --- a/shell-completion/bash/journalctl +++ b/shell-completion/bash/journalctl @@ -47,7 +47,7 @@ _journalctl() { --version --list-catalog --update-catalog --list-boots --show-cursor --dmesg -k --pager-end -e -r --reverse --utc -x --catalog --no-full --force --dump-catalog - --flush' + --flush --rotate' [ARG]='-b --boot --this-boot -D --directory --file -F --field -o --output -u --unit --user-unit -p --priority --vacuum-size --vacuum-time' diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl index 0534c0d9cc..140465d316 100644 --- a/shell-completion/bash/machinectl +++ b/shell-completion/bash/machinectl @@ -26,7 +26,7 @@ __contains_word() { __get_machines() { local a b - (machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager) | \ + (machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager; echo ".host") | \ { while read a b; do echo " $a"; done; } | sort -u; } @@ -41,7 +41,7 @@ _machinectl() { local -A VERBS=( [STANDALONE]='list list-images pull-tar pull-raw pull-dkr import-tar import-raw export-tar export-raw list-transfers cancel-transfer' - [MACHINES]='status show start login enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit' + [MACHINES]='status show start login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit' ) _init_completion || return diff --git a/shell-completion/bash/networkctl b/shell-completion/bash/networkctl index 7ca2aa5a81..942c7e1c00 100644 --- a/shell-completion/bash/networkctl +++ b/shell-completion/bash/networkctl @@ -24,7 +24,7 @@ __contains_word () { } __get_links() { - networkctl list --no-legend --no-pager --all | awk '{ print $2 }' | sort -u + networkctl list --no-legend --no-pager --all | { while read -r a b c; do echo " $b"; done; }; } _networkctl() { diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index 4d63e2870f..f9a4f2265e 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -87,8 +87,8 @@ __get_all_unit_files () { { __systemctl $1 list-unit-files; } | { while read -r __get_machines() { local a b - (machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager) | \ - { while read a b; do echo " $a"; done; } | sort -u; + { machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager; } | \ + { while read a b; do echo " $a"; done; } } _systemctl () { @@ -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 @@ -119,9 +121,7 @@ _systemctl () { comps=$(__systemctl $mode -t help) ;; --state) - comps='loaded not-found stub - active inactive failed - dead elapsed exited listening mounted plugged running waiting' + comps=$(__systemctl $mode --state=help) ;; --job-mode) comps='fail replace replace-irreversibly isolate @@ -161,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' diff --git a/shell-completion/bash/systemd-nspawn b/shell-completion/bash/systemd-nspawn index 83e34ef02e..f9b740380c 100644 --- a/shell-completion/bash/systemd-nspawn +++ b/shell-completion/bash/systemd-nspawn @@ -85,7 +85,7 @@ _systemd_nspawn() { CAP_SYS_CHROOT CAP_SYS_NICE CAP_SYS_PTRACE CAP_SYS_RESOURCE CAP_SYS_TTY_CONFIG' ;; --link-journal) - comps='no auto guest host' + comps='no auto guest try-guest host try-host' ;; --bind|--bind-ro) compopt -o nospace diff --git a/shell-completion/bash/systemd-path b/shell-completion/bash/systemd-path index cdaf29794e..2f0c5f5bd7 100644 --- a/shell-completion/bash/systemd-path +++ b/shell-completion/bash/systemd-path @@ -24,7 +24,7 @@ __contains_word () { } __get_names() { - systemd-path | cut -d: -f1 | sort -u + systemd-path | { while IFS=: read -r a b; do echo " $a"; done; } } _systemd_path() { diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index a948677516..7379431b71 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -81,7 +81,12 @@ _systemd_run() { KillSignal= LimitCPU= LimitFSIZE= LimitDATA= LimitSTACK= LimitCORE= LimitRSS= LimitNOFILE= LimitAS= LimitNPROC= LimitMEMLOCK= LimitLOCKS= LimitSIGPENDING= LimitMSGQUEUE= - LimitNICE= LimitRTPRIO= LimitRTTIME=' + LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= + PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= + TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= + SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= + ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= + ProtectSystem= ProtectHome= RuntimeDirectory=' 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/_systemctl.in b/shell-completion/zsh/_systemctl.in index 4bf306aacb..96f51a0ee0 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -334,13 +334,13 @@ _systemctl_caching_policy() _unit_states() { local -a _states - _states=(loaded failed active inactive not-found listening running waiting plugged mounted exited dead masked) + _states=("${(fo)$(__systemctl --state=help)}") _values -s , "${_states[@]}" } _unit_types() { local -a _types - _types=(automount busname device mount path service snapshot socket swap target timer) + _types=("${(fo)$(__systemctl -t help)}") _values -s , "${_types[@]}" } diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run index 8d6957fa9b..8bb0156a85 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= \ + ))' \ '--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/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index e5d252c818..bb23e64d24 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -89,7 +89,7 @@ _udevadm_test-builtin(){ _udevadm_mounts(){ local dev_tmp dpath_tmp mp_tmp mline - tmp=( "${(@f)$(< /etc/mtab)}" ) + tmp=( "${(@f)$(< /proc/self/mounts)}" ) dev_tmp=( "${(@)${(@)tmp%% *}:#none}" ) mp_tmp=( "${(@)${(@)tmp#* }%% *}" ) diff --git a/src/activate/activate.c b/src/activate/activate.c index 5318829442..b7e6255f49 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -19,26 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> +#include <getopt.h> #include <sys/epoll.h> #include <sys/prctl.h> #include <sys/socket.h> #include <sys/wait.h> -#include <getopt.h> +#include <unistd.h> -#include "systemd/sd-daemon.h" +#include "sd-daemon.h" -#include "socket-util.h" -#include "build.h" +#include "alloc-util.h" +#include "fd-util.h" #include "log.h" -#include "strv.h" #include "macro.h" #include "signal-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "strv.h" static char** arg_listen = NULL; static bool arg_accept = false; static char** arg_args = NULL; static char** arg_setenv = NULL; +static const char *arg_fdname = NULL; static int add_epoll(int epoll_fd, int fd) { struct epoll_event ev = { @@ -137,8 +140,8 @@ static int launch(char* name, char **argv, char **env, int fds) { length = strv_length(arg_setenv); - /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, NULL */ - envp = new0(char *, length + 7); + /* PATH, TERM, HOME, USER, LISTEN_FDS, LISTEN_PID, LISTEN_FDNAMES, NULL */ + envp = new0(char *, length + 8); if (!envp) return log_oom(); @@ -146,7 +149,9 @@ static int launch(char* name, char **argv, char **env, int fds) { if (strchr(*s, '=')) envp[n_env++] = *s; else { - _cleanup_free_ char *p = strappend(*s, "="); + _cleanup_free_ char *p; + + p = strappend(*s, "="); if (!p) return log_oom(); envp[n_env] = strv_find_prefix(env, p); @@ -165,15 +170,37 @@ static int launch(char* name, char **argv, char **env, int fds) { (asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0)) return log_oom(); + if (arg_fdname) { + char *e; + + e = strappend("LISTEN_FDNAMES=", arg_fdname); + if (!e) + return log_oom(); + + for (i = 1; i < (unsigned) fds; i++) { + char *c; + + c = strjoin(e, ":", arg_fdname, NULL); + if (!c) { + free(e); + return log_oom(); + } + + free(e); + e = c; + } + + envp[n_env++] = e; + } + tmp = strv_join(argv, " "); if (!tmp) return log_oom(); log_info("Execing %s (%s)", name, tmp); execvpe(name, argv, envp); - log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp); - return -errno; + return log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp); } static int launch1(const char* child, char** argv, char **env, int fd) { @@ -290,6 +317,7 @@ static void help(void) { static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_FDNAME, }; static const struct option options[] = { @@ -298,11 +326,12 @@ static int parse_argv(int argc, char *argv[]) { { "listen", required_argument, NULL, 'l' }, { "accept", no_argument, NULL, 'a' }, { "setenv", required_argument, NULL, 'E' }, - { "environment", required_argument, NULL, 'E' }, /* alias */ + { "environment", required_argument, NULL, 'E' }, /* legacy alias */ + { "fdname", required_argument, NULL, ARG_FDNAME }, {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -314,29 +343,34 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0 /* done */; + return version(); - case 'l': { - int r = strv_extend(&arg_listen, optarg); + case 'l': + r = strv_extend(&arg_listen, optarg); if (r < 0) - return r; + return log_oom(); break; - } case 'a': arg_accept = true; break; - case 'E': { - int r = strv_extend(&arg_setenv, optarg); + case 'E': + r = strv_extend(&arg_setenv, optarg); if (r < 0) - return r; + return log_oom(); break; - } + + case ARG_FDNAME: + if (!fdname_is_valid(optarg)) { + log_error("File descriptor name %s is not valid, refusing.", optarg); + return -EINVAL; + } + + arg_fdname = optarg; + break; case '?': return -EINVAL; diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index f4255f979e..a377996a37 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -21,12 +21,14 @@ #include <stdlib.h> -#include "manager.h" +#include "alloc-util.h" +#include "analyze-verify.h" #include "bus-util.h" #include "log.h" -#include "strv.h" +#include "manager.h" #include "pager.h" -#include "analyze-verify.h" +#include "path-util.h" +#include "strv.h" static int generate_path(char **var, char **filenames) { char **filename; diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 3657ef50f1..27ead903e9 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -20,25 +20,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> #include <getopt.h> #include <locale.h> +#include <stdio.h> +#include <stdlib.h> #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "analyze-verify.h" #include "bus-error.h" -#include "log.h" -#include "build.h" -#include "util.h" -#include "strxcpyx.h" -#include "strv.h" -#include "unit-name.h" -#include "special.h" +#include "bus-util.h" +#include "glob-util.h" #include "hashmap.h" +#include "locale-util.h" +#include "log.h" #include "pager.h" -#include "analyze-verify.h" +#include "parse-util.h" +#include "special.h" +#include "strv.h" +#include "strxcpyx.h" #include "terminal-util.h" +#include "unit-name.h" +#include "util.h" #define SCALE_X (0.1 / 1000.0) /* pixels per us */ #define SCALE_Y (20.0) @@ -318,6 +322,10 @@ finish: } static void free_host_info(struct host_info *hi) { + + if (!hi) + return; + free(hi->hostname); free(hi->kernel_name); free(hi->kernel_release); @@ -328,6 +336,8 @@ static void free_host_info(struct host_info *hi) { free(hi); } +DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info*, free_host_info); + static int acquire_time_data(sd_bus *bus, struct unit_times **out) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; @@ -430,24 +440,25 @@ fail: } static int acquire_host_info(sd_bus *bus, struct host_info **hi) { - int r; - struct host_info *host; - static const struct bus_properties_map hostname_map[] = { - { "Hostname", "s", NULL, offsetof(struct host_info, hostname) }, - { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) }, - { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) }, - { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) }, + { "Hostname", "s", NULL, offsetof(struct host_info, hostname) }, + { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) }, + { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) }, + { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) }, { "OperatingSystemPrettyName", "s", NULL, offsetof(struct host_info, os_pretty_name) }, {} }; static const struct bus_properties_map manager_map[] = { - { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) }, - { "Architecture", "s", NULL, offsetof(struct host_info, architecture) }, + { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) }, + { "Architecture", "s", NULL, offsetof(struct host_info, architecture) }, {} }; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(free_host_infop) struct host_info *host; + int r; + host = new0(struct host_info, 1); if (!host) return log_oom(); @@ -458,7 +469,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) { hostname_map, host); if (r < 0) - goto fail; + log_debug_errno(r, "Failed to get host information from systemd-hostnamed: %s", bus_error_message(&error, r)); r = bus_map_all_properties(bus, "org.freedesktop.systemd1", @@ -466,13 +477,12 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) { manager_map, host); if (r < 0) - goto fail; + return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r)); *hi = host; + host = NULL; + return 0; -fail: - free_host_info(host); - return r; } static int pretty_boot_time(sd_bus *bus, char **_buf) { @@ -535,9 +545,9 @@ static void svg_graph_box(double height, double begin, double end) { } static int analyze_plot(sd_bus *bus) { + _cleanup_(free_host_infop) struct host_info *host = NULL; struct unit_times *times; struct boot_times *boot; - struct host_info *host = NULL; int n, m = 1, y=0; double width; _cleanup_free_ char *pretty_times = NULL; @@ -557,7 +567,7 @@ static int analyze_plot(sd_bus *bus) { n = acquire_time_data(bus, ×); if (n <= 0) - goto out; + return n; qsort(times, n, sizeof(struct unit_times), compare_unit_start); @@ -653,12 +663,12 @@ static int analyze_plot(sd_bus *bus) { svg("<text x=\"20\" y=\"50\">%s</text>", pretty_times); svg("<text x=\"20\" y=\"30\">%s %s (%s %s %s) %s %s</text>", isempty(host->os_pretty_name) ? "Linux" : host->os_pretty_name, - isempty(host->hostname) ? "" : host->hostname, - isempty(host->kernel_name) ? "" : host->kernel_name, - isempty(host->kernel_release) ? "" : host->kernel_release, - isempty(host->kernel_version) ? "" : host->kernel_version, - isempty(host->architecture) ? "" : host->architecture, - isempty(host->virtualization) ? "" : host->virtualization); + strempty(host->hostname), + strempty(host->kernel_name), + strempty(host->kernel_release), + strempty(host->kernel_version), + strempty(host->architecture), + strempty(host->virtualization)); svg("<g transform=\"translate(%.3f,100)\">\n", 20.0 + (SCALE_X * boot->firmware_time)); svg_graph_box(m, -(double) boot->firmware_time, boot->finish_time); @@ -742,8 +752,6 @@ static int analyze_plot(sd_bus *bus) { free_unit_times(times, (unsigned) n); n = 0; -out: - free_host_info(host); return n; } @@ -1217,10 +1225,8 @@ static int dump(sd_bus *bus, char **args) { &error, &reply, ""); - if (r < 0) { - log_error("Failed issue method call: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed issue method call: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &text); if (r < 0) @@ -1251,11 +1257,36 @@ static int set_log_level(sd_bus *bus, char **args) { &error, "s", args[0]); - if (r < 0) { - log_error("Failed to issue method call: %s", bus_error_message(&error, -r)); - return -EIO; + if (r < 0) + return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); + + return 0; +} + +static int set_log_target(sd_bus *bus, char **args) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + assert(bus); + assert(args); + + if (strv_length(args) != 1) { + log_error("This command expects one argument only."); + return -E2BIG; } + r = sd_bus_set_property( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "LogTarget", + &error, + "s", + args[0]); + if (r < 0) + return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); + return 0; } @@ -1285,7 +1316,8 @@ static void help(void) { " critical-chain Print a tree of the time critical chain of units\n" " plot Output SVG graphic showing service initialization\n" " dot Output dependency graph in dot(1) format\n" - " set-log-level LEVEL Set logging threshold for systemd\n" + " set-log-level LEVEL Set logging threshold for manager\n" + " set-log-target TARGET Set logging target for manager\n" " dump Output state serialization of service manager\n" " verify FILE... Check unit files for correctness\n" , program_invocation_short_name); @@ -1339,9 +1371,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_USER: arg_user = true; @@ -1434,7 +1464,7 @@ int main(int argc, char *argv[]) { else { _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; - r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus); + r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; @@ -1454,6 +1484,8 @@ int main(int argc, char *argv[]) { r = dump(bus, argv+optind+1); else if (streq(argv[optind], "set-log-level")) r = set_log_level(bus, argv+optind+1); + else if (streq(argv[optind], "set-log-target")) + r = set_log_target(bus, argv+optind+1); else log_error("Unknown operation '%s'.", argv[optind]); } diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index abfd545c79..a544866000 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -20,36 +20,36 @@ ***/ #include <errno.h> -#include <unistd.h> #include <getopt.h> #include <stddef.h> +#include <unistd.h> +#include "ask-password-api.h" +#include "def.h" #include "log.h" #include "macro.h" #include "strv.h" -#include "ask-password-api.h" -#include "def.h" static const char *arg_icon = NULL; static const char *arg_id = NULL; -static const char *arg_message = NULL; -static bool arg_echo = false; -static bool arg_use_tty = true; +static const char *arg_keyname = NULL; +static char *arg_message = NULL; static usec_t arg_timeout = DEFAULT_TIMEOUT_USEC; -static bool arg_accept_cached = false; static bool arg_multiple = false; +static AskPasswordFlags arg_flags = ASK_PASSWORD_PUSH_CACHE; static void help(void) { printf("%s [OPTIONS...] MESSAGE\n\n" "Query the user for a system passphrase, via the TTY or an UI agent.\n\n" - " -h --help Show this help\n" - " --icon=NAME Icon name\n" - " --timeout=SEC Timeout in sec\n" - " --echo Do not mask input (useful for usernames)\n" - " --no-tty Ask question via agent even on TTY\n" - " --accept-cached Accept cached passwords\n" - " --multiple List multiple passwords if available\n" - " --id=ID Query identifier (e.g. cryptsetup:/dev/sda5)\n" + " -h --help Show this help\n" + " --icon=NAME Icon name\n" + " --id=ID Query identifier (e.g. \"cryptsetup:/dev/sda5\")\n" + " --keyname=NAME Kernel key name for caching passwords (e.g. \"cryptsetup\")\n" + " --timeout=SEC Timeout in seconds\n" + " --echo Do not mask input (useful for usernames)\n" + " --no-tty Ask question via agent even on TTY\n" + " --accept-cached Accept cached passwords\n" + " --multiple List multiple passwords if available\n" , program_invocation_short_name); } @@ -62,7 +62,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_NO_TTY, ARG_ACCEPT_CACHED, ARG_MULTIPLE, - ARG_ID + ARG_ID, + ARG_KEYNAME, }; static const struct option options[] = { @@ -74,6 +75,7 @@ static int parse_argv(int argc, char *argv[]) { { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED }, { "multiple", no_argument, NULL, ARG_MULTIPLE }, { "id", required_argument, NULL, ARG_ID }, + { "keyname", required_argument, NULL, ARG_KEYNAME }, {} }; @@ -102,15 +104,15 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ECHO: - arg_echo = true; + arg_flags |= ASK_PASSWORD_ECHO; break; case ARG_NO_TTY: - arg_use_tty = false; + arg_flags |= ASK_PASSWORD_NO_TTY; break; case ARG_ACCEPT_CACHED: - arg_accept_cached = true; + arg_flags |= ASK_PASSWORD_ACCEPT_CACHED; break; case ARG_MULTIPLE: @@ -121,6 +123,10 @@ static int parse_argv(int argc, char *argv[]) { arg_id = optarg; break; + case ARG_KEYNAME: + arg_keyname = optarg; + break; + case '?': return -EINVAL; @@ -128,18 +134,20 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } - if (optind != argc - 1) { - log_error("%s: required argument missing.", program_invocation_short_name); - return -EINVAL; + if (argc > optind) { + arg_message = strv_join(argv + optind, " "); + if (!arg_message) + return log_oom(); } - arg_message = argv[optind]; return 1; } int main(int argc, char *argv[]) { - int r; + _cleanup_strv_free_erase_ char **l = NULL; usec_t timeout; + char **p; + int r; log_parse_environment(); log_open(); @@ -153,36 +161,21 @@ int main(int argc, char *argv[]) { else timeout = 0; - if (arg_use_tty && isatty(STDIN_FILENO)) { - char *password = NULL; - - r = ask_password_tty(arg_message, timeout, arg_echo, NULL, - &password); - if (r >= 0) { - puts(password); - free(password); - } - - } else { - char **l; - - r = ask_password_agent(arg_message, arg_icon, arg_id, timeout, - arg_echo, arg_accept_cached, &l); - if (r >= 0) { - char **p; - - STRV_FOREACH(p, l) { - puts(*p); + r = ask_password_auto(arg_message, arg_icon, arg_id, arg_keyname, timeout, arg_flags, &l); + if (r < 0) { + log_error_errno(r, "Failed to query password: %m"); + goto finish; + } - if (!arg_multiple) - break; - } + STRV_FOREACH(p, l) { + puts(*p); - strv_free(l); - } + if (!arg_multiple) + break; } finish: + free(arg_message); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index c8961de946..b0fa079fec 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -19,12 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "mkdir.h" -#include "fileio.h" #include "libudev.h" -#include "udev-util.h" + +#include "alloc-util.h" #include "def.h" +#include "escape.h" +#include "fileio.h" +#include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "string-util.h" +#include "udev-util.h" +#include "util.h" static struct udev_device *find_pci_or_platform_parent(struct udev_device *device) { struct udev_device *parent; @@ -375,7 +381,7 @@ int main(int argc, char *argv[]) { _cleanup_free_ char *value = NULL; const char *clamp; - if (!shall_restore_state()) + if (shall_restore_state() == 0) return EXIT_SUCCESS; if (!validate_device(udev, device)) diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c new file mode 100644 index 0000000000..48183e381f --- /dev/null +++ b/src/basic/alloc-util.c @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "util.h" + +void* memdup(const void *p, size_t l) { + void *r; + + assert(p); + + r = malloc(l); + if (!r) + return NULL; + + memcpy(r, p, l); + return r; +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { + size_t a, newalloc; + void *q; + + assert(p); + assert(allocated); + + if (*allocated >= need) + return *p; + + newalloc = MAX(need * 2, 64u / size); + a = newalloc * size; + + /* check for overflows */ + if (a < size * need) + return NULL; + + q = realloc(*p, a); + if (!q) + return NULL; + + *p = q; + *allocated = newalloc; + return q; +} + +void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { + size_t prev; + uint8_t *q; + + assert(p); + assert(allocated); + + prev = *allocated; + + q = greedy_realloc(p, allocated, need, size); + if (!q) + return NULL; + + if (*allocated > prev) + memzero(q + prev * size, (*allocated - prev) * size); + + return q; +} diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h new file mode 100644 index 0000000000..12b602e185 --- /dev/null +++ b/src/basic/alloc-util.h @@ -0,0 +1,108 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <alloca.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h" + +#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) + +#define new0(t, n) ((t*) calloc((n), sizeof(t))) + +#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) + +#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) + +#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) + +#define malloc0(n) (calloc(1, (n))) + +static inline void *mfree(void *memory) { + free(memory); + return NULL; +} + +void* memdup(const void *p, size_t l) _alloc_(2); + +static inline void freep(void *p) { + free(*(void**) p); +} + +#define _cleanup_free_ _cleanup_(freep) + +_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return malloc(a * b); +} + +_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return realloc(p, a * b); +} + +_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return memdup(p, a * b); +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); +void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); + +#define GREEDY_REALLOC(array, allocated, need) \ + greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define GREEDY_REALLOC0(array, allocated, need) \ + greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define alloca0(n) \ + ({ \ + char *_new_; \ + size_t _len_ = n; \ + _new_ = alloca(_len_); \ + (void *) memset(_new_, 0, _len_); \ + }) + +/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ +#define alloca_align(size, align) \ + ({ \ + void *_ptr_; \ + size_t _mask_ = (align) - 1; \ + _ptr_ = alloca((size) + _mask_); \ + (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ + }) + +#define alloca0_align(size, align) \ + ({ \ + void *_new_; \ + size_t _size_ = (size); \ + _new_ = alloca_align(_size_, (align)); \ + (void*)memset(_new_, 0, _size_); \ + }) diff --git a/src/basic/async.c b/src/basic/async.c index 7725e6d7d3..c3135f0efe 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -23,6 +23,7 @@ #include <unistd.h> #include "async.h" +#include "fd-util.h" #include "log.h" #include "util.h" diff --git a/src/basic/audit.c b/src/basic/audit-util.c index 1f593aa813..4612297334 100644 --- a/src/basic/audit.c +++ b/src/basic/audit-util.c @@ -22,11 +22,15 @@ #include <errno.h> #include <stdio.h> +#include "alloc-util.h" +#include "audit-util.h" +#include "fd-util.h" +#include "fileio.h" #include "macro.h" -#include "audit.h" -#include "util.h" +#include "parse-util.h" #include "process-util.h" -#include "fileio.h" +#include "user-util.h" +#include "util.h" int audit_session_from_pid(pid_t pid, uint32_t *id) { _cleanup_free_ char *s = NULL; diff --git a/src/basic/audit.h b/src/basic/audit-util.h index 6de331c73e..6de331c73e 100644 --- a/src/basic/audit.h +++ b/src/basic/audit-util.h diff --git a/src/basic/barrier.c b/src/basic/barrier.c index 436ba95989..2d55bab4ab 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -30,6 +30,7 @@ #include <unistd.h> #include "barrier.h" +#include "fd-util.h" #include "macro.h" #include "util.h" diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index 2eabf3e1c1..1449e2ea85 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" - +#include "alloc-util.h" #include "bitmap.h" +#include "util.h" struct Bitmap { uint64_t *bitmaps; diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 074deeccda..4c90bc0c80 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -20,23 +20,26 @@ ***/ #include <stdlib.h> -#include <sys/vfs.h> #include <sys/stat.h> - +#include <sys/vfs.h> #ifdef HAVE_LINUX_BTRFS_H #include <linux/btrfs.h> #endif +#include "alloc-util.h" +#include "btrfs-ctree.h" +#include "btrfs-util.h" +#include "copy.h" +#include "fd-util.h" +#include "fileio.h" +#include "macro.h" #include "missing.h" -#include "util.h" #include "path-util.h" -#include "macro.h" -#include "copy.h" #include "selinux-util.h" #include "smack-util.h" -#include "fileio.h" -#include "btrfs-ctree.h" -#include "btrfs-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "util.h" /* WARNING: Be careful with file system ioctls! When we get an fd, we * need to make sure it either refers to only a regular file or @@ -59,13 +62,13 @@ static int validate_subvolume_name(const char *name) { static int open_parent(const char *path, int flags) { _cleanup_free_ char *parent = NULL; - int r, fd; + int fd; assert(path); - r = path_get_parent(path, &parent); - if (r < 0) - return r; + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; fd = open(parent, flags); if (fd < 0) @@ -436,7 +439,7 @@ static int btrfs_ioctl_search_args_compare(const struct btrfs_ioctl_search_args #define BTRFS_IOCTL_SEARCH_HEADER_BODY(sh) \ ((void*) ((uint8_t*) sh + sizeof(struct btrfs_ioctl_search_header))) -int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) { +int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) { struct btrfs_ioctl_search_args args = { /* Tree of tree roots */ .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, @@ -453,16 +456,23 @@ int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *ret) { .key.max_transid = (uint64_t) -1, }; - uint64_t subvol_id; bool found = false; int r; assert(fd >= 0); assert(ret); - r = btrfs_subvol_get_id_fd(fd, &subvol_id); - if (r < 0) - return r; + if (subvol_id == 0) { + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } args.key.min_objectid = args.key.max_objectid = subvol_id; @@ -521,7 +531,7 @@ finish: return 0; } -int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { +int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) { struct btrfs_ioctl_search_args args = { /* Tree of quota items */ @@ -540,18 +550,25 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { .key.max_transid = (uint64_t) -1, }; - uint64_t subvol_id; bool found_info = false, found_limit = false; int r; assert(fd >= 0); assert(ret); - r = btrfs_subvol_get_id_fd(fd, &subvol_id); - if (r < 0) - return r; + if (qgroupid == 0) { + r = btrfs_subvol_get_id_fd(fd, &qgroupid); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } - args.key.min_offset = args.key.max_offset = subvol_id; + args.key.min_offset = args.key.max_offset = qgroupid; while (btrfs_ioctl_search_args_compare(&args) <= 0) { const struct btrfs_ioctl_search_header *sh; @@ -571,7 +588,7 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { if (sh->objectid != 0) continue; - if (sh->offset != subvol_id) + if (sh->offset != qgroupid) continue; if (sh->type == BTRFS_QGROUP_INFO_KEY) { @@ -585,12 +602,14 @@ int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *ret) { } else if (sh->type == BTRFS_QGROUP_LIMIT_KEY) { const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh); - ret->referenced_max = le64toh(qli->max_rfer); - ret->exclusive_max = le64toh(qli->max_excl); - - if (ret->referenced_max == 0) + if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER) + ret->referenced_max = le64toh(qli->max_rfer); + else ret->referenced_max = (uint64_t) -1; - if (ret->exclusive_max == 0) + + if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_EXCL) + ret->exclusive_max = le64toh(qli->max_excl); + else ret->exclusive_max = (uint64_t) -1; found_limit = true; @@ -622,6 +641,109 @@ finish: return 0; } +int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *ret) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret); +} + +int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) { + uint64_t level, lowest = (uint64_t) -1, lowest_qgroupid = 0; + _cleanup_free_ uint64_t *qgroups = NULL; + int r, n, i; + + assert(fd >= 0); + assert(ret); + + /* This finds the "subtree" qgroup for a specific + * subvolume. This only works for subvolumes that have been + * prepared with btrfs_subvol_auto_qgroup_fd() with + * insert_intermediary_qgroup=true (or equivalent). For others + * it will return the leaf qgroup instead. The two cases may + * be distuingished via the return value, which is 1 in case + * an appropriate "subtree" qgroup was found, and 0 + * otherwise. */ + + if (subvol_id == 0) { + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } + + r = btrfs_qgroupid_split(subvol_id, &level, NULL); + if (r < 0) + return r; + if (level != 0) /* Input must be a leaf qgroup */ + return -EINVAL; + + n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups); + if (n < 0) + return n; + + for (i = 0; i < n; i++) { + uint64_t id; + + r = btrfs_qgroupid_split(qgroups[i], &level, &id); + if (r < 0) + return r; + + if (id != subvol_id) + continue; + + if (lowest == (uint64_t) -1 || level < lowest) { + lowest_qgroupid = qgroups[i]; + lowest = level; + } + } + + if (lowest == (uint64_t) -1) { + /* No suitable higher-level qgroup found, let's return + * the leaf qgroup instead, and indicate that with the + * return value. */ + + *ret = subvol_id; + return 0; + } + + *ret = lowest_qgroupid; + return 1; +} + +int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *ret) { + uint64_t qgroupid; + int r; + + assert(fd >= 0); + assert(ret); + + /* This determines the quota data of the qgroup with the + * lowest level, that shares the id part with the specified + * subvolume. This is useful for determining the quota data + * for entire subvolume subtrees, as long as the subtrees have + * been set up with btrfs_qgroup_subvol_auto_fd() or in a + * compatible way */ + + r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid); + if (r < 0) + return r; + + return btrfs_qgroup_get_quota_fd(fd, qgroupid, ret); +} + +int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *ret) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return btrfs_subvol_get_subtree_quota_fd(fd, subvol_id, ret); +} + int btrfs_defrag_fd(int fd) { struct stat st; @@ -679,37 +801,79 @@ int btrfs_quota_enable(const char *path, bool b) { return btrfs_quota_enable_fd(fd, b); } -int btrfs_quota_limit_fd(int fd, uint64_t referenced_max) { +int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max) { + struct btrfs_ioctl_qgroup_limit_args args = { - .lim.max_rfer = - referenced_max == (uint64_t) -1 ? 0 : - referenced_max == 0 ? 1 : referenced_max, + .lim.max_rfer = referenced_max, .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER, }; + unsigned c; int r; assert(fd >= 0); - r = btrfs_is_filesystem(fd); - if (r < 0) - return r; - if (!r) - return -ENOTTY; + if (qgroupid == 0) { + r = btrfs_subvol_get_id_fd(fd, &qgroupid); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } - if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) - return -errno; + args.qgroupid = qgroupid; + + for (c = 0;; c++) { + if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) { + + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + + return -errno; + } + + break; + } return 0; } -int btrfs_quota_limit(const char *path, uint64_t referenced_max) { +int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max); +} + +int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max) { + uint64_t qgroupid; + int r; + + assert(fd >= 0); + + r = btrfs_subvol_find_subtree_qgroup(fd, subvol_id, &qgroupid); + if (r < 0) + return r; + + return btrfs_qgroup_set_limit_fd(fd, qgroupid, referenced_max); +} + +int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max) { _cleanup_close_ int fd = -1; fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); if (fd < 0) return -errno; - return btrfs_quota_limit_fd(fd, referenced_max); + return btrfs_subvol_set_subtree_quota_limit_fd(fd, subvol_id, referenced_max); } int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { @@ -799,7 +963,188 @@ int btrfs_resize_loopback(const char *p, uint64_t new_size, bool grow_only) { return btrfs_resize_loopback_fd(fd, new_size, grow_only); } -static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, bool recursive) { +int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret) { + assert(ret); + + if (level >= (UINT64_C(1) << (64 - BTRFS_QGROUP_LEVEL_SHIFT))) + return -EINVAL; + + if (id >= (UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT)) + return -EINVAL; + + *ret = (level << BTRFS_QGROUP_LEVEL_SHIFT) | id; + return 0; +} + +int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id) { + assert(level || id); + + if (level) + *level = qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT; + + if (id) + *id = qgroupid & ((UINT64_C(1) << BTRFS_QGROUP_LEVEL_SHIFT) - 1); + + return 0; +} + +static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) { + + struct btrfs_ioctl_qgroup_create_args args = { + .create = b, + .qgroupid = qgroupid, + }; + unsigned c; + int r; + + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (r == 0) + return -ENOTTY; + + for (c = 0;; c++) { + if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) { + + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + + return -errno; + } + + break; + } + + return 0; +} + +int btrfs_qgroup_create(int fd, uint64_t qgroupid) { + return qgroup_create_or_destroy(fd, true, qgroupid); +} + +int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) { + return qgroup_create_or_destroy(fd, false, qgroupid); +} + +int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) { + _cleanup_free_ uint64_t *qgroups = NULL; + uint64_t subvol_id; + int i, n, r; + + /* Destroys the specified qgroup, but unassigns it from all + * its parents first. Also, it recursively destroys all + * qgroups it is assgined to that have the same id part of the + * qgroupid as the specified group. */ + + r = btrfs_qgroupid_split(qgroupid, NULL, &subvol_id); + if (r < 0) + return r; + + n = btrfs_qgroup_find_parents(fd, qgroupid, &qgroups); + if (n < 0) + return n; + + for (i = 0; i < n; i++) { + uint64_t id; + + r = btrfs_qgroupid_split(qgroups[i], NULL, &id); + if (r < 0) + return r; + + r = btrfs_qgroup_unassign(fd, qgroupid, qgroups[i]); + if (r < 0) + return r; + + if (id != subvol_id) + continue; + + /* The parent qgroupid shares the same id part with + * us? If so, destroy it too. */ + + (void) btrfs_qgroup_destroy_recursive(fd, qgroups[i]); + } + + return btrfs_qgroup_destroy(fd, qgroupid); +} + +int btrfs_quota_scan_start(int fd) { + struct btrfs_ioctl_quota_rescan_args args = {}; + + assert(fd >= 0); + + if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &args) < 0) + return -errno; + + return 0; +} + +int btrfs_quota_scan_wait(int fd) { + assert(fd >= 0); + + if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT) < 0) + return -errno; + + return 0; +} + +int btrfs_quota_scan_ongoing(int fd) { + struct btrfs_ioctl_quota_rescan_args args = {}; + + assert(fd >= 0); + + if (ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_STATUS, &args) < 0) + return -errno; + + return !!args.flags; +} + +static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t parent) { + struct btrfs_ioctl_qgroup_assign_args args = { + .assign = b, + .src = child, + .dst = parent, + }; + unsigned c; + int r; + + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (r == 0) + return -ENOTTY; + + for (c = 0;; c++) { + r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args); + if (r < 0) { + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + + return -errno; + } + + if (r == 0) + return 0; + + /* If the return value is > 0, we need to request a rescan */ + + (void) btrfs_quota_scan_start(fd); + return 1; + } +} + +int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent) { + return qgroup_assign_or_unassign(fd, true, child, parent); +} + +int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent) { + return qgroup_assign_or_unassign(fd, false, child, parent); +} + +static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol_id, BtrfsRemoveFlags flags) { struct btrfs_ioctl_search_args args = { .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, @@ -828,16 +1173,6 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (!S_ISDIR(st.st_mode)) return -EINVAL; - /* First, try to remove the subvolume. If it happens to be - * already empty, this will just work. */ - strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1); - if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) - return 0; - if (!recursive || errno != ENOTEMPTY) - return -errno; - - /* OK, the subvolume is not empty, let's look for child - * subvolumes, and remove them, first */ subvol_fd = openat(fd, subvolume, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); if (subvol_fd < 0) return -errno; @@ -848,6 +1183,19 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol return r; } + /* First, try to remove the subvolume. If it happens to be + * already empty, this will just work. */ + strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1); + if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) >= 0) { + (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); /* for the leaf subvolumes, the qgroup id is identical to the subvol id */ + return 0; + } + if (!(flags & BTRFS_REMOVE_RECURSIVE) || errno != ENOTEMPTY) + return -errno; + + /* OK, the subvolume is not empty, let's look for child + * subvolumes, and remove them, first */ + args.key.min_offset = args.key.max_offset = subvol_id; while (btrfs_ioctl_search_args_compare(&args) <= 0) { @@ -897,7 +1245,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (isempty(ino_args.name)) /* Subvolume is in the top-level * directory of the subvolume. */ - r = subvol_remove_children(subvol_fd, p, sh->objectid, recursive); + r = subvol_remove_children(subvol_fd, p, sh->objectid, flags); else { _cleanup_close_ int child_fd = -1; @@ -909,7 +1257,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (child_fd < 0) return -errno; - r = subvol_remove_children(child_fd, p, sh->objectid, recursive); + r = subvol_remove_children(child_fd, p, sh->objectid, flags); } if (r < 0) return r; @@ -925,10 +1273,11 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol if (ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &vol_args) < 0) return -errno; + (void) btrfs_qgroup_destroy_recursive(fd, subvol_id); return 0; } -int btrfs_subvol_remove(const char *path, bool recursive) { +int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags) { _cleanup_close_ int fd = -1; const char *subvolume; int r; @@ -943,11 +1292,194 @@ int btrfs_subvol_remove(const char *path, bool recursive) { if (fd < 0) return fd; - return subvol_remove_children(fd, subvolume, 0, recursive); + return subvol_remove_children(fd, subvolume, 0, flags); +} + +int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags) { + return subvol_remove_children(fd, subvolume, 0, flags); +} + +int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid) { + + struct btrfs_ioctl_search_args args = { + /* Tree of quota items */ + .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID, + + /* The object ID is always 0 */ + .key.min_objectid = 0, + .key.max_objectid = 0, + + /* Look precisely for the quota items */ + .key.min_type = BTRFS_QGROUP_LIMIT_KEY, + .key.max_type = BTRFS_QGROUP_LIMIT_KEY, + + /* For our qgroup */ + .key.min_offset = old_qgroupid, + .key.max_offset = old_qgroupid, + + /* No restrictions on the other components */ + .key.min_transid = 0, + .key.max_transid = (uint64_t) -1, + }; + + int r; + + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + + while (btrfs_ioctl_search_args_compare(&args) <= 0) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; + + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) + return -errno; + + if (args.key.nr_items <= 0) + break; + + FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) { + const struct btrfs_qgroup_limit_item *qli = BTRFS_IOCTL_SEARCH_HEADER_BODY(sh); + struct btrfs_ioctl_qgroup_limit_args qargs; + unsigned c; + + /* Make sure we start the next search at least from this entry */ + btrfs_ioctl_search_args_set(&args, sh); + + if (sh->objectid != 0) + continue; + if (sh->type != BTRFS_QGROUP_LIMIT_KEY) + continue; + if (sh->offset != old_qgroupid) + continue; + + /* We found the entry, now copy things over. */ + + qargs = (struct btrfs_ioctl_qgroup_limit_args) { + .qgroupid = new_qgroupid, + + .lim.max_rfer = le64toh(qli->max_rfer), + .lim.max_excl = le64toh(qli->max_excl), + .lim.rsv_rfer = le64toh(qli->rsv_rfer), + .lim.rsv_excl = le64toh(qli->rsv_excl), + + .lim.flags = le64toh(qli->flags) & (BTRFS_QGROUP_LIMIT_MAX_RFER| + BTRFS_QGROUP_LIMIT_MAX_EXCL| + BTRFS_QGROUP_LIMIT_RSV_RFER| + BTRFS_QGROUP_LIMIT_RSV_EXCL), + }; + + for (c = 0;; c++) { + if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &qargs) < 0) { + if (errno == EBUSY && c < 10) { + (void) btrfs_quota_scan_wait(fd); + continue; + } + return -errno; + } + + break; + } + + return 1; + } + + /* Increase search key by one, to read the next item, if we can. */ + if (!btrfs_ioctl_search_args_inc(&args)) + break; + } + + return 0; +} + +static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) { + _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL; + bool copy_from_parent = false, insert_intermediary_qgroup = false; + int n_old_qgroups, n_old_parent_qgroups, r, i; + uint64_t old_parent_id; + + assert(fd >= 0); + + /* Copies a reduced form of quota information from the old to + * the new subvolume. */ + + n_old_qgroups = btrfs_qgroup_find_parents(fd, old_subvol_id, &old_qgroups); + if (n_old_qgroups <= 0) /* Nothing to copy */ + return n_old_qgroups; + + r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id); + if (r < 0) + return r; + + n_old_parent_qgroups = btrfs_qgroup_find_parents(fd, old_parent_id, &old_parent_qgroups); + if (n_old_parent_qgroups < 0) + return n_old_parent_qgroups; + + for (i = 0; i < n_old_qgroups; i++) { + uint64_t id; + int j; + + r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id); + if (r < 0) + return r; + + if (id == old_subvol_id) { + /* The old subvolume was member of a qgroup + * that had the same id, but a different level + * as it self. Let's set up something similar + * in the destination. */ + insert_intermediary_qgroup = true; + break; + } + + for (j = 0; j < n_old_parent_qgroups; j++) + if (old_parent_qgroups[j] == old_qgroups[i]) { + /* The old subvolume shared a common + * parent qgroup with its parent + * subvolume. Let's set up something + * similar in the destination. */ + copy_from_parent = true; + } + } + + if (!insert_intermediary_qgroup && !copy_from_parent) + return 0; + + return btrfs_subvol_auto_qgroup_fd(fd, new_subvol_id, insert_intermediary_qgroup); } -int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive) { - return subvol_remove_children(fd, subvolume, 0, recursive); +static int copy_subtree_quota_limits(int fd, uint64_t old_subvol, uint64_t new_subvol) { + uint64_t old_subtree_qgroup, new_subtree_qgroup; + bool changed; + int r; + + /* First copy the leaf limits */ + r = btrfs_qgroup_copy_limits(fd, old_subvol, new_subvol); + if (r < 0) + return r; + changed = r > 0; + + /* Then, try to copy the subtree limits, if there are any. */ + r = btrfs_subvol_find_subtree_qgroup(fd, old_subvol, &old_subtree_qgroup); + if (r < 0) + return r; + if (r == 0) + return changed; + + r = btrfs_subvol_find_subtree_qgroup(fd, new_subvol, &new_subtree_qgroup); + if (r < 0) + return r; + if (r == 0) + return changed; + + r = btrfs_qgroup_copy_limits(fd, old_subtree_qgroup, new_subtree_qgroup); + if (r != 0) + return r; + + return changed; } static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolume, uint64_t old_subvol_id, BtrfsSnapshotFlags flags) { @@ -978,12 +1510,12 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum assert(subvolume); strncpy(vol_args.name, subvolume, sizeof(vol_args.name)-1); - vol_args.fd = old_fd; if (ioctl(new_fd, BTRFS_IOC_SNAP_CREATE_V2, &vol_args) < 0) return -errno; - if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) + if (!(flags & BTRFS_SNAPSHOT_RECURSIVE) && + !(flags & BTRFS_SNAPSHOT_QUOTA)) return 0; if (old_subvol_id == 0) { @@ -996,6 +1528,17 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum if (r < 0) return r; + if (flags & BTRFS_SNAPSHOT_QUOTA) + (void) copy_quota_hierarchy(new_fd, old_subvol_id, new_subvol_id); + + if (!(flags & BTRFS_SNAPSHOT_RECURSIVE)) { + + if (flags & BTRFS_SNAPSHOT_QUOTA) + (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id); + + return 0; + } + args.key.min_offset = args.key.max_offset = old_subvol_id; while (btrfs_ioctl_search_args_compare(&args) <= 0) { @@ -1113,6 +1656,9 @@ static int subvol_snapshot_children(int old_fd, int new_fd, const char *subvolum break; } + if (flags & BTRFS_SNAPSHOT_QUOTA) + (void) copy_subtree_quota_limits(new_fd, old_subvol_id, new_subvol_id); + return 0; } @@ -1137,14 +1683,14 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag r = copy_directory_fd(old_fd, new_path, true); if (r < 0) { - btrfs_subvol_remove(new_path, false); + (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA); return r; } if (flags & BTRFS_SNAPSHOT_READ_ONLY) { r = btrfs_subvol_set_read_only(new_path, true); if (r < 0) { - btrfs_subvol_remove(new_path, false); + (void) btrfs_subvol_remove(new_path, BTRFS_REMOVE_QUOTA); return r; } } @@ -1175,3 +1721,302 @@ int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnaps return btrfs_subvol_snapshot_fd(old_fd, new_path, flags); } + +int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) { + + struct btrfs_ioctl_search_args args = { + /* Tree of quota items */ + .key.tree_id = BTRFS_QUOTA_TREE_OBJECTID, + + /* Look precisely for the quota relation items */ + .key.min_type = BTRFS_QGROUP_RELATION_KEY, + .key.max_type = BTRFS_QGROUP_RELATION_KEY, + + /* No restrictions on the other components */ + .key.min_offset = 0, + .key.max_offset = (uint64_t) -1, + + .key.min_transid = 0, + .key.max_transid = (uint64_t) -1, + }; + + _cleanup_free_ uint64_t *items = NULL; + size_t n_items = 0, n_allocated = 0; + int r; + + assert(fd >= 0); + assert(ret); + + if (qgroupid == 0) { + r = btrfs_subvol_get_id_fd(fd, &qgroupid); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } + + args.key.min_objectid = args.key.max_objectid = qgroupid; + + while (btrfs_ioctl_search_args_compare(&args) <= 0) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; + + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) + return -errno; + + if (args.key.nr_items <= 0) + break; + + FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) { + + /* Make sure we start the next search at least from this entry */ + btrfs_ioctl_search_args_set(&args, sh); + + if (sh->type != BTRFS_QGROUP_RELATION_KEY) + continue; + if (sh->offset < sh->objectid) + continue; + if (sh->objectid != qgroupid) + continue; + + if (!GREEDY_REALLOC(items, n_allocated, n_items+1)) + return -ENOMEM; + + items[n_items++] = sh->offset; + } + + /* Increase search key by one, to read the next item, if we can. */ + if (!btrfs_ioctl_search_args_inc(&args)) + break; + } + + if (n_items <= 0) { + *ret = NULL; + return 0; + } + + *ret = items; + items = NULL; + + return (int) n_items; +} + +int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermediary_qgroup) { + _cleanup_free_ uint64_t *qgroups = NULL; + uint64_t parent_subvol; + bool changed = false; + int n = 0, r; + + assert(fd >= 0); + + /* + * Sets up the specified subvolume's qgroup automatically in + * one of two ways: + * + * If insert_intermediary_qgroup is false, the subvolume's + * leaf qgroup will be assigned to the same parent qgroups as + * the subvolume's parent subvolume. + * + * If insert_intermediary_qgroup is true a new intermediary + * higher-level qgroup is created, with a higher level number, + * but reusing the id of the subvolume. The level number is + * picked as one smaller than the lowest level qgroup the + * parent subvolume is a member of. If the parent subvolume's + * leaf qgroup is assigned to no higher-level qgroup a new + * qgroup of level 255 is created instead. Either way, the new + * qgroup is then assigned to the parent's higher-level + * qgroup, and the subvolume itself is assigned to it. + * + * If the subvolume is already assigned to a higher level + * qgroup, no operation is executed. + * + * Effectively this means: regardless if + * insert_intermediary_qgroup is true or not, after this + * function is invoked the subvolume will be accounted within + * the same qgroups as the parent. However, if it is true, it + * will also get its own higher-level qgroup, which may in + * turn be used by subvolumes created beneath this subvolume + * later on. + * + * This hence defines a simple default qgroup setup for + * subvolumes, as long as this function is invoked on each + * created subvolume: each subvolume is always accounting + * together with its immediate parents. Optionally, if + * insert_intermediary_qgroup is true, it will also get a + * qgroup that then includes all its own child subvolumes. + */ + + if (subvol_id == 0) { + r = btrfs_is_subvol(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } + + n = btrfs_qgroup_find_parents(fd, subvol_id, &qgroups); + if (n < 0) + return n; + if (n > 0) /* already parent qgroups set up, let's bail */ + return 0; + + r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol); + if (r < 0) + return r; + + qgroups = mfree(qgroups); + n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups); + if (n < 0) + return n; + + if (insert_intermediary_qgroup) { + uint64_t lowest = 256, new_qgroupid; + bool created = false; + int i; + + /* Determine the lowest qgroup that the parent + * subvolume is assigned to. */ + + for (i = 0; i < n; i++) { + uint64_t level; + + r = btrfs_qgroupid_split(qgroups[i], &level, NULL); + if (r < 0) + return r; + + if (level < lowest) + lowest = level; + } + + if (lowest <= 1) /* There are no levels left we could use insert an intermediary qgroup at */ + return -EBUSY; + + r = btrfs_qgroupid_make(lowest - 1, subvol_id, &new_qgroupid); + if (r < 0) + return r; + + /* Create the new intermediary group, unless it already exists */ + r = btrfs_qgroup_create(fd, new_qgroupid); + if (r < 0 && r != -EEXIST) + return r; + if (r >= 0) + changed = created = true; + + for (i = 0; i < n; i++) { + r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]); + if (r < 0 && r != -EEXIST) { + if (created) + (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid); + + return r; + } + if (r >= 0) + changed = true; + } + + r = btrfs_qgroup_assign(fd, subvol_id, new_qgroupid); + if (r < 0 && r != -EEXIST) { + if (created) + (void) btrfs_qgroup_destroy_recursive(fd, new_qgroupid); + return r; + } + if (r >= 0) + changed = true; + + } else { + int i; + + /* Assign our subvolume to all the same qgroups as the parent */ + + for (i = 0; i < n; i++) { + r = btrfs_qgroup_assign(fd, subvol_id, qgroups[i]); + if (r < 0 && r != -EEXIST) + return r; + if (r >= 0) + changed = true; + } + } + + return changed; +} + +int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (fd < 0) + return -errno; + + return btrfs_subvol_auto_qgroup_fd(fd, subvol_id, create_intermediary_qgroup); +} + +int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) { + + struct btrfs_ioctl_search_args args = { + /* Tree of tree roots */ + .key.tree_id = BTRFS_ROOT_TREE_OBJECTID, + + /* Look precisely for the subvolume items */ + .key.min_type = BTRFS_ROOT_BACKREF_KEY, + .key.max_type = BTRFS_ROOT_BACKREF_KEY, + + /* No restrictions on the other components */ + .key.min_offset = 0, + .key.max_offset = (uint64_t) -1, + + .key.min_transid = 0, + .key.max_transid = (uint64_t) -1, + }; + int r; + + assert(fd >= 0); + assert(ret); + + if (subvol_id == 0) { + r = btrfs_subvol_get_id_fd(fd, &subvol_id); + if (r < 0) + return r; + } else { + r = btrfs_is_filesystem(fd); + if (r < 0) + return r; + if (!r) + return -ENOTTY; + } + + args.key.min_objectid = args.key.max_objectid = subvol_id; + + while (btrfs_ioctl_search_args_compare(&args) <= 0) { + const struct btrfs_ioctl_search_header *sh; + unsigned i; + + args.key.nr_items = 256; + if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) + return -errno; + + if (args.key.nr_items <= 0) + break; + + FOREACH_BTRFS_IOCTL_SEARCH_HEADER(i, sh, args) { + + if (sh->type != BTRFS_ROOT_BACKREF_KEY) + continue; + if (sh->objectid != subvol_id) + continue; + + *ret = sh->offset; + return 0; + } + } + + return -ENXIO; +} diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 8632c3638c..fc9efd72d5 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -47,42 +47,82 @@ typedef enum BtrfsSnapshotFlags { BTRFS_SNAPSHOT_FALLBACK_COPY = 1, BTRFS_SNAPSHOT_READ_ONLY = 2, BTRFS_SNAPSHOT_RECURSIVE = 4, + BTRFS_SNAPSHOT_QUOTA = 8, } BtrfsSnapshotFlags; +typedef enum BtrfsRemoveFlags { + BTRFS_REMOVE_RECURSIVE = 1, + BTRFS_REMOVE_QUOTA = 2, +} BtrfsRemoveFlags; + int btrfs_is_filesystem(int fd); int btrfs_is_subvol(int fd); +int btrfs_reflink(int infd, int outfd); +int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz); + +int btrfs_get_block_device_fd(int fd, dev_t *dev); +int btrfs_get_block_device(const char *path, dev_t *dev); + +int btrfs_defrag_fd(int fd); +int btrfs_defrag(const char *p); + +int btrfs_quota_enable_fd(int fd, bool b); +int btrfs_quota_enable(const char *path, bool b); + +int btrfs_quota_scan_start(int fd); +int btrfs_quota_scan_wait(int fd); +int btrfs_quota_scan_ongoing(int fd); + +int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only); +int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only); + int btrfs_subvol_make(const char *path); int btrfs_subvol_make_label(const char *path); int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlags flags); int btrfs_subvol_snapshot(const char *old_path, const char *new_path, BtrfsSnapshotFlags flags); +int btrfs_subvol_remove(const char *path, BtrfsRemoveFlags flags); +int btrfs_subvol_remove_fd(int fd, const char *subvolume, BtrfsRemoveFlags flags); + int btrfs_subvol_set_read_only_fd(int fd, bool b); int btrfs_subvol_set_read_only(const char *path, bool b); int btrfs_subvol_get_read_only_fd(int fd); + int btrfs_subvol_get_id(int fd, const char *subvolume, uint64_t *ret); int btrfs_subvol_get_id_fd(int fd, uint64_t *ret); -int btrfs_subvol_get_info_fd(int fd, BtrfsSubvolInfo *info); -int btrfs_subvol_get_quota_fd(int fd, BtrfsQuotaInfo *quota); +int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret); -int btrfs_reflink(int infd, int outfd); -int btrfs_clone_range(int infd, uint64_t in_offset, int ofd, uint64_t out_offset, uint64_t sz); +int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *info); -int btrfs_get_block_device_fd(int fd, dev_t *dev); -int btrfs_get_block_device(const char *path, dev_t *dev); +int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret); -int btrfs_defrag_fd(int fd); -int btrfs_defrag(const char *p); +int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQuotaInfo *quota); +int btrfs_subvol_get_subtree_quota_fd(int fd, uint64_t subvol_id, BtrfsQuotaInfo *quota); -int btrfs_quota_enable_fd(int fd, bool b); -int btrfs_quota_enable(const char *path, bool b); +int btrfs_subvol_set_subtree_quota_limit(const char *path, uint64_t subvol_id, uint64_t referenced_max); +int btrfs_subvol_set_subtree_quota_limit_fd(int fd, uint64_t subvol_id, uint64_t referenced_max); -int btrfs_quota_limit_fd(int fd, uint64_t referenced_max); -int btrfs_quota_limit(const char *path, uint64_t referenced_max); +int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool new_qgroup); +int btrfs_subvol_auto_qgroup(const char *path, uint64_t subvol_id, bool create_intermediary_qgroup); -int btrfs_resize_loopback_fd(int fd, uint64_t size, bool grow_only); -int btrfs_resize_loopback(const char *path, uint64_t size, bool grow_only); +int btrfs_qgroupid_make(uint64_t level, uint64_t id, uint64_t *ret); +int btrfs_qgroupid_split(uint64_t qgroupid, uint64_t *level, uint64_t *id); + +int btrfs_qgroup_create(int fd, uint64_t qgroupid); +int btrfs_qgroup_destroy(int fd, uint64_t qgroupid); +int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid); + +int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max); +int btrfs_qgroup_set_limit(const char *path, uint64_t qgroupid, uint64_t referenced_max); + +int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupid); + +int btrfs_qgroup_assign(int fd, uint64_t child, uint64_t parent); +int btrfs_qgroup_unassign(int fd, uint64_t child, uint64_t parent); + +int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret); -int btrfs_subvol_remove(const char *path, bool recursive); -int btrfs_subvol_remove_fd(int fd, const char *subvolume, bool recursive); +int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *quota); +int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo *quota); diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c index ccc9f2bf8e..c1534657ac 100644 --- a/src/basic/bus-label.c +++ b/src/basic/bus-label.c @@ -21,10 +21,11 @@ #include <stdlib.h> -#include "util.h" -#include "macro.h" - +#include "alloc-util.h" #include "bus-label.h" +#include "hexdecoct.h" +#include "macro.h" +#include "util.h" char *bus_label_escape(const char *s) { char *r, *t; diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 2dcc9c5575..a6a906f453 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -22,7 +22,10 @@ #include <stdlib.h> #include <string.h> +#include "alloc-util.h" +#include "string-util.h" #include "calendarspec.h" +#include "fileio.h" #define BITS_WEEKDAYS 127 @@ -279,6 +282,9 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { fputc(':', f); format_chain(f, 2, c->second); + if (c->utc) + fputs(" UTC", f); + r = fflush_and_check(f); if (r < 0) { free(buf); @@ -646,6 +652,7 @@ fail: int calendar_spec_from_string(const char *p, CalendarSpec **spec) { CalendarSpec *c; int r; + const char *utc; assert(p); assert(spec); @@ -657,6 +664,12 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { if (!c) return -ENOMEM; + utc = endswith_no_case(p, " UTC"); + if (utc) { + c->utc = true; + p = strndupa(p, utc - p); + } + if (strcaseeq(p, "minutely")) { r = const_chain(0, &c->second); if (r < 0) @@ -859,13 +872,13 @@ static int find_matching_component(const CalendarComponent *c, int *val) { return r; } -static bool tm_out_of_bounds(const struct tm *tm) { +static bool tm_out_of_bounds(const struct tm *tm, bool utc) { struct tm t; assert(tm); t = *tm; - if (mktime(&t) == (time_t) -1) + if (mktime_or_timegm(&t, utc) == (time_t) -1) return true; /* Did any normalization take place? If so, it was out of bounds before */ @@ -878,7 +891,7 @@ static bool tm_out_of_bounds(const struct tm *tm) { t.tm_sec != tm->tm_sec; } -static bool matches_weekday(int weekdays_bits, const struct tm *tm) { +static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { struct tm t; int k; @@ -886,7 +899,7 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm) { return true; t = *tm; - if (mktime(&t) == (time_t) -1) + if (mktime_or_timegm(&t, utc) == (time_t) -1) return false; k = t.tm_wday == 0 ? 6 : t.tm_wday - 1; @@ -904,7 +917,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { for (;;) { /* Normalize the current date */ - mktime(&c); + mktime_or_timegm(&c, spec->utc); c.tm_isdst = -1; c.tm_year += 1900; @@ -916,7 +929,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = 0; } - if (r < 0 || tm_out_of_bounds(&c)) + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) return r; c.tm_mon += 1; @@ -927,7 +940,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = 0; } - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_year ++; c.tm_mon = 0; c.tm_mday = 1; @@ -938,14 +951,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { r = find_matching_component(spec->day, &c.tm_mday); if (r > 0) c.tm_hour = c.tm_min = c.tm_sec = 0; - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_mon ++; c.tm_mday = 1; c.tm_hour = c.tm_min = c.tm_sec = 0; continue; } - if (!matches_weekday(spec->weekdays_bits, &c)) { + if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) { c.tm_mday++; c.tm_hour = c.tm_min = c.tm_sec = 0; continue; @@ -954,7 +967,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { r = find_matching_component(spec->hour, &c.tm_hour); if (r > 0) c.tm_min = c.tm_sec = 0; - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_mday ++; c.tm_hour = c.tm_min = c.tm_sec = 0; continue; @@ -963,14 +976,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { r = find_matching_component(spec->minute, &c.tm_min); if (r > 0) c.tm_sec = 0; - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_hour ++; c.tm_min = c.tm_sec = 0; continue; } r = find_matching_component(spec->second, &c.tm_sec); - if (r < 0 || tm_out_of_bounds(&c)) { + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_min ++; c.tm_sec = 0; continue; @@ -991,13 +1004,13 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) assert(next); t = (time_t) (usec / USEC_PER_SEC) + 1; - assert_se(localtime_r(&t, &tm)); + assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc)); r = find_next(spec, &tm); if (r < 0) return r; - t = mktime(&tm); + t = mktime_or_timegm(&tm, spec->utc); if (t == (time_t) -1) return -EINVAL; diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h index 7baf318249..56dc02f391 100644 --- a/src/basic/calendarspec.h +++ b/src/basic/calendarspec.h @@ -36,6 +36,7 @@ typedef struct CalendarComponent { typedef struct CalendarSpec { int weekdays_bits; + bool utc; CalendarComponent *year; CalendarComponent *month; diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index bd5bffbfa5..4d391510bc 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -21,9 +21,10 @@ #include <string.h> -#include "util.h" #include "cap-list.h" #include "missing.h" +#include "parse-util.h" +#include "util.h" static const struct capability_name* lookup_capability(register const char *str, register unsigned int len); diff --git a/src/basic/capability.c b/src/basic/capability-util.c index 8dbe4da5bb..0eb5c03d65 100644 --- a/src/basic/capability.c +++ b/src/basic/capability-util.c @@ -19,18 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> +#include <grp.h> #include <stdio.h> #include <sys/capability.h> #include <sys/prctl.h> -#include "grp.h" +#include <unistd.h> +#include "alloc-util.h" +#include "capability-util.h" +#include "fileio.h" +#include "log.h" #include "macro.h" +#include "parse-util.h" #include "util.h" -#include "log.h" -#include "fileio.h" -#include "capability.h" int have_effective_cap(int value) { _cleanup_cap_free_ cap_t cap; @@ -276,10 +278,8 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) { assert(keep_capabilities & (1ULL << (i - 1))); if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 || - cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0) { - log_error_errno(errno, "Failed to enable capabilities bits: %m"); - return -errno; - } + cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0) + return log_error_errno(errno, "Failed to enable capabilities bits: %m"); if (cap_set_proc(d) < 0) return log_error_errno(errno, "Failed to increase capabilities: %m"); diff --git a/src/basic/capability.h b/src/basic/capability-util.h index 4eb5c2a835..4eb5c2a835 100644 --- a/src/basic/capability.h +++ b/src/basic/capability-util.h diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index 95fc2b9e5d..f7fc2c2c97 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -19,28 +19,39 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <dirent.h> #include <errno.h> -#include <unistd.h> +#include <ftw.h> #include <signal.h> -#include <string.h> #include <stdlib.h> -#include <dirent.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> -#include <ftw.h> +#include <unistd.h> -#include "set.h" -#include "macro.h" -#include "util.h" +#include "alloc-util.h" +#include "cgroup-util.h" +#include "dirent-util.h" +#include "extract-word.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" -#include "process-util.h" +#include "fs-util.h" +#include "login-util.h" +#include "macro.h" +#include "mkdir.h" +#include "parse-util.h" #include "path-util.h" -#include "unit-name.h" -#include "fileio.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "set.h" #include "special.h" -#include "mkdir.h" -#include "login-util.h" -#include "cgroup-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "unit-name.h" +#include "user-util.h" +#include "util.h" int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { _cleanup_free_ char *fs = NULL; diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c new file mode 100644 index 0000000000..d49ca0537a --- /dev/null +++ b/src/basic/chattr-util.c @@ -0,0 +1,107 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <linux/fs.h> + +#include "chattr-util.h" +#include "fd-util.h" +#include "util.h" + +int chattr_fd(int fd, unsigned value, unsigned mask) { + unsigned old_attr, new_attr; + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + /* Explicitly check whether this is a regular file or + * directory. If it is anything else (such as a device node or + * fifo), then the ioctl will not hit the file systems but + * possibly drivers, where the ioctl might have different + * effects. Notably, DRM is using the same ioctl() number. */ + + if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) + return -ENOTTY; + + if (mask == 0) + return 0; + + if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) + return -errno; + + new_attr = (old_attr & ~mask) | (value & mask); + if (new_attr == old_attr) + return 0; + + if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) + return -errno; + + return 1; +} + +int chattr_path(const char *p, unsigned value, unsigned mask) { + _cleanup_close_ int fd = -1; + + assert(p); + + if (mask == 0) + return 0; + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return chattr_fd(fd, value, mask); +} + +int read_attr_fd(int fd, unsigned *ret) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) + return -ENOTTY; + + if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) + return -errno; + + return 0; +} + +int read_attr_path(const char *p, unsigned *ret) { + _cleanup_close_ int fd = -1; + + assert(p); + assert(ret); + + fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + + return read_attr_fd(fd, ret); +} diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h new file mode 100644 index 0000000000..ba6b8eb5c1 --- /dev/null +++ b/src/basic/chattr-util.h @@ -0,0 +1,28 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +int chattr_fd(int fd, unsigned value, unsigned mask); +int chattr_path(const char *p, unsigned value, unsigned mask); + +int read_attr_fd(int fd, unsigned *ret); +int read_attr_path(const char *p, unsigned *ret); diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index e4e03df1e4..00ee4c2796 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -20,15 +20,17 @@ ***/ #include <errno.h> -#include <stdio.h> #include <fcntl.h> +#include <linux/rtc.h> +#include <stdio.h> #include <sys/ioctl.h> #include <sys/time.h> -#include <linux/rtc.h> +#include "clock-util.h" +#include "fd-util.h" #include "macro.h" +#include "string-util.h" #include "util.h" -#include "clock-util.h" int clock_get_hwclock(struct tm *tm) { _cleanup_close_ int fd = -1; diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index 8c2d235430..fef2d471a6 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -21,6 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <time.h> int clock_is_localtime(void); int clock_set_timezone(int *min); diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index da8745b284..be9972ffff 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -19,20 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> +#include <dirent.h> #include <errno.h> -#include <stdlib.h> #include <stdio.h> -#include <dirent.h> +#include <stdlib.h> +#include <string.h> +#include "conf-files.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "hashmap.h" +#include "log.h" #include "macro.h" -#include "util.h" #include "missing.h" -#include "log.h" -#include "strv.h" #include "path-util.h" -#include "hashmap.h" -#include "conf-files.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { _cleanup_closedir_ DIR *dir = NULL; diff --git a/src/basic/copy.c b/src/basic/copy.c index b20c178727..a187ae08fe 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -22,10 +22,20 @@ #include <sys/sendfile.h> #include <sys/xattr.h> -#include "util.h" +#include "alloc-util.h" #include "btrfs-util.h" -#include "strv.h" +#include "chattr-util.h" #include "copy.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "string-util.h" +#include "strv.h" +#include "umask-util.h" +#include "util.h" +#include "xattr-util.h" #define COPY_BUFFER_SIZE (16*1024) diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c new file mode 100644 index 0000000000..e2ec4ca83f --- /dev/null +++ b/src/basic/cpu-set-util.c @@ -0,0 +1,111 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2015 Lennart Poettering + Copyright 2015 Filipe Brandenburger + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "cpu-set-util.h" +#include "extract-word.h" +#include "parse-util.h" +#include "string-util.h" +#include "util.h" + +cpu_set_t* cpu_set_malloc(unsigned *ncpus) { + cpu_set_t *c; + unsigned n = 1024; + + /* Allocates the cpuset in the right size */ + + for (;;) { + c = CPU_ALLOC(n); + if (!c) + return NULL; + + if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) { + CPU_ZERO_S(CPU_ALLOC_SIZE(n), c); + + if (ncpus) + *ncpus = n; + + return c; + } + + CPU_FREE(c); + + if (errno != EINVAL) + return NULL; + + n *= 2; + } +} + +int parse_cpu_set_and_warn( + const char *rvalue, + cpu_set_t **cpu_set, + const char *unit, + const char *filename, + unsigned line, + const char *lvalue) { + + const char *whole_rvalue = rvalue; + _cleanup_cpu_free_ cpu_set_t *c = NULL; + unsigned ncpus = 0; + + assert(lvalue); + assert(rvalue); + + for (;;) { + _cleanup_free_ char *word = NULL; + unsigned cpu, cpu_lower, cpu_upper; + int r; + + r = extract_first_word(&rvalue, &word, WHITESPACE ",", EXTRACT_QUOTES); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue); + if (r == 0) + break; + + if (!c) { + c = cpu_set_malloc(&ncpus); + if (!c) + return log_oom(); + } + + r = parse_range(word, &cpu_lower, &cpu_upper); + if (r < 0) + return log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU affinity '%s'", word); + if (cpu_lower >= ncpus || cpu_upper >= ncpus) + return log_syntax(unit, LOG_ERR, filename, line, EINVAL, "CPU out of range '%s' ncpus is %u", word, ncpus); + + if (cpu_lower > cpu_upper) + log_syntax(unit, LOG_WARNING, filename, line, 0, "Range '%s' is invalid, %u > %u", word, cpu_lower, cpu_upper); + else + for (cpu = cpu_lower; cpu <= cpu_upper; cpu++) + CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); + } + + /* On success, sets *cpu_set and returns ncpus for the system. */ + if (c) { + *cpu_set = c; + c = NULL; + } + + return (int) ncpus; +} diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h new file mode 100644 index 0000000000..19b457a684 --- /dev/null +++ b/src/basic/cpu-set-util.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2015 Lennart Poettering + Copyright 2015 Filipe Brandenburger + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sched.h> + +#include "macro.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); +#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) + +cpu_set_t* cpu_set_malloc(unsigned *ncpus); + +int parse_cpu_set_and_warn(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); diff --git a/src/basic/def.h b/src/basic/def.h index 7c4161eb72..950f693899 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -35,17 +35,14 @@ * the watchdog pings will keep the loop busy. */ #define DEFAULT_EXIT_USEC (30*USEC_PER_SEC) +/* The default value for the net.unix.max_dgram_qlen sysctl */ +#define DEFAULT_UNIX_MAX_DGRAM_QLEN 512UL + #define SYSTEMD_CGROUP_CONTROLLER "name=systemd" #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT #define SIGNALS_IGNORE SIGPIPE -#define DIGITS "0123456789" -#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" -#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS -#define ALPHANUMERICAL LETTERS DIGITS - #define REBOOT_PARAM_FILE "/run/systemd/reboot-param" #ifdef HAVE_SPLIT_USR @@ -78,3 +75,18 @@ #define NOTIFY_FD_MAX 768 #define NOTIFY_BUFFER_MAX PIPE_BUF + +/* Return a nulstr for a standard cascade of configuration directories, + * suitable to pass to conf_files_list_nulstr or config_parse_many. */ +#define CONF_DIRS_NULSTR(n) \ + "/etc/" n ".d\0" \ + "/run/" n ".d\0" \ + "/usr/local/lib/" n ".d\0" \ + "/usr/lib/" n ".d\0" \ + CONF_DIR_SPLIT_USR(n) + +#ifdef HAVE_SPLIT_USR +#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0" +#else +#define CONF_DIR_SPLIT_USR(n) +#endif diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h index 04ba4897e5..7db81f3d52 100644 --- a/src/basic/device-nodes.h +++ b/src/basic/device-nodes.h @@ -21,5 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <sys/types.h> + int encode_devnode_name(const char *str, char *str_enc, size_t len); int whitelisted_char_for_devnode(char c, const char *additional); diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c new file mode 100644 index 0000000000..c433d5844a --- /dev/null +++ b/src/basic/dirent-util.c @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "dirent-util.h" +#include "string-util.h" + +int dirent_ensure_type(DIR *d, struct dirent *de) { + struct stat st; + + assert(d); + assert(de); + + if (de->d_type != DT_UNKNOWN) + return 0; + + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + return -errno; + + de->d_type = + S_ISREG(st.st_mode) ? DT_REG : + S_ISDIR(st.st_mode) ? DT_DIR : + S_ISLNK(st.st_mode) ? DT_LNK : + S_ISFIFO(st.st_mode) ? DT_FIFO : + S_ISSOCK(st.st_mode) ? DT_SOCK : + S_ISCHR(st.st_mode) ? DT_CHR : + S_ISBLK(st.st_mode) ? DT_BLK : + DT_UNKNOWN; + + return 0; +} + +bool dirent_is_file(const struct dirent *de) { + assert(de); + + if (hidden_file(de->d_name)) + return false; + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + return false; + + return true; +} + +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { + assert(de); + + if (de->d_type != DT_REG && + de->d_type != DT_LNK && + de->d_type != DT_UNKNOWN) + return false; + + if (hidden_file_allow_backup(de->d_name)) + return false; + + return endswith(de->d_name, suffix); +} diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h new file mode 100644 index 0000000000..5866a755f4 --- /dev/null +++ b/src/basic/dirent-util.h @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <dirent.h> + +#include "path-util.h" + +int dirent_ensure_type(DIR *d, struct dirent *de); + +bool dirent_is_file(const struct dirent *de) _pure_; +bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; + +#define FOREACH_DIRENT(de, d, on_error) \ + for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ + if (!de) { \ + if (errno > 0) { \ + on_error; \ + } \ + break; \ + } else if (hidden_file((de)->d_name)) \ + continue; \ + else + +#define FOREACH_DIRENT_ALL(de, d, on_error) \ + for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ + if (!de) { \ + if (errno > 0) { \ + on_error; \ + } \ + break; \ + } else diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 4804a67f91..9ddac5d6a1 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -22,11 +22,14 @@ #include <limits.h> #include <unistd.h> +#include "alloc-util.h" +#include "def.h" +#include "env-util.h" +#include "parse-util.h" +#include "string-util.h" #include "strv.h" #include "utf8.h" #include "util.h" -#include "env-util.h" -#include "def.h" #define VALID_CHARS_ENV_NAME \ DIGITS LETTERS \ @@ -541,7 +544,7 @@ char **replace_env_argv(char **argv, char **env) { STRV_FOREACH(i, argv) { /* If $FOO appears as single word, replace it by the split up variable */ - if ((*i)[0] == '$' && (*i)[1] != '{') { + if ((*i)[0] == '$' && (*i)[1] != '{' && (*i)[1] != '$') { char *e; char **w, **m = NULL; unsigned q; @@ -592,3 +595,13 @@ char **replace_env_argv(char **argv, char **env) { ret[k] = NULL; return ret; } + +int getenv_bool(const char *p) { + const char *e; + + e = getenv(p); + if (!e) + return -ENXIO; + + return parse_boolean(e); +} diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 803aa61cad..6485dade18 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -47,3 +47,5 @@ char **strv_env_unset_many(char **l, ...) _sentinel_; char *strv_env_get_n(char **l, const char *name, size_t k) _pure_; char *strv_env_get(char **x, const char *n) _pure_; + +int getenv_bool(const char *p); diff --git a/src/basic/escape.c b/src/basic/escape.c new file mode 100644 index 0000000000..4815161b09 --- /dev/null +++ b/src/basic/escape.c @@ -0,0 +1,482 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "hexdecoct.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" + +size_t cescape_char(char c, char *buf) { + char * buf_old = buf; + + switch (c) { + + case '\a': + *(buf++) = '\\'; + *(buf++) = 'a'; + break; + case '\b': + *(buf++) = '\\'; + *(buf++) = 'b'; + break; + case '\f': + *(buf++) = '\\'; + *(buf++) = 'f'; + break; + case '\n': + *(buf++) = '\\'; + *(buf++) = 'n'; + break; + case '\r': + *(buf++) = '\\'; + *(buf++) = 'r'; + break; + case '\t': + *(buf++) = '\\'; + *(buf++) = 't'; + break; + case '\v': + *(buf++) = '\\'; + *(buf++) = 'v'; + break; + case '\\': + *(buf++) = '\\'; + *(buf++) = '\\'; + break; + case '"': + *(buf++) = '\\'; + *(buf++) = '"'; + break; + case '\'': + *(buf++) = '\\'; + *(buf++) = '\''; + break; + + default: + /* For special chars we prefer octal over + * hexadecimal encoding, simply because glib's + * g_strescape() does the same */ + if ((c < ' ') || (c >= 127)) { + *(buf++) = '\\'; + *(buf++) = octchar((unsigned char) c >> 6); + *(buf++) = octchar((unsigned char) c >> 3); + *(buf++) = octchar((unsigned char) c); + } else + *(buf++) = c; + break; + } + + return buf - buf_old; +} + +char *cescape(const char *s) { + char *r, *t; + const char *f; + + assert(s); + + /* Does C style string escaping. May be reversed with + * cunescape(). */ + + r = new(char, strlen(s)*4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) + t += cescape_char(*f, t); + + *t = 0; + + return r; +} + +int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { + int r = 1; + + assert(p); + assert(*p); + assert(ret); + + /* Unescapes C style. Returns the unescaped character in ret, + * unless we encountered a \u sequence in which case the full + * unicode character is returned in ret_unicode, instead. */ + + if (length != (size_t) -1 && length < 1) + return -EINVAL; + + switch (p[0]) { + + case 'a': + *ret = '\a'; + break; + case 'b': + *ret = '\b'; + break; + case 'f': + *ret = '\f'; + break; + case 'n': + *ret = '\n'; + break; + case 'r': + *ret = '\r'; + break; + case 't': + *ret = '\t'; + break; + case 'v': + *ret = '\v'; + break; + case '\\': + *ret = '\\'; + break; + case '"': + *ret = '"'; + break; + case '\'': + *ret = '\''; + break; + + case 's': + /* This is an extension of the XDG syntax files */ + *ret = ' '; + break; + + case 'x': { + /* hexadecimal encoding */ + int a, b; + + if (length != (size_t) -1 && length < 3) + return -EINVAL; + + a = unhexchar(p[1]); + if (a < 0) + return -EINVAL; + + b = unhexchar(p[2]); + if (b < 0) + return -EINVAL; + + /* Don't allow NUL bytes */ + if (a == 0 && b == 0) + return -EINVAL; + + *ret = (char) ((a << 4U) | b); + r = 3; + break; + } + + case 'u': { + /* C++11 style 16bit unicode */ + + int a[4]; + unsigned i; + uint32_t c; + + if (length != (size_t) -1 && length < 5) + return -EINVAL; + + for (i = 0; i < 4; i++) { + a[i] = unhexchar(p[1 + i]); + if (a[i] < 0) + return a[i]; + } + + c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; + + /* Don't allow 0 chars */ + if (c == 0) + return -EINVAL; + + if (c < 128) + *ret = c; + else { + if (!ret_unicode) + return -EINVAL; + + *ret = 0; + *ret_unicode = c; + } + + r = 5; + break; + } + + case 'U': { + /* C++11 style 32bit unicode */ + + int a[8]; + unsigned i; + uint32_t c; + + if (length != (size_t) -1 && length < 9) + return -EINVAL; + + for (i = 0; i < 8; i++) { + a[i] = unhexchar(p[1 + i]); + if (a[i] < 0) + return a[i]; + } + + c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | + ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; + + /* Don't allow 0 chars */ + if (c == 0) + return -EINVAL; + + /* Don't allow invalid code points */ + if (!unichar_is_valid(c)) + return -EINVAL; + + if (c < 128) + *ret = c; + else { + if (!ret_unicode) + return -EINVAL; + + *ret = 0; + *ret_unicode = c; + } + + r = 9; + break; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + /* octal encoding */ + int a, b, c; + uint32_t m; + + if (length != (size_t) -1 && length < 3) + return -EINVAL; + + a = unoctchar(p[0]); + if (a < 0) + return -EINVAL; + + b = unoctchar(p[1]); + if (b < 0) + return -EINVAL; + + c = unoctchar(p[2]); + if (c < 0) + return -EINVAL; + + /* don't allow NUL bytes */ + if (a == 0 && b == 0 && c == 0) + return -EINVAL; + + /* Don't allow bytes above 255 */ + m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; + if (m > 255) + return -EINVAL; + + *ret = m; + r = 3; + break; + } + + default: + return -EINVAL; + } + + return r; +} + +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) { + char *r, *t; + const char *f; + size_t pl; + + assert(s); + assert(ret); + + /* Undoes C style string escaping, and optionally prefixes it. */ + + pl = prefix ? strlen(prefix) : 0; + + r = new(char, pl+length+1); + if (!r) + return -ENOMEM; + + if (prefix) + memcpy(r, prefix, pl); + + for (f = s, t = r + pl; f < s + length; f++) { + size_t remaining; + uint32_t u; + char c; + int k; + + remaining = s + length - f; + assert(remaining > 0); + + if (*f != '\\') { + /* A literal literal, copy verbatim */ + *(t++) = *f; + continue; + } + + if (remaining == 1) { + if (flags & UNESCAPE_RELAX) { + /* A trailing backslash, copy verbatim */ + *(t++) = *f; + continue; + } + + free(r); + return -EINVAL; + } + + k = cunescape_one(f + 1, remaining - 1, &c, &u); + if (k < 0) { + if (flags & UNESCAPE_RELAX) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + continue; + } + + free(r); + return k; + } + + if (c != 0) + /* Non-Unicode? Let's encode this directly */ + *(t++) = c; + else + /* Unicode? Then let's encode this in UTF-8 */ + t += utf8_encode_unichar(t, u); + + f += k; + } + + *t = 0; + + *ret = r; + return t - r; +} + +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { + return cunescape_length_with_prefix(s, length, NULL, flags, ret); +} + +int cunescape(const char *s, UnescapeFlags flags, char **ret) { + return cunescape_length(s, strlen(s), flags, ret); +} + +char *xescape(const char *s, const char *bad) { + char *r, *t; + const char *f; + + /* Escapes all chars in bad, in addition to \ and all special + * chars, in \xFF style escaping. May be reversed with + * cunescape(). */ + + r = new(char, strlen(s) * 4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) { + + if ((*f < ' ') || (*f >= 127) || + (*f == '\\') || strchr(bad, *f)) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = hexchar(*f >> 4); + *(t++) = hexchar(*f); + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} + +static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { + assert(bad); + + for (; *s; s++) { + if (*s == '\\' || strchr(bad, *s)) + *(t++) = '\\'; + + *(t++) = *s; + } + + return t; +} + +char *shell_escape(const char *s, const char *bad) { + char *r, *t; + + r = new(char, strlen(s)*2+1); + if (!r) + return NULL; + + t = strcpy_backslash_escaped(r, s, bad); + *t = 0; + + return r; +} + +char *shell_maybe_quote(const char *s) { + const char *p; + char *r, *t; + + assert(s); + + /* Encloses a string in double quotes if necessary to make it + * OK as shell string. */ + + for (p = s; *p; p++) + if (*p <= ' ' || + *p >= 127 || + strchr(SHELL_NEED_QUOTES, *p)) + break; + + if (!*p) + return strdup(s); + + r = new(char, 1+strlen(s)*2+1+1); + if (!r) + return NULL; + + t = r; + *(t++) = '"'; + t = mempcpy(t, s, p - s); + + t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); + + *(t++)= '"'; + *t = 0; + + return r; +} diff --git a/src/basic/escape.h b/src/basic/escape.h new file mode 100644 index 0000000000..85ba909081 --- /dev/null +++ b/src/basic/escape.h @@ -0,0 +1,48 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/types.h> +#include <inttypes.h> + +/* What characters are special in the shell? */ +/* must be escaped outside and inside double-quotes */ +#define SHELL_NEED_ESCAPE "\"\\`$" +/* can be escaped or double-quoted */ +#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;" + +typedef enum UnescapeFlags { + UNESCAPE_RELAX = 1, +} UnescapeFlags; + +char *cescape(const char *s); +size_t cescape_char(char c, char *buf); + +int cunescape(const char *s, UnescapeFlags flags, char **ret); +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); +int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode); + +char *xescape(const char *s, const char *bad); + +char *shell_escape(const char *s, const char *bad); +char *shell_maybe_quote(const char *s); diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c new file mode 100644 index 0000000000..2bf3bfec1d --- /dev/null +++ b/src/basic/ether-addr-util.c @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdio.h> + +#include "ether-addr-util.h" +#include "macro.h" + +char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { + assert(addr); + assert(buffer); + + /* Like ether_ntoa() but uses %02x instead of %x to print + * ethernet addresses, which makes them look less funny. Also, + * doesn't use a static buffer. */ + + sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", + addr->ether_addr_octet[0], + addr->ether_addr_octet[1], + addr->ether_addr_octet[2], + addr->ether_addr_octet[3], + addr->ether_addr_octet[4], + addr->ether_addr_octet[5]); + + return buffer; +} diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 7033138788..008f3b893e 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -25,3 +25,7 @@ #define ETHER_ADDR_FORMAT_STR "%02X%02X%02X%02X%02X%02X" #define ETHER_ADDR_FORMAT_VAL(x) (x).ether_addr_octet[0], (x).ether_addr_octet[1], (x).ether_addr_octet[2], (x).ether_addr_octet[3], (x).ether_addr_octet[4], (x).ether_addr_octet[5] + +#define ETHER_ADDR_TO_STRING_MAX (3*6) + +char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c new file mode 100644 index 0000000000..6721b85c0a --- /dev/null +++ b/src/basic/extract-word.c @@ -0,0 +1,286 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "extract-word.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" + +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { + _cleanup_free_ char *s = NULL; + size_t allocated = 0, sz = 0; + int r; + + char quote = 0; /* 0 or ' or " */ + bool backslash = false; /* whether we've just seen a backslash */ + bool separator = false; /* whether we've just seen a separator */ + bool start = true; /* false means we're looking at a value */ + + assert(p); + assert(ret); + + if (!separators) + separators = WHITESPACE; + + /* Bail early if called after last value or with no input */ + if (!*p) + goto finish_force_terminate; + + /* Parses the first word of a string, and returns it in + * *ret. Removes all quotes in the process. When parsing fails + * (because of an uneven number of quotes or similar), leaves + * the pointer *p at the first invalid character. */ + + for (;;) { + char c = **p; + + if (start) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + + if (c == 0) + goto finish_force_terminate; + else if (strchr(separators, c)) { + (*p) ++; + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) + goto finish_force_next; + continue; + } + + /* We found a non-blank character, so we will always + * want to return a string (even if it is empty), + * allocate it here. */ + if (!GREEDY_REALLOC(s, allocated, sz+1)) + return -ENOMEM; + + start = false; + } + + if (backslash) { + if (!GREEDY_REALLOC(s, allocated, sz+7)) + return -ENOMEM; + + if (c == 0) { + if ((flags & EXTRACT_CUNESCAPE_RELAX) && + (!quote || flags & EXTRACT_RELAX)) { + /* If we find an unquoted trailing backslash and we're in + * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the + * output. + * + * Unbalanced quotes will only be allowed in EXTRACT_RELAX + * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. + */ + s[sz++] = '\\'; + goto finish_force_terminate; + } + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; + return -EINVAL; + } + + if (flags & EXTRACT_CUNESCAPE) { + uint32_t u; + + r = cunescape_one(*p, (size_t) -1, &c, &u); + if (r < 0) { + if (flags & EXTRACT_CUNESCAPE_RELAX) { + s[sz++] = '\\'; + s[sz++] = c; + goto end_escape; + } + return -EINVAL; + } + + (*p) += r - 1; + + if (c != 0) + s[sz++] = c; /* normal explicit char */ + else + sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ + } else + s[sz++] = c; + +end_escape: + backslash = false; + + } else if (quote) { /* inside either single or double quotes */ + if (c == 0) { + if (flags & EXTRACT_RELAX) + goto finish_force_terminate; + return -EINVAL; + } else if (c == quote) /* found the end quote */ + quote = 0; + else if (c == '\\') + backslash = true; + else { + if (!GREEDY_REALLOC(s, allocated, sz+2)) + return -ENOMEM; + + s[sz++] = c; + } + + } else if (separator) { + if (c == 0) + goto finish_force_terminate; + if (!strchr(separators, c)) + goto finish; + + } else { + if (c == 0) + goto finish_force_terminate; + else if ((c == '\'' || c == '"') && (flags & EXTRACT_QUOTES)) + quote = c; + else if (c == '\\') + backslash = true; + else if (strchr(separators, c)) { + if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { + (*p) ++; + goto finish_force_next; + } + separator = true; + } else { + if (!GREEDY_REALLOC(s, allocated, sz+2)) + return -ENOMEM; + + s[sz++] = c; + } + } + + (*p) ++; + } + +finish_force_terminate: + *p = NULL; +finish: + if (!s) { + *p = NULL; + *ret = NULL; + return 0; + } + +finish_force_next: + s[sz] = 0; + *ret = s; + s = NULL; + + return 1; +} + +int extract_first_word_and_warn( + const char **p, + char **ret, + const char *separators, + ExtractFlags flags, + const char *unit, + const char *filename, + unsigned line, + const char *rvalue) { + + /* Try to unquote it, if it fails, warn about it and try again + * but this time using EXTRACT_CUNESCAPE_RELAX to keep the + * backslashes verbatim in invalid escape sequences. */ + + const char *save; + int r; + + save = *p; + r = extract_first_word(p, ret, separators, flags); + if (r >= 0) + return r; + + if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) { + + /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ + *p = save; + r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); + if (r >= 0) { + /* It worked this time, hence it must have been an invalid escape sequence we could correct. */ + log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Invalid escape sequences in line, correcting: \"%s\"", rvalue); + return r; + } + + /* If it's still EINVAL; then it must be unbalanced quoting, report this. */ + if (r == -EINVAL) + return log_syntax(unit, LOG_ERR, filename, line, r, "Unbalanced quoting, ignoring: \"%s\"", rvalue); + } + + /* Can be any error, report it */ + return log_syntax(unit, LOG_ERR, filename, line, r, "Unable to decode word \"%s\", ignoring: %m", rvalue); +} + +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { + va_list ap; + char **l; + int n = 0, i, c, r; + + /* Parses a number of words from a string, stripping any + * quotes if necessary. */ + + assert(p); + + /* Count how many words are expected */ + va_start(ap, flags); + for (;;) { + if (!va_arg(ap, char **)) + break; + n++; + } + va_end(ap); + + if (n <= 0) + return 0; + + /* Read all words into a temporary array */ + l = newa0(char*, n); + for (c = 0; c < n; c++) { + + r = extract_first_word(p, &l[c], separators, flags); + if (r < 0) { + int j; + + for (j = 0; j < c; j++) + free(l[j]); + + return r; + } + + if (r == 0) + break; + } + + /* If we managed to parse all words, return them in the passed + * in parameters */ + va_start(ap, flags); + for (i = 0; i < n; i++) { + char **v; + + v = va_arg(ap, char **); + assert(v); + + *v = l[i]; + } + va_end(ap); + + return c; +} diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h new file mode 100644 index 0000000000..ddc1c4f463 --- /dev/null +++ b/src/basic/extract-word.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "macro.h" + +typedef enum ExtractFlags { + EXTRACT_RELAX = 1, + EXTRACT_CUNESCAPE = 2, + EXTRACT_CUNESCAPE_RELAX = 4, + EXTRACT_QUOTES = 8, + EXTRACT_DONT_COALESCE_SEPARATORS = 16, +} ExtractFlags; + +int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); +int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); +int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c new file mode 100644 index 0000000000..d1b1db3a4d --- /dev/null +++ b/src/basic/fd-util.c @@ -0,0 +1,351 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "dirent-util.h" +#include "fd-util.h" +#include "parse-util.h" +#include "socket-util.h" +#include "util.h" + +int close_nointr(int fd) { + assert(fd >= 0); + + if (close(fd) >= 0) + return 0; + + /* + * Just ignore EINTR; a retry loop is the wrong thing to do on + * Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (errno == EINTR) + return 0; + + return -errno; +} + +int safe_close(int fd) { + + /* + * Like close_nointr() but cannot fail. Guarantees errno is + * unchanged. Is a NOP with negative fds passed, and returns + * -1, so that it can be used in this syntax: + * + * fd = safe_close(fd); + */ + + if (fd >= 0) { + PROTECT_ERRNO; + + /* The kernel might return pretty much any error code + * via close(), but the fd will be closed anyway. The + * only condition we want to check for here is whether + * the fd was invalid at all... */ + + assert_se(close_nointr(fd) != -EBADF); + } + + return -1; +} + +void safe_close_pair(int p[]) { + assert(p); + + if (p[0] == p[1]) { + /* Special case pairs which use the same fd in both + * directions... */ + p[0] = p[1] = safe_close(p[0]); + return; + } + + p[0] = safe_close(p[0]); + p[1] = safe_close(p[1]); +} + +void close_many(const int fds[], unsigned n_fd) { + unsigned i; + + assert(fds || n_fd <= 0); + + for (i = 0; i < n_fd; i++) + safe_close(fds[i]); +} + +int fclose_nointr(FILE *f) { + assert(f); + + /* Same as close_nointr(), but for fclose() */ + + if (fclose(f) == 0) + return 0; + + if (errno == EINTR) + return 0; + + return -errno; +} + +FILE* safe_fclose(FILE *f) { + + /* Same as safe_close(), but for fclose() */ + + if (f) { + PROTECT_ERRNO; + + assert_se(fclose_nointr(f) != EBADF); + } + + return NULL; +} + +DIR* safe_closedir(DIR *d) { + + if (d) { + PROTECT_ERRNO; + + assert_se(closedir(d) >= 0 || errno != EBADF); + } + + return NULL; +} + +int fd_nonblock(int fd, bool nonblock) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) + return -errno; + + if (nonblock) + nflags = flags | O_NONBLOCK; + else + nflags = flags & ~O_NONBLOCK; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFL, nflags) < 0) + return -errno; + + return 0; +} + +int fd_cloexec(int fd, bool cloexec) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFD, 0); + if (flags < 0) + return -errno; + + if (cloexec) + nflags = flags | FD_CLOEXEC; + else + nflags = flags & ~FD_CLOEXEC; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFD, nflags) < 0) + return -errno; + + return 0; +} + +_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { + unsigned i; + + assert(n_fdset == 0 || fdset); + + for (i = 0; i < n_fdset; i++) + if (fdset[i] == fd) + return true; + + return false; +} + +int close_all_fds(const int except[], unsigned n_except) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(n_except == 0 || except); + + d = opendir("/proc/self/fd"); + if (!d) { + int fd; + struct rlimit rl; + + /* When /proc isn't available (for example in chroots) + * the fallback is brute forcing through the fd + * table */ + + assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); + for (fd = 3; fd < (int) rl.rlim_max; fd ++) { + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) + if (errno != EBADF && r == 0) + r = -errno; + } + + return r; + } + + while ((de = readdir(d))) { + int fd = -1; + + if (hidden_file(de->d_name)) + continue; + + if (safe_atoi(de->d_name, &fd) < 0) + /* Let's better ignore this, just in case */ + continue; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) { + /* Valgrind has its own FD and doesn't want to have it closed */ + if (errno != EBADF && r == 0) + r = -errno; + } + } + + return r; +} + +int same_fd(int a, int b) { + struct stat sta, stb; + pid_t pid; + int r, fa, fb; + + assert(a >= 0); + assert(b >= 0); + + /* Compares two file descriptors. Note that semantics are + * quite different depending on whether we have kcmp() or we + * don't. If we have kcmp() this will only return true for + * dup()ed file descriptors, but not otherwise. If we don't + * have kcmp() this will also return true for two fds of the same + * file, created by separate open() calls. Since we use this + * call mostly for filtering out duplicates in the fd store + * this difference hopefully doesn't matter too much. */ + + if (a == b) + return true; + + /* Try to use kcmp() if we have it. */ + pid = getpid(); + r = kcmp(pid, pid, KCMP_FILE, a, b); + if (r == 0) + return true; + if (r > 0) + return false; + if (errno != ENOSYS) + return -errno; + + /* We don't have kcmp(), use fstat() instead. */ + if (fstat(a, &sta) < 0) + return -errno; + + if (fstat(b, &stb) < 0) + return -errno; + + if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) + return false; + + /* We consider all device fds different, since two device fds + * might refer to quite different device contexts even though + * they share the same inode and backing dev_t. */ + + if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) + return false; + + if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) + return false; + + /* The fds refer to the same inode on disk, let's also check + * if they have the same fd flags. This is useful to + * distinguish the read and write side of a pipe created with + * pipe(). */ + fa = fcntl(a, F_GETFL); + if (fa < 0) + return -errno; + + fb = fcntl(b, F_GETFL); + if (fb < 0) + return -errno; + + return fa == fb; +} + +void cmsg_close_all(struct msghdr *mh) { + struct cmsghdr *cmsg; + + assert(mh); + + CMSG_FOREACH(cmsg, mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) + close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); +} + +bool fdname_is_valid(const char *s) { + const char *p; + + /* Validates a name for $LISTEN_FDNAMES. We basically allow + * everything ASCII that's not a control character. Also, as + * special exception the ":" character is not allowed, as we + * use that as field separator in $LISTEN_FDNAMES. + * + * Note that the empty string is explicitly allowed + * here. However, we limit the length of the names to 255 + * characters. */ + + if (!s) + return false; + + for (p = s; *p; p++) { + if (*p < ' ') + return false; + if (*p >= 127) + return false; + if (*p == ':') + return false; + } + + return p - s < 256; +} diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h new file mode 100644 index 0000000000..1ca10f0383 --- /dev/null +++ b/src/basic/fd-util.h @@ -0,0 +1,71 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdio.h> +#include <dirent.h> +#include <stdbool.h> +#include <sys/socket.h> + +#include "macro.h" + +int close_nointr(int fd); +int safe_close(int fd); +void safe_close_pair(int p[]); + +void close_many(const int fds[], unsigned n_fd); + +int fclose_nointr(FILE *f); +FILE* safe_fclose(FILE *f); +DIR* safe_closedir(DIR *f); + +static inline void closep(int *fd) { + safe_close(*fd); +} + +static inline void close_pairp(int (*p)[2]) { + safe_close_pair(*p); +} + +static inline void fclosep(FILE **f) { + safe_fclose(*f); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); + +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_pclose_ _cleanup_(pclosep) +#define _cleanup_closedir_ _cleanup_(closedirp) +#define _cleanup_close_pair_ _cleanup_(close_pairp) + +int fd_nonblock(int fd, bool nonblock); +int fd_cloexec(int fd, bool cloexec); + +int close_all_fds(const int except[], unsigned n_except); + +int same_fd(int a, int b); + +void cmsg_close_all(struct msghdr *mh); + +bool fdname_is_valid(const char *s); diff --git a/src/basic/fdset.c b/src/basic/fdset.c index d70fe156a2..42b0b2b98f 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -23,11 +23,15 @@ #include <dirent.h> #include <fcntl.h> +#include "sd-daemon.h" + +#include "dirent-util.h" +#include "fd-util.h" +#include "fdset.h" +#include "macro.h" +#include "parse-util.h" #include "set.h" #include "util.h" -#include "macro.h" -#include "fdset.h" -#include "sd-daemon.h" #define MAKE_SET(s) ((Set*) s) #define MAKE_FDSET(s) ((FDSet*) s) @@ -40,7 +44,7 @@ FDSet *fdset_new(void) { return MAKE_FDSET(set_new(NULL)); } -int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds) { +int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds) { unsigned i; FDSet *s; int r; diff --git a/src/basic/fdset.h b/src/basic/fdset.h index 340438d7c4..70d8acbcff 100644 --- a/src/basic/fdset.h +++ b/src/basic/fdset.h @@ -35,7 +35,7 @@ int fdset_consume(FDSet *s, int fd); bool fdset_contains(FDSet *s, int fd); int fdset_remove(FDSet *s, int fd); -int fdset_new_array(FDSet **ret, int *fds, unsigned n_fds); +int fdset_new_array(FDSet **ret, const int *fds, unsigned n_fds); int fdset_new_fill(FDSet **ret); int fdset_new_listen_fds(FDSet **ret, bool unset); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 4a9105f421..619dafb517 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -21,11 +21,20 @@ #include <unistd.h> -#include "util.h" -#include "strv.h" -#include "utf8.h" +#include "alloc-util.h" #include "ctype.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "hexdecoct.h" +#include "path-util.h" +#include "random-util.h" +#include "string-util.h" +#include "strv.h" +#include "umask-util.h" +#include "utf8.h" +#include "util.h" int write_string_stream(FILE *f, const char *line, bool enforce_newline) { @@ -51,7 +60,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor if (r < 0) return r; - fchmod_umask(fileno(f), 0644); + (void) fchmod_umask(fileno(f), 0644); r = write_string_stream(f, line, enforce_newline); if (r >= 0) { @@ -60,7 +69,7 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor } if (r < 0) - unlink(p); + (void) unlink(p); return r; } @@ -775,15 +784,19 @@ int executable_is_script(const char *path, char **interpreter) { /** * Retrieve one field from a file like /proc/self/status. pattern - * should start with '\n' and end with a ':'. Whitespace and zeros - * after the ':' will be skipped. field must be freed afterwards. + * should not include whitespace or the delimiter (':'). pattern matches only + * the beginning of a line. Whitespace before ':' is skipped. Whitespace and + * zeros after the ':' will be skipped. field must be freed afterwards. + * terminator specifies the terminating characters of the field value (not + * included in the value). */ -int get_status_field(const char *filename, const char *pattern, char **field) { +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { _cleanup_free_ char *status = NULL; char *t, *f; size_t len; int r; + assert(terminator); assert(filename); assert(pattern); assert(field); @@ -792,11 +805,31 @@ int get_status_field(const char *filename, const char *pattern, char **field) { if (r < 0) return r; - t = strstr(status, pattern); - if (!t) - return -ENOENT; + t = status; + + do { + bool pattern_ok; + + do { + t = strstr(t, pattern); + if (!t) + return -ENOENT; + + /* Check that pattern occurs in beginning of line. */ + pattern_ok = (t == status || t[-1] == '\n'); + + t += strlen(pattern); + + } while (!pattern_ok); + + t += strspn(t, " \t"); + if (!*t) + return -ENOENT; + + } while (*t != ':'); + + t++; - t += strlen(pattern); if (*t) { t += strspn(t, " \t"); @@ -812,7 +845,7 @@ int get_status_field(const char *filename, const char *pattern, char **field) { t --; } - len = strcspn(t, WHITESPACE); + len = strcspn(t, terminator); f = strndup(t, len); if (!f) @@ -821,3 +854,298 @@ int get_status_field(const char *filename, const char *pattern, char **field) { *field = f; return 0; } + +DIR *xopendirat(int fd, const char *name, int flags) { + int nfd; + DIR *d; + + assert(!(flags & O_CREAT)); + + nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); + if (nfd < 0) + return NULL; + + d = fdopendir(nfd); + if (!d) { + safe_close(nfd); + return NULL; + } + + return d; +} + +static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) { + char **i; + + assert(path); + assert(mode); + assert(_f); + + if (!path_strv_resolve_uniq(search, root)) + return -ENOMEM; + + STRV_FOREACH(i, search) { + _cleanup_free_ char *p = NULL; + FILE *f; + + if (root) + p = strjoin(root, *i, "/", path, NULL); + else + p = strjoin(*i, "/", path, NULL); + if (!p) + return -ENOMEM; + + f = fopen(p, mode); + if (f) { + *_f = f; + return 0; + } + + if (errno != ENOENT) + return -errno; + } + + return -ENOENT; +} + +int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) { + _cleanup_strv_free_ char **copy = NULL; + + assert(path); + assert(mode); + assert(_f); + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + copy = strv_copy((char**) search); + if (!copy) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, root, copy, _f); +} + +int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) { + _cleanup_strv_free_ char **s = NULL; + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + s = strv_split_nulstr(search); + if (!s) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, root, s, _f); +} + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { + FILE *f; + char *t; + int r, fd; + + assert(path); + assert(_f); + assert(_temp_path); + + r = tempfn_xxxxxx(path, NULL, &t); + if (r < 0) + return r; + + fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + free(t); + return -errno; + } + + f = fdopen(fd, "we"); + if (!f) { + unlink_noerrno(t); + free(t); + safe_close(fd); + return -errno; + } + + *_f = f; + *_temp_path = t; + + return 0; +} + +int fflush_and_check(FILE *f) { + assert(f); + + errno = 0; + fflush(f); + + if (ferror(f)) + return errno ? -errno : -EIO; + + return 0; +} + +/* This is much like like mkostemp() but is subject to umask(). */ +int mkostemp_safe(char *pattern, int flags) { + _cleanup_umask_ mode_t u; + int fd; + + assert(pattern); + + u = umask(077); + + fd = mkostemp(pattern, flags); + if (fd < 0) + return -errno; + + return fd; +} + +int open_tmpfile(const char *path, int flags) { + char *p; + int fd; + + assert(path); + +#ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ + fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + + /* Fall back to unguessable name + unlinking */ + p = strjoina(path, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, flags); + if (fd < 0) + return fd; + + unlink(p); + return fd; +} + +int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { + const char *fn; + char *t; + + assert(p); + assert(ret); + + /* + * Turns this: + * /foo/bar/waldo + * + * Into this: + * /foo/bar/.#<extra>waldoXXXXXX + */ + + fn = basename(p); + if (!filename_is_valid(fn)) + return -EINVAL; + + if (extra == NULL) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); + if (!t) + return -ENOMEM; + + strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); + + *ret = path_kill_slashes(t); + return 0; +} + +int tempfn_random(const char *p, const char *extra, char **ret) { + const char *fn; + char *t, *x; + uint64_t u; + unsigned i; + + assert(p); + assert(ret); + + /* + * Turns this: + * /foo/bar/waldo + * + * Into this: + * /foo/bar/.#<extra>waldobaa2a261115984a9 + */ + + fn = basename(p); + if (!filename_is_valid(fn)) + return -EINVAL; + + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); + if (!t) + return -ENOMEM; + + x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn); + + u = random_u64(); + for (i = 0; i < 16; i++) { + *(x++) = hexchar(u & 0xF); + u >>= 4; + } + + *x = 0; + + *ret = path_kill_slashes(t); + return 0; +} + +int tempfn_random_child(const char *p, const char *extra, char **ret) { + char *t, *x; + uint64_t u; + unsigned i; + + assert(p); + assert(ret); + + /* Turns this: + * /foo/bar/waldo + * Into this: + * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0 + */ + + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1); + if (!t) + return -ENOMEM; + + x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); + + u = random_u64(); + for (i = 0; i < 16; i++) { + *(x++) = hexchar(u & 0xF); + u >>= 4; + } + + *x = 0; + + *ret = path_kill_slashes(t); + return 0; +} diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 2e8148ff24..fa7f192331 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -20,8 +20,12 @@ You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ + +#include <dirent.h> +#include <stdbool.h> #include <stddef.h> #include <stdio.h> +#include <sys/types.h> #include "macro.h" @@ -48,4 +52,28 @@ int write_env_file(const char *fname, char **l); int executable_is_script(const char *path, char **interpreter); -int get_status_field(const char *filename, const char *pattern, char **field); +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); + +DIR *xopendirat(int dirfd, const char *name, int flags); + +int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); +int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); + +#define FOREACH_LINE(line, f, on_error) \ + for (;;) \ + if (!fgets(line, sizeof(line), f)) { \ + if (ferror(f)) { \ + on_error; \ + } \ + break; \ + } else + +int fflush_and_check(FILE *f); + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path); +int mkostemp_safe(char *pattern, int flags); +int open_tmpfile(const char *path, int flags); + +int tempfn_xxxxxx(const char *p, const char *extra, char **ret); +int tempfn_random(const char *p, const char *extra, char **ret); +int tempfn_random_child(const char *p, const char *extra, char **ret); diff --git a/src/shared/formats-util.h b/src/basic/formats-util.h index ce516b117d..ce516b117d 100644 --- a/src/shared/formats-util.h +++ b/src/basic/formats-util.h diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c new file mode 100644 index 0000000000..7aee404bfc --- /dev/null +++ b/src/basic/fs-util.c @@ -0,0 +1,480 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" + +int unlink_noerrno(const char *path) { + PROTECT_ERRNO; + int r; + + r = unlink(path); + if (r < 0) + return -errno; + + return 0; +} + +int rmdir_parents(const char *path, const char *stop) { + size_t l; + int r = 0; + + assert(path); + assert(stop); + + l = strlen(path); + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + while (l > 0) { + char *t; + + /* Skip last component */ + while (l > 0 && path[l-1] != '/') + l--; + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + if (l <= 0) + break; + + t = strndup(path, l); + if (!t) + return -ENOMEM; + + if (path_startswith(stop, t)) { + free(t); + return 0; + } + + r = rmdir(t); + free(t); + + if (r < 0) + if (errno != ENOENT) + return -errno; + } + + return 0; +} + + +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { + struct stat buf; + int ret; + + ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE); + if (ret >= 0) + return 0; + + /* renameat2() exists since Linux 3.15, btrfs added support for it later. + * If it is not implemented, fallback to another method. */ + if (!IN_SET(errno, EINVAL, ENOSYS)) + return -errno; + + /* The link()/unlink() fallback does not work on directories. But + * renameat() without RENAME_NOREPLACE gives the same semantics on + * directories, except when newpath is an *empty* directory. This is + * good enough. */ + ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW); + if (ret >= 0 && S_ISDIR(buf.st_mode)) { + ret = renameat(olddirfd, oldpath, newdirfd, newpath); + return ret >= 0 ? 0 : -errno; + } + + /* If it is not a directory, use the link()/unlink() fallback. */ + ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0); + if (ret < 0) + return -errno; + + ret = unlinkat(olddirfd, oldpath, 0); + if (ret < 0) { + /* backup errno before the following unlinkat() alters it */ + ret = errno; + (void) unlinkat(newdirfd, newpath, 0); + errno = ret; + return -errno; + } + + return 0; +} + +int readlinkat_malloc(int fd, const char *p, char **ret) { + size_t l = 100; + int r; + + assert(p); + assert(ret); + + for (;;) { + char *c; + ssize_t n; + + c = new(char, l); + if (!c) + return -ENOMEM; + + n = readlinkat(fd, p, c, l-1); + if (n < 0) { + r = -errno; + free(c); + return r; + } + + if ((size_t) n < l-1) { + c[n] = 0; + *ret = c; + return 0; + } + + free(c); + l *= 2; + } +} + +int readlink_malloc(const char *p, char **ret) { + return readlinkat_malloc(AT_FDCWD, p, ret); +} + +int readlink_value(const char *p, char **ret) { + _cleanup_free_ char *link = NULL; + char *value; + int r; + + r = readlink_malloc(p, &link); + if (r < 0) + return r; + + value = basename(link); + if (!value) + return -ENOENT; + + value = strdup(value); + if (!value) + return -ENOMEM; + + *ret = value; + + return 0; +} + +int readlink_and_make_absolute(const char *p, char **r) { + _cleanup_free_ char *target = NULL; + char *k; + int j; + + assert(p); + assert(r); + + j = readlink_malloc(p, &target); + if (j < 0) + return j; + + k = file_in_same_dir(p, target); + if (!k) + return -ENOMEM; + + *r = k; + return 0; +} + +int readlink_and_canonicalize(const char *p, char **r) { + char *t, *s; + int j; + + assert(p); + assert(r); + + j = readlink_and_make_absolute(p, &t); + if (j < 0) + return j; + + s = canonicalize_file_name(t); + if (s) { + free(t); + *r = s; + } else + *r = t; + + path_kill_slashes(*r); + + return 0; +} + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { + assert(path); + + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (chmod(path, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (chown(path, uid, gid) < 0) + return -errno; + + return 0; +} + +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { + assert(fd >= 0); + + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (fchmod(fd, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (fchown(fd, uid, gid) < 0) + return -errno; + + return 0; +} + +int fchmod_umask(int fd, mode_t m) { + mode_t u; + int r; + + u = umask(0777); + r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; + umask(u); + + return r; +} + +int fd_warn_permissions(const char *path, int fd) { + struct stat st; + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st.st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid() == 1 && (st.st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + +int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { + _cleanup_close_ int fd; + int r; + + assert(path); + + if (parents) + mkdir_parents(path, 0755); + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); + if (fd < 0) + return -errno; + + if (mode > 0) { + r = fchmod(fd, mode); + if (r < 0) + return -errno; + } + + if (uid != UID_INVALID || gid != GID_INVALID) { + r = fchown(fd, uid, gid); + if (r < 0) + return -errno; + } + + if (stamp != USEC_INFINITY) { + struct timespec ts[2]; + + timespec_store(&ts[0], stamp); + ts[1] = ts[0]; + r = futimens(fd, ts); + } else + r = futimens(fd, NULL); + if (r < 0) + return -errno; + + return 0; +} + +int touch(const char *path) { + return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0); +} + +int symlink_idempotent(const char *from, const char *to) { + _cleanup_free_ char *p = NULL; + int r; + + assert(from); + assert(to); + + if (symlink(from, to) < 0) { + if (errno != EEXIST) + return -errno; + + r = readlink_malloc(to, &p); + if (r < 0) + return r; + + if (!streq(p, from)) + return -EINVAL; + } + + return 0; +} + +int symlink_atomic(const char *from, const char *to) { + _cleanup_free_ char *t = NULL; + int r; + + assert(from); + assert(to); + + r = tempfn_random(to, NULL, &t); + if (r < 0) + return r; + + if (symlink(from, t) < 0) + return -errno; + + if (rename(t, to) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int mknod_atomic(const char *path, mode_t mode, dev_t dev) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + r = tempfn_random(path, NULL, &t); + if (r < 0) + return r; + + if (mknod(t, mode, dev) < 0) + return -errno; + + if (rename(t, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int mkfifo_atomic(const char *path, mode_t mode) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + r = tempfn_random(path, NULL, &t); + if (r < 0) + return r; + + if (mkfifo(t, mode) < 0) + return -errno; + + if (rename(t, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int get_files_in_directory(const char *path, char ***list) { + _cleanup_closedir_ DIR *d = NULL; + size_t bufsize = 0, n = 0; + _cleanup_strv_free_ char **l = NULL; + + assert(path); + + /* Returns all files in a directory in *list, and the number + * of files as return value. If list is NULL returns only the + * number. */ + + d = opendir(path); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + if (!de) + break; + + dirent_ensure_type(d, de); + + if (!dirent_is_file(de)) + continue; + + if (list) { + /* one extra slot is needed for the terminating NULL */ + if (!GREEDY_REALLOC(l, bufsize, n + 2)) + return -ENOMEM; + + l[n] = strdup(de->d_name); + if (!l[n]) + return -ENOMEM; + + l[++n] = NULL; + } else + n++; + } + + if (list) { + *list = l; + l = NULL; /* avoid freeing */ + } + + return n; +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h new file mode 100644 index 0000000000..b94873e65b --- /dev/null +++ b/src/basic/fs-util.h @@ -0,0 +1,74 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <sys/inotify.h> +#include <sys/types.h> +#include <unistd.h> +#include <limits.h> + +#include "time-util.h" + +int unlink_noerrno(const char *path); + +int rmdir_parents(const char *path, const char *stop); + +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); + +int readlinkat_malloc(int fd, const char *p, char **ret); +int readlink_malloc(const char *p, char **r); +int readlink_value(const char *p, char **ret); +int readlink_and_make_absolute(const char *p, char **r); +int readlink_and_canonicalize(const char *p, char **r); + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid); + +int fchmod_umask(int fd, mode_t mode); + +int fd_warn_permissions(const char *path, int fd); + +#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) + +int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); +int touch(const char *path); + +int symlink_idempotent(const char *from, const char *to); + +int symlink_atomic(const char *from, const char *to); +int mknod_atomic(const char *path, mode_t mode, dev_t dev); +int mkfifo_atomic(const char *path, mode_t mode); + +int get_files_in_directory(const char *path, char ***list); + +#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) + +#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ + for ((e) = &buffer.ev; \ + (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \ + (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len)) + +union inotify_event_buffer { + struct inotify_event ev; + uint8_t raw[INOTIFY_EVENT_MAX]; +}; diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c new file mode 100644 index 0000000000..0bfbcb1d37 --- /dev/null +++ b/src/basic/glob-util.c @@ -0,0 +1,72 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <glob.h> + +#include "glob-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" + +int glob_exists(const char *path) { + _cleanup_globfree_ glob_t g = {}; + int k; + + assert(path); + + errno = 0; + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + + if (k == GLOB_NOMATCH) + return 0; + if (k == GLOB_NOSPACE) + return -ENOMEM; + if (k != 0) + return errno ? -errno : -EIO; + + return !strv_isempty(g.gl_pathv); +} + +int glob_extend(char ***strv, const char *path) { + _cleanup_globfree_ glob_t g = {}; + int k; + char **p; + + errno = 0; + k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); + + if (k == GLOB_NOMATCH) + return -ENOENT; + if (k == GLOB_NOSPACE) + return -ENOMEM; + if (k != 0) + return errno ? -errno : -EIO; + if (strv_isempty(g.gl_pathv)) + return -ENOENT; + + STRV_FOREACH(p, g.gl_pathv) { + k = strv_extend(strv, *p); + if (k < 0) + return k; + } + + return 0; +} diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h new file mode 100644 index 0000000000..793adf4a6c --- /dev/null +++ b/src/basic/glob-util.h @@ -0,0 +1,37 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <string.h> + +#include "macro.h" +#include "string-util.h" + +int glob_exists(const char *path); +int glob_extend(char ***strv, const char *path); + +#define _cleanup_globfree_ _cleanup_(globfree) + +_pure_ static inline bool string_is_glob(const char *p) { + /* Check if a string contains any glob patterns. */ + return !!strpbrk(p, GLOB_CHARS); +} diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 7d2a4160c6..4109a08c6c 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -20,18 +20,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> #include <pthread.h> +#include <stdlib.h> -#include "util.h" +#include "alloc-util.h" #include "hashmap.h" -#include "set.h" #include "macro.h" -#include "siphash24.h" -#include "strv.h" #include "mempool.h" +#include "process-util.h" #include "random-util.h" +#include "set.h" +#include "siphash24.h" +#include "strv.h" +#include "util.h" #ifdef ENABLE_DEBUG_HASHMAP #include "list.h" @@ -276,10 +278,8 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; -unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, strlen(p), hash_key); - return (unsigned long) u; +void string_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, strlen(p) + 1, state); } int string_compare_func(const void *a, const void *b) { @@ -291,10 +291,8 @@ const struct hash_ops string_hash_ops = { .compare = string_compare_func }; -unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, &p, sizeof(p), hash_key); - return (unsigned long) u; +void trivial_hash_func(const void *p, struct siphash *state) { + siphash24_compress(&p, sizeof(p), state); } int trivial_compare_func(const void *a, const void *b) { @@ -306,10 +304,8 @@ const struct hash_ops trivial_hash_ops = { .compare = trivial_compare_func }; -unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, sizeof(uint64_t), hash_key); - return (unsigned long) u; +void uint64_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(uint64_t), state); } int uint64_compare_func(const void *_a, const void *_b) { @@ -325,10 +321,8 @@ const struct hash_ops uint64_hash_ops = { }; #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; - siphash24((uint8_t*) &u, p, sizeof(dev_t), hash_key); - return (unsigned long) u; +void devt_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(dev_t), state); } int devt_compare_func(const void *_a, const void *_b) { @@ -379,7 +373,16 @@ static uint8_t *hash_key(HashmapBase *h) { } static unsigned base_bucket_hash(HashmapBase *h, const void *p) { - return (unsigned) (h->hash_ops->hash(p, hash_key(h)) % n_buckets(h)); + struct siphash state; + uint64_t hash; + + siphash24_init(&state, hash_key(h)); + + h->hash_ops->hash(p, &state); + + siphash24_finalize((uint8_t*)&hash, &state); + + return (unsigned) (hash % n_buckets(h)); } #define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index 2af23024de..ed6a092d82 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -25,6 +25,7 @@ #include <stdbool.h> #include "macro.h" +#include "siphash24.h" #include "util.h" /* @@ -67,7 +68,7 @@ typedef struct { #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) -typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); +typedef void (*hash_func_t)(const void *p, struct siphash *state); typedef int (*compare_func_t)(const void *a, const void *b); struct hash_ops { @@ -75,28 +76,28 @@ struct hash_ops { compare_func_t compare; }; -unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void string_hash_func(const void *p, struct siphash *state); int string_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops string_hash_ops; /* This will compare the passed pointers directly, and will not * dereference them. This is hence not useful for strings or * suchlike. */ -unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void trivial_hash_func(const void *p, struct siphash *state); int trivial_compare_func(const void *a, const void *b) _const_; extern const struct hash_ops trivial_hash_ops; /* 32bit values we can always just embedd in the pointer itself, but * in order to support 32bit archs we need store 64bit values * indirectly, since they don't fit in a pointer. */ -unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void uint64_hash_func(const void *p, struct siphash *state); int uint64_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops uint64_hash_ops; /* On some archs dev_t is 32bit, and on others 64bit. And sometimes * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 -unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_; +void devt_hash_func(const void *p, struct siphash *state) _pure_; int devt_compare_func(const void *a, const void *b) _pure_; extern const struct hash_ops devt_hash_ops = { .hash = devt_hash_func, diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c new file mode 100644 index 0000000000..4eb566b15a --- /dev/null +++ b/src/basic/hexdecoct.c @@ -0,0 +1,698 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <ctype.h> +#include <inttypes.h> + +#include "alloc-util.h" +#include "hexdecoct.h" +#include "util.h" + +char octchar(int x) { + return '0' + (x & 7); +} + +int unoctchar(char c) { + + if (c >= '0' && c <= '7') + return c - '0'; + + return -EINVAL; +} + +char decchar(int x) { + return '0' + (x % 10); +} + +int undecchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + return -EINVAL; +} + +char hexchar(int x) { + static const char table[16] = "0123456789abcdef"; + + return table[x & 15]; +} + +int unhexchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -EINVAL; +} + +char *hexmem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + z = r = malloc(l * 2 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + l; x++) { + *(z++) = hexchar(*x >> 4); + *(z++) = hexchar(*x & 15); + } + + *z = 0; + return r; +} + +int unhexmem(const char *p, size_t l, void **mem, size_t *len) { + _cleanup_free_ uint8_t *r = NULL; + uint8_t *z; + const char *x; + + assert(mem); + assert(len); + assert(p); + + z = r = malloc((l + 1) / 2 + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + l; x += 2) { + int a, b; + + a = unhexchar(x[0]); + if (a < 0) + return a; + else if (x+1 < p + l) { + b = unhexchar(x[1]); + if (b < 0) + return b; + } else + b = 0; + + *(z++) = (uint8_t) a << 4 | (uint8_t) b; + } + + *z = 0; + + *mem = r; + r = NULL; + *len = (l + 1) / 2; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-6 + * Notice that base32hex differs from base32 in the alphabet it uses. + * The distinction is that the base32hex representation preserves the + * order of the underlying data when compared as bytestrings, this is + * useful when representing NSEC3 hashes, as one can then verify the + * order of hashes directly from their representation. */ +char base32hexchar(int x) { + static const char table[32] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUV"; + + return table[x & 31]; +} + +int unbase32hexchar(char c) { + unsigned offset; + + if (c >= '0' && c <= '9') + return c - '0'; + + offset = '9' - '0' + 1; + + if (c >= 'A' && c <= 'V') + return c - 'A' + offset; + + return -EINVAL; +} + +char *base32hexmem(const void *p, size_t l, bool padding) { + char *r, *z; + const uint8_t *x; + size_t len; + + if (padding) + /* five input bytes makes eight output bytes, padding is added so we must round up */ + len = 8 * (l + 4) / 5; + else { + /* same, but round down as there is no padding */ + len = 8 * l / 5; + + switch (l % 5) { + case 4: + len += 7; + break; + case 3: + len += 5; + break; + case 2: + len += 4; + break; + case 1: + len += 2; + break; + } + } + + z = r = malloc(len + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ + x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */ + *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */ + } + + switch (l % 5) { + case 4: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */ + if (padding) + *(z++) = '='; + + break; + + case 3: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 2: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 1: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + } + + *z = 0; + return r; +} + +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d, e, f, g, h; + uint8_t *z; + const char *x; + size_t len; + unsigned pad = 0; + + assert(p); + + /* padding ensures any base32hex input has input divisible by 8 */ + if (padding && l % 8 != 0) + return -EINVAL; + + if (padding) { + /* strip the padding */ + while (l > 0 && p[l - 1] == '=' && pad < 7) { + pad ++; + l --; + } + } + + /* a group of eight input bytes needs five output bytes, in case of + padding we need to add some extra bytes */ + len = (l / 8) * 5; + + switch (l % 8) { + case 7: + len += 4; + break; + case 5: + len += 3; + break; + case 4: + len += 2; + break; + case 2: + len += 1; + break; + case 0: + break; + default: + return -EINVAL; + } + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 8) * 8; x += 8) { + /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW + e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + h = unbase32hexchar(x[7]); + if (h < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */ + } + + switch (l % 8) { + case 7: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + /* g == 000VV000 */ + if (g & 7) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + + break; + case 5: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + /* e == 000SSSS0 */ + if (e & 1) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + + break; + case 4: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + /* d == 000W0000 */ + if (d & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + + break; + case 2: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 000YYY00 */ + if (b & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + + break; + case 0: + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-4 */ +char base64char(int x) { + static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + return table[x & 63]; +} + +int unbase64char(char c) { + unsigned offset; + + if (c >= 'A' && c <= 'Z') + return c - 'A'; + + offset = 'Z' - 'A' + 1; + + if (c >= 'a' && c <= 'z') + return c - 'a' + offset; + + offset += 'z' - 'a' + 1; + + if (c >= '0' && c <= '9') + return c - '0' + offset; + + offset += '9' - '0' + 1; + + if (c == '+') + return offset; + + offset ++; + + if (c == '/') + return offset; + + return -EINVAL; +} + +char *base64mem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + /* three input bytes makes four output bytes, padding is added so we must round up */ + z = r = malloc(4 * (l + 2) / 3 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ + *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ + } + + switch (l % 3) { + case 2: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ + *(z++) = '='; + + break; + case 1: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ + *(z++) = '='; + *(z++) = '='; + + break; + } + + *z = 0; + return r; +} + +int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d; + uint8_t *z; + const char *x; + size_t len; + + assert(p); + + /* padding ensures any base63 input has input divisible by 4 */ + if (l % 4 != 0) + return -EINVAL; + + /* strip the padding */ + if (l > 0 && p[l - 1] == '=') + l --; + if (l > 0 && p[l - 1] == '=') + l --; + + /* a group of four input bytes needs three output bytes, in case of + padding we need to add two or three extra bytes */ + len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 4) * 4; x += 4) { + /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase64char(x[3]); + if (d < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + } + + switch (l % 4) { + case 3: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + /* c == 00ZZZZ00 */ + if (c & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + + break; + case 2: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 00YY0000 */ + if (b & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + + break; + case 0: + + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +void hexdump(FILE *f, const void *p, size_t s) { + const uint8_t *b = p; + unsigned n = 0; + + assert(s == 0 || b); + + while (s > 0) { + size_t i; + + fprintf(f, "%04x ", n); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputs(" ", f); + else + fprintf(f, "%02x ", b[i]); + + if (i == 7) + fputc(' ', f); + } + + fputc(' ', f); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputc(' ', f); + else + fputc(isprint(b[i]) ? (char) b[i] : '.', f); + } + + fputc('\n', f); + + if (s < 16) + break; + + n += 16; + b += 16; + s -= 16; + } +} diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h new file mode 100644 index 0000000000..4aeb4c3bdc --- /dev/null +++ b/src/basic/hexdecoct.h @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <stdio.h> +#include <sys/types.h> + +#include "macro.h" + +char octchar(int x) _const_; +int unoctchar(char c) _const_; + +char decchar(int x) _const_; +int undecchar(char c) _const_; + +char hexchar(int x) _const_; +int unhexchar(char c) _const_; + +char *hexmem(const void *p, size_t l); +int unhexmem(const char *p, size_t l, void **mem, size_t *len); + +char base32hexchar(int x) _const_; +int unbase32hexchar(char c) _const_; + +char base64char(int x) _const_; +int unbase64char(char c) _const_; + +char *base32hexmem(const void *p, size_t l, bool padding); +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); + +char *base64mem(const void *p, size_t l); +int unbase64mem(const char *p, size_t l, void **mem, size_t *len); + +void hexdump(FILE *f, const void *p, size_t s); diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 1b816fb77a..ea0528c6fc 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/utsname.h> #include <ctype.h> +#include <sys/utsname.h> -#include "util.h" +#include "fd-util.h" +#include "fileio.h" #include "hostname-util.h" +#include "string-util.h" +#include "util.h" bool hostname_is_set(void) { struct utsname u; diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index d88864b598..f4e24121e7 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -21,6 +21,7 @@ #include <arpa/inet.h> +#include "alloc-util.h" #include "in-addr-util.h" int in_addr_is_null(int family, const union in_addr_union *u) { diff --git a/src/basic/io-util.c b/src/basic/io-util.c new file mode 100644 index 0000000000..ac8f93ff57 --- /dev/null +++ b/src/basic/io-util.c @@ -0,0 +1,261 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <poll.h> +#include <unistd.h> + +#include "io-util.h" + +int flush_fd(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + + for (;;) { + char buf[LINE_MAX]; + ssize_t l; + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; + + return -errno; + + } else if (r == 0) + return 0; + + l = read(fd, buf, sizeof(buf)); + if (l < 0) { + + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + return 0; + + return -errno; + } else if (l == 0) + return 0; + } +} + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { + uint8_t *p = buf; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + /* If called with nbytes == 0, let's call read() at least + * once, to validate the operation */ + + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; + + do { + ssize_t k; + + k = read(fd, p, nbytes); + if (k < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN && do_poll) { + + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ + + (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); + continue; + } + + return n > 0 ? n : -errno; + } + + if (k == 0) + return n; + + assert((size_t) k <= nbytes); + + p += k; + nbytes -= k; + n += k; + } while (nbytes > 0); + + return n; +} + +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { + ssize_t n; + + n = loop_read(fd, buf, nbytes, do_poll); + if (n < 0) + return (int) n; + if ((size_t) n != nbytes) + return -EIO; + + return 0; +} + +int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { + const uint8_t *p = buf; + + assert(fd >= 0); + assert(buf); + + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; + + do { + ssize_t k; + + k = write(fd, p, nbytes); + if (k < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN && do_poll) { + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via write() */ + + (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); + continue; + } + + return -errno; + } + + if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */ + return -EIO; + + assert((size_t) k <= nbytes); + + p += k; + nbytes -= k; + } while (nbytes > 0); + + return 0; +} + +int pipe_eof(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN|POLLHUP, + }; + + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents & POLLHUP; +} + +int fd_wait_for_event(int fd, int event, usec_t t) { + + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; + + struct timespec ts; + int r; + + r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents; +} + +static size_t nul_length(const uint8_t *p, size_t sz) { + size_t n = 0; + + while (sz > 0) { + if (*p != 0) + break; + + n++; + p++; + sz--; + } + + return n; +} + +ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { + const uint8_t *q, *w, *e; + ssize_t l; + + q = w = p; + e = q + sz; + while (q < e) { + size_t n; + + n = nul_length(q, e - q); + + /* If there are more than the specified run length of + * NUL bytes, or if this is the beginning or the end + * of the buffer, then seek instead of write */ + if ((n > run_length) || + (n > 0 && q == p) || + (n > 0 && q + n >= e)) { + if (q > w) { + l = write(fd, w, q - w); + if (l < 0) + return -errno; + if (l != q -w) + return -EIO; + } + + if (lseek(fd, n, SEEK_CUR) == (off_t) -1) + return -errno; + + q += n; + w = q; + } else if (n > 0) + q += n; + else + q ++; + } + + if (q > w) { + l = write(fd, w, q - w); + if (l < 0) + return -errno; + if (l != q - w) + return -EIO; + } + + return q - (const uint8_t*) p; +} diff --git a/src/basic/io-util.h b/src/basic/io-util.h new file mode 100644 index 0000000000..cd2aa75ad2 --- /dev/null +++ b/src/basic/io-util.h @@ -0,0 +1,76 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/types.h> +#include <sys/uio.h> + +#include "time-util.h" + +int flush_fd(int fd); + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); +int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); + +int pipe_eof(int fd); + +int fd_wait_for_event(int fd, int event, usec_t timeout); + +ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); + +#define IOVEC_SET_STRING(i, s) \ + do { \ + struct iovec *_i = &(i); \ + char *_s = (char *)(s); \ + _i->iov_base = _s; \ + _i->iov_len = strlen(_s); \ + } while(false) + +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { + unsigned j; + size_t r = 0; + + for (j = 0; j < n; j++) + r += i[j].iov_len; + + return r; +} + +static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { + unsigned j; + + for (j = 0; j < n; j++) { + size_t sub; + + if (_unlikely_(k <= 0)) + break; + + sub = MIN(i[j].iov_len, k); + i[j].iov_len -= sub; + i[j].iov_base = (uint8_t*) i[j].iov_base + sub; + k -= sub; + } + + return k; +} diff --git a/src/basic/json.c b/src/basic/json.c index be40a0d203..716705e5ff 100644 --- a/src/basic/json.c +++ b/src/basic/json.c @@ -19,11 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <math.h> +#include <sys/types.h> + +#include "alloc-util.h" +#include "json.h" #include "macro.h" +#include "hexdecoct.h" +#include "string-util.h" #include "utf8.h" -#include "json.h" int json_variant_new(JsonVariant **ret, JsonVariantType type) { JsonVariant *v; diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 61db9a8125..b87fd7670b 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -19,14 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <langinfo.h> +#include <locale.h> #include <sys/mman.h> +#include "dirent-util.h" +#include "fd-util.h" +#include "locale-util.h" +#include "path-util.h" #include "set.h" -#include "util.h" -#include "utf8.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" - -#include "locale-util.h" +#include "utf8.h" +#include "util.h" static int add_locales_from_archive(Set *locales) { /* Stolen from glibc... */ @@ -204,6 +210,88 @@ bool locale_is_valid(const char *name) { return true; } +void init_gettext(void) { + setlocale(LC_ALL, ""); + textdomain(GETTEXT_PACKAGE); +} + +bool is_locale_utf8(void) { + const char *set; + static int cached_answer = -1; + + /* Note that we default to 'true' here, since today UTF8 is + * pretty much supported everywhere. */ + + if (cached_answer >= 0) + goto out; + + if (!setlocale(LC_ALL, "")) { + cached_answer = true; + goto out; + } + + set = nl_langinfo(CODESET); + if (!set) { + cached_answer = true; + goto out; + } + + if (streq(set, "UTF-8")) { + cached_answer = true; + goto out; + } + + /* For LC_CTYPE=="C" return true, because CTYPE is effectly + * unset and everything can do to UTF-8 nowadays. */ + set = setlocale(LC_CTYPE, NULL); + if (!set) { + cached_answer = true; + goto out; + } + + /* Check result, but ignore the result if C was set + * explicitly. */ + cached_answer = + STR_IN_SET(set, "C", "POSIX") && + !getenv("LC_ALL") && + !getenv("LC_CTYPE") && + !getenv("LANG"); + +out: + return (bool) cached_answer; +} + + +const char *draw_special_char(DrawSpecialChar ch) { + + static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { + + /* UTF-8 */ { + [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */ + [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ + [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ + [DRAW_TREE_SPACE] = " ", /* */ + [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ + [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */ + [DRAW_ARROW] = "\342\206\222", /* → */ + [DRAW_DASH] = "\342\200\223", /* – */ + }, + + /* ASCII fallback */ { + [DRAW_TREE_VERTICAL] = "| ", + [DRAW_TREE_BRANCH] = "|-", + [DRAW_TREE_RIGHT] = "`-", + [DRAW_TREE_SPACE] = " ", + [DRAW_TRIANGULAR_BULLET] = ">", + [DRAW_BLACK_CIRCLE] = "*", + [DRAW_ARROW] = "->", + [DRAW_DASH] = "-", + } + }; + + return draw_table[!is_locale_utf8()][ch]; +} + static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { [VARIABLE_LANG] = "LANG", [VARIABLE_LANGUAGE] = "LANGUAGE", diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index e48aa3d9af..c71d145139 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -21,6 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <libintl.h> #include <stdbool.h> #include "macro.h" @@ -50,5 +51,25 @@ typedef enum LocaleVariable { int get_locales(char ***l); bool locale_is_valid(const char *name); +#define _(String) gettext(String) +#define N_(String) String +void init_gettext(void); + +bool is_locale_utf8(void); + +typedef enum DrawSpecialChar { + DRAW_TREE_VERTICAL, + DRAW_TREE_BRANCH, + DRAW_TREE_RIGHT, + DRAW_TREE_SPACE, + DRAW_TRIANGULAR_BULLET, + DRAW_BLACK_CIRCLE, + DRAW_ARROW, + DRAW_DASH, + _DRAW_SPECIAL_CHAR_MAX +} DrawSpecialChar; + +const char *draw_special_char(DrawSpecialChar ch); + const char* locale_variable_to_string(LocaleVariable i) _const_; LocaleVariable locale_variable_from_string(const char *s) _pure_; diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index f3ec6a3e52..87c3aef7af 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -27,9 +27,13 @@ #include <limits.h> #include <sys/file.h> -#include "util.h" -#include "lockfile-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "lockfile-util.h" +#include "path-util.h" +#include "util.h" int make_lock_file(const char *p, int operation, LockFile *ret) { _cleanup_close_ int fd = -1; diff --git a/src/basic/log.c b/src/basic/log.c index 38f42b3a6e..fe29cacd9e 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -19,26 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdarg.h> -#include <stdio.h> #include <errno.h> -#include <unistd.h> #include <fcntl.h> +#include <printf.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> #include <sys/socket.h> #include <sys/un.h> -#include <stddef.h> -#include <printf.h> +#include <unistd.h> #include "sd-messages.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" #include "log.h" -#include "util.h" -#include "missing.h" #include "macro.h" -#include "socket-util.h" -#include "formats-util.h" +#include "missing.h" +#include "parse-util.h" +#include "proc-cmdline.h" #include "process-util.h" -#include "terminal-util.h" #include "signal-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" +#include "syslog-util.h" +#include "terminal-util.h" +#include "util.h" #define SNDBUF_SIZE (8*1024*1024) @@ -435,7 +445,7 @@ static int write_to_syslog( static int write_to_kmsg( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, @@ -506,7 +516,7 @@ static int log_do_header( static int write_to_journal( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, @@ -640,7 +650,7 @@ int log_dump_internal( int log_internalv( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *format, @@ -667,7 +677,7 @@ int log_internalv( int log_internal( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *format, ...) { @@ -685,7 +695,7 @@ int log_internal( int log_object_internalv( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, @@ -729,7 +739,7 @@ int log_object_internalv( int log_object_internal( int level, int error, - const char*file, + const char *file, int line, const char *func, const char *object_field, @@ -922,7 +932,7 @@ int log_set_max_level_from_string(const char *e) { t = log_level_from_string(e); if (t < 0) - return t; + return -EINVAL; log_set_max_level(t); return 0; diff --git a/src/basic/log.h b/src/basic/log.h index 569762d083..cda1e45cc8 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -21,14 +21,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> +#include <errno.h> #include <stdarg.h> +#include <stdbool.h> #include <stdlib.h> -#include <syslog.h> #include <sys/signalfd.h> -#include <errno.h> +#include <syslog.h> #include "sd-id128.h" + #include "macro.h" typedef enum LogTarget{ @@ -227,3 +228,15 @@ int log_syntax_internal( ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ : -abs(_e); \ }) + +#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ + ({ \ + int _level = (level); \ + if (log_get_max_level() >= LOG_PRI(_level)) { \ + _cleanup_free_ char *_p = NULL; \ + _p = utf8_escape_invalid(rvalue); \ + log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ + "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ + } \ + -EINVAL; \ + }) diff --git a/src/basic/login-util.c b/src/basic/login-util.c index e25437f0f4..832f477bd2 100644 --- a/src/basic/login-util.c +++ b/src/basic/login-util.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "login-util.h" #include "def.h" +#include "string-util.h" +#include "login-util.h" bool session_id_valid(const char *id) { diff --git a/src/basic/login-util.h b/src/basic/login-util.h index a79f20c1b1..be5bb64870 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -22,5 +22,10 @@ #pragma once #include <stdbool.h> +#include <unistd.h> bool session_id_valid(const char *id); + +static inline bool logind_running(void) { + return access("/run/systemd/seats/", F_OK) >= 0; +} diff --git a/src/basic/macro.h b/src/basic/macro.h index f55d65e2f1..5088e6720d 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -22,11 +22,10 @@ ***/ #include <assert.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/uio.h> #include <inttypes.h> #include <stdbool.h> +#include <sys/param.h> +#include <sys/types.h> #define _printf_(a,b) __attribute__ ((format (printf, a, b))) #define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) @@ -295,111 +294,10 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) #define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) -/* The following macros add 1 when converting things, since UID 0 is a - * valid UID, while the pointer NULL is special */ -#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1)) -#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) - -#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) -#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) - -#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) -#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) - -#define memzero(x,l) (memset((x), 0, (l))) -#define zero(x) (memzero(&(x), sizeof(x))) - #define CHAR_TO_STR(x) ((char[2]) { x, 0 }) #define char_array_0(x) x[sizeof(x)-1] = 0; -#define IOVEC_SET_STRING(i, s) \ - do { \ - struct iovec *_i = &(i); \ - char *_s = (char *)(s); \ - _i->iov_base = _s; \ - _i->iov_len = strlen(_s); \ - } while(false) - -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; - - for (j = 0; j < n; j++) - r += i[j].iov_len; - - return r; -} - -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; - - for (j = 0; j < n; j++) { - size_t sub; - - if (_unlikely_(k <= 0)) - break; - - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t*) i[j].iov_base + sub; - k -= sub; - } - - return k; -} - -#define VA_FORMAT_ADVANCE(format, ap) \ -do { \ - int _argtypes[128]; \ - size_t _i, _k; \ - _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ - assert(_k < ELEMENTSOF(_argtypes)); \ - for (_i = 0; _i < _k; _i++) { \ - if (_argtypes[_i] & PA_FLAG_PTR) { \ - (void) va_arg(ap, void*); \ - continue; \ - } \ - \ - switch (_argtypes[_i]) { \ - case PA_INT: \ - case PA_INT|PA_FLAG_SHORT: \ - case PA_CHAR: \ - (void) va_arg(ap, int); \ - break; \ - case PA_INT|PA_FLAG_LONG: \ - (void) va_arg(ap, long int); \ - break; \ - case PA_INT|PA_FLAG_LONG_LONG: \ - (void) va_arg(ap, long long int); \ - break; \ - case PA_WCHAR: \ - (void) va_arg(ap, wchar_t); \ - break; \ - case PA_WSTRING: \ - case PA_STRING: \ - case PA_POINTER: \ - (void) va_arg(ap, void*); \ - break; \ - case PA_FLOAT: \ - case PA_DOUBLE: \ - (void) va_arg(ap, double); \ - break; \ - case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ - (void) va_arg(ap, long double); \ - break; \ - default: \ - assert_not_reached("Unknown format string argument."); \ - } \ - } \ -} while(false) - - /* Because statfs.t_type can be int on some architectures, we have to cast - * the const magic to the type, otherwise the compiler warns about - * signed/unsigned comparison, because the magic can be 32 bit unsigned. - */ -#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) - /* Returns the number of chars needed to format variables of the * specified type as a decimal string. Adds in extra space for a * negative '-' prefix (hence works correctly on signed @@ -410,6 +308,15 @@ do { \ sizeof(type) <= 4 ? 10 : \ sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) +#define DECIMAL_STR_WIDTH(x) \ + ({ \ + typeof(x) _x_ = (x); \ + unsigned ans = 1; \ + while (_x_ /= 10) \ + ans++; \ + ans; \ + }) + #define SET_FLAG(v, flag, b) \ (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) @@ -427,21 +334,6 @@ do { \ _found; \ }) -/* Return a nulstr for a standard cascade of configuration directories, - * suitable to pass to conf_files_list_nulstr or config_parse_many. */ -#define CONF_DIRS_NULSTR(n) \ - "/etc/" n ".d\0" \ - "/run/" n ".d\0" \ - "/usr/local/lib/" n ".d\0" \ - "/usr/lib/" n ".d\0" \ - CONF_DIR_SPLIT_USR(n) - -#ifdef HAVE_SPLIT_USR -#define CONF_DIR_SPLIT_USR(n) "/lib/" n ".d\0" -#else -#define CONF_DIR_SPLIT_USR(n) -#endif - /* Define C11 thread_local attribute even on older gcc compiler * version */ #ifndef thread_local @@ -466,10 +358,6 @@ do { \ #endif #endif -#define UID_INVALID ((uid_t) -1) -#define GID_INVALID ((gid_t) -1) -#define MODE_INVALID ((mode_t) -1) - #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ @@ -477,7 +365,4 @@ do { \ } \ struct __useless_struct_to_allow_trailing_semicolon__ -#define CMSG_FOREACH(cmsg, mh) \ - for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) - #include "log.h" diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index e99a738e1f..92630f6b25 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -19,19 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <fcntl.h> -#include <sys/mman.h> -#include <sys/prctl.h> - #ifdef HAVE_LINUX_MEMFD_H -# include <linux/memfd.h> +#include <linux/memfd.h> #endif +#include <stdio.h> +#include <sys/mman.h> +#include <sys/prctl.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "memfd-util.h" -#include "utf8.h" #include "missing.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" int memfd_new(const char *name) { _cleanup_free_ char *g = NULL; diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 3ed551fb37..2cb404ea81 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -21,7 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - +#include <sys/types.h> +#include <inttypes.h> int memfd_new(const char *name); int memfd_new_and_map(const char *name, size_t sz, void **p); diff --git a/src/basic/missing.h b/src/basic/missing.h index 9811b6b23e..306c56a156 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -126,6 +126,10 @@ #define SOL_NETLINK 270 #endif +#ifndef NETLINK_LIST_MEMBERSHIPS +#define NETLINK_LIST_MEMBERSHIPS 9 +#endif + #if !HAVE_DECL_PIVOT_ROOT static inline int pivot_root(const char *new_root, const char *put_old) { return syscall(SYS_pivot_root, new_root, put_old); @@ -248,6 +252,10 @@ static inline int getrandom(void *buffer, size_t count, unsigned flags) { #define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) #endif +#ifndef BTRFS_QGROUP_LEVEL_SHIFT +#define BTRFS_QGROUP_LEVEL_SHIFT 48 +#endif + #ifndef HAVE_LINUX_BTRFS_H struct btrfs_ioctl_vol_args { int64_t fd; @@ -486,6 +494,10 @@ struct btrfs_ioctl_quota_ctl_args { #define BTRFS_QGROUP_LIMIT_KEY 244 #endif +#ifndef BTRFS_QGROUP_RELATION_KEY +#define BTRFS_QGROUP_RELATION_KEY 246 +#endif + #ifndef BTRFS_ROOT_BACKREF_KEY #define BTRFS_ROOT_BACKREF_KEY 144 #endif @@ -842,6 +854,19 @@ static inline int setns(int fd, int nstype) { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif +#if !HAVE_DECL_IFLA_BR_PRIORITY +#define IFLA_BR_UNSPEC 0 +#define IFLA_BR_FORWARD_DELAY 1 +#define IFLA_BR_HELLO_TIME 2 +#define IFLA_BR_MAX_AGE 3 +#define IFLA_BR_AGEING_TIME 4 +#define IFLA_BR_STP_STATE 5 +#define IFLA_BR_PRIORITY 6 +#define __IFLA_BR_MAX 7 + +#define IFLA_BR_MAX (__IFLA_BR_MAX - 1) +#endif + #if !HAVE_DECL_IFLA_BRPORT_LEARNING_SYNC #define IFLA_BRPORT_UNSPEC 0 #define IFLA_BRPORT_STATE 1 @@ -1050,3 +1075,48 @@ static inline int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, uns #ifndef INPUT_PROP_ACCELEROMETER #define INPUT_PROP_ACCELEROMETER 0x06 #endif + +#if !HAVE_DECL_KEY_SERIAL_T +typedef int32_t key_serial_t; +#endif + +#if !HAVE_DECL_KEYCTL +static inline long keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4,unsigned long arg5) { +#if defined(__NR_keyctl) + return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5); +#else + errno = ENOSYS; + return -1; +#endif +} + +static inline key_serial_t add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) { +#if defined (__NR_add_key) + return syscall(__NR_add_key, type, description, payload, plen, ringid); +#else + errno = ENOSYS; + return -1; +#endif +} + +static inline key_serial_t request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) { +#if defined (__NR_request_key) + return syscall(__NR_request_key, type, description, callout_info, destringid); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#ifndef KEYCTL_READ +#define KEYCTL_READ 11 +#endif + +#ifndef KEYCTL_SET_TIMEOUT +#define KEYCTL_SET_TIMEOUT 15 +#endif + +#ifndef KEY_SPEC_USER_KEYRING +#define KEY_SPEC_USER_KEYRING -4 +#endif diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 7ee4546988..0214c4627e 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -22,9 +22,12 @@ #include <string.h> #include <errno.h> -#include "util.h" -#include "path-util.h" +#include "fs-util.h" #include "mkdir.h" +#include "path-util.h" +#include "stat-util.h" +#include "user-util.h" +#include "util.h" int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) { struct stat st; diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c new file mode 100644 index 0000000000..29997b1ce7 --- /dev/null +++ b/src/basic/mount-util.c @@ -0,0 +1,529 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <string.h> +#include <sys/mount.h> +#include <sys/statvfs.h> + +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "set.h" +#include "stdio-util.h" +#include "string-util.h" +#include "util.h" + +static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { + char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; + _cleanup_free_ char *fdinfo = NULL; + _cleanup_close_ int subfd = -1; + char *p; + int r; + + if ((flags & AT_EMPTY_PATH) && isempty(filename)) + xsprintf(path, "/proc/self/fdinfo/%i", fd); + else { + subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); + if (subfd < 0) + return -errno; + + xsprintf(path, "/proc/self/fdinfo/%i", subfd); + } + + r = read_full_file(path, &fdinfo, NULL); + if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ + return -EOPNOTSUPP; + if (r < 0) + return -errno; + + p = startswith(fdinfo, "mnt_id:"); + if (!p) { + p = strstr(fdinfo, "\nmnt_id:"); + if (!p) /* The mnt_id field is a relatively new addition */ + return -EOPNOTSUPP; + + p += 8; + } + + p += strspn(p, WHITESPACE); + p[strcspn(p, WHITESPACE)] = 0; + + return safe_atoi(p, mnt_id); +} + + +int fd_is_mount_point(int fd, const char *filename, int flags) { + union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; + int mount_id = -1, mount_id_parent = -1; + bool nosupp = false, check_st_dev = true; + struct stat a, b; + int r; + + assert(fd >= 0); + assert(filename); + + /* First we will try the name_to_handle_at() syscall, which + * tells us the mount id and an opaque file "handle". It is + * not supported everywhere though (kernel compile-time + * option, not all file systems are hooked up). If it works + * the mount id is usually good enough to tell us whether + * something is a mount point. + * + * If that didn't work we will try to read the mount id from + * /proc/self/fdinfo/<fd>. This is almost as good as + * name_to_handle_at(), however, does not return the + * opaque file handle. The opaque file handle is pretty useful + * to detect the root directory, which we should always + * consider a mount point. Hence we use this only as + * fallback. Exporting the mnt_id in fdinfo is a pretty recent + * kernel addition. + * + * As last fallback we do traditional fstat() based st_dev + * comparisons. This is how things were traditionally done, + * but unionfs breaks breaks this since it exposes file + * systems with a variety of st_dev reported. Also, btrfs + * subvolumes have different st_dev, even though they aren't + * real mounts of their own. */ + + r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); + if (r < 0) { + if (errno == ENOSYS) + /* This kernel does not support name_to_handle_at() + * fall back to simpler logic. */ + goto fallback_fdinfo; + else if (errno == EOPNOTSUPP) + /* This kernel or file system does not support + * name_to_handle_at(), hence let's see if the + * upper fs supports it (in which case it is a + * mount point), otherwise fallback to the + * traditional stat() logic */ + nosupp = true; + else + return -errno; + } + + r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); + if (r < 0) { + if (errno == EOPNOTSUPP) { + if (nosupp) + /* Neither parent nor child do name_to_handle_at()? + We have no choice but to fall back. */ + goto fallback_fdinfo; + else + /* The parent can't do name_to_handle_at() but the + * directory we are interested in can? + * If so, it must be a mount point. */ + return 1; + } else + return -errno; + } + + /* The parent can do name_to_handle_at() but the + * directory we are interested in can't? If so, it + * must be a mount point. */ + if (nosupp) + return 1; + + /* If the file handle for the directory we are + * interested in and its parent are identical, we + * assume this is the root directory, which is a mount + * point. */ + + if (h.handle.handle_bytes == h_parent.handle.handle_bytes && + h.handle.handle_type == h_parent.handle.handle_type && + memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) + return 1; + + return mount_id != mount_id_parent; + +fallback_fdinfo: + r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); + if (r == -EOPNOTSUPP) + goto fallback_fstat; + if (r < 0) + return r; + + r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); + if (r < 0) + return r; + + if (mount_id != mount_id_parent) + return 1; + + /* Hmm, so, the mount ids are the same. This leaves one + * special case though for the root file system. For that, + * let's see if the parent directory has the same inode as we + * are interested in. Hence, let's also do fstat() checks now, + * too, but avoid the st_dev comparisons, since they aren't + * that useful on unionfs mounts. */ + check_st_dev = false; + +fallback_fstat: + /* yay for fstatat() taking a different set of flags than the other + * _at() above */ + if (flags & AT_SYMLINK_FOLLOW) + flags &= ~AT_SYMLINK_FOLLOW; + else + flags |= AT_SYMLINK_NOFOLLOW; + if (fstatat(fd, filename, &a, flags) < 0) + return -errno; + + if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) + return -errno; + + /* A directory with same device and inode as its parent? Must + * be the root directory */ + if (a.st_dev == b.st_dev && + a.st_ino == b.st_ino) + return 1; + + return check_st_dev && (a.st_dev != b.st_dev); +} + +/* flags can be AT_SYMLINK_FOLLOW or 0 */ +int path_is_mount_point(const char *t, int flags) { + _cleanup_close_ int fd = -1; + _cleanup_free_ char *canonical = NULL, *parent = NULL; + + assert(t); + + if (path_equal(t, "/")) + return 1; + + /* we need to resolve symlinks manually, we can't just rely on + * fd_is_mount_point() to do that for us; if we have a structure like + * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we + * look at needs to be /usr, not /. */ + if (flags & AT_SYMLINK_FOLLOW) { + canonical = canonicalize_file_name(t); + if (!canonical) + return -errno; + + t = canonical; + } + + parent = dirname_malloc(t); + if (!parent) + return -ENOMEM; + + fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); + if (fd < 0) + return -errno; + + return fd_is_mount_point(fd, basename(t), flags); +} + +int umount_recursive(const char *prefix, int flags) { + bool again; + int n = 0, r; + + /* Try to umount everything recursively below a + * directory. Also, take care of stacked mounts, and keep + * unmounting them until they are gone. */ + + do { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + + again = false; + r = 0; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *path = NULL, *p = NULL; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%*s " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%*s" /* (11) mount options 2 */ + "%*[^\n]", /* some rubbish at the end */ + &path); + if (k != 1) { + if (k == EOF) + break; + + continue; + } + + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; + + if (!path_startswith(p, prefix)) + continue; + + if (umount2(p, flags) < 0) { + r = -errno; + continue; + } + + again = true; + n++; + + break; + } + + } while (again); + + return r ? r : n; +} + +static int get_mount_flags(const char *path, unsigned long *flags) { + struct statvfs buf; + + if (statvfs(path, &buf) < 0) + return -errno; + *flags = buf.f_flag; + return 0; +} + +int bind_remount_recursive(const char *prefix, bool ro) { + _cleanup_set_free_free_ Set *done = NULL; + _cleanup_free_ char *cleaned = NULL; + int r; + + /* Recursively remount a directory (and all its submounts) + * read-only or read-write. If the directory is already + * mounted, we reuse the mount and simply mark it + * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write + * operation). If it isn't we first make it one. Afterwards we + * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all + * submounts we can access, too. When mounts are stacked on + * the same mount point we only care for each individual + * "top-level" mount on each point, as we cannot + * influence/access the underlying mounts anyway. We do not + * have any effect on future submounts that might get + * propagated, they migt be writable. This includes future + * submounts that have been triggered via autofs. */ + + cleaned = strdup(prefix); + if (!cleaned) + return -ENOMEM; + + path_kill_slashes(cleaned); + + done = set_new(&string_hash_ops); + if (!done) + return -ENOMEM; + + for (;;) { + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + _cleanup_set_free_free_ Set *todo = NULL; + bool top_autofs = false; + char *x; + unsigned long orig_flags; + + todo = set_new(&string_hash_ops); + if (!todo) + return -ENOMEM; + + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) + return -errno; + + for (;;) { + _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; + int k; + + k = fscanf(proc_self_mountinfo, + "%*s " /* (1) mount id */ + "%*s " /* (2) parent id */ + "%*s " /* (3) major:minor */ + "%*s " /* (4) root */ + "%ms " /* (5) mount point */ + "%*s" /* (6) mount options (superblock) */ + "%*[^-]" /* (7) optional fields */ + "- " /* (8) separator */ + "%ms " /* (9) file system type */ + "%*s" /* (10) mount source */ + "%*s" /* (11) mount options (bind mount) */ + "%*[^\n]", /* some rubbish at the end */ + &path, + &type); + if (k != 2) { + if (k == EOF) + break; + + continue; + } + + r = cunescape(path, UNESCAPE_RELAX, &p); + if (r < 0) + return r; + + /* Let's ignore autofs mounts. If they aren't + * triggered yet, we want to avoid triggering + * them, as we don't make any guarantees for + * future submounts anyway. If they are + * already triggered, then we will find + * another entry for this. */ + if (streq(type, "autofs")) { + top_autofs = top_autofs || path_equal(cleaned, p); + continue; + } + + if (path_startswith(p, cleaned) && + !set_contains(done, p)) { + + r = set_consume(todo, p); + p = NULL; + + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } + } + + /* If we have no submounts to process anymore and if + * the root is either already done, or an autofs, we + * are done */ + if (set_isempty(todo) && + (top_autofs || set_contains(done, cleaned))) + return 0; + + if (!set_contains(done, cleaned) && + !set_contains(todo, cleaned)) { + /* The prefix directory itself is not yet a + * mount, make it one. */ + if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0) + return -errno; + + orig_flags = 0; + (void) get_mount_flags(cleaned, &orig_flags); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) + return -errno; + + x = strdup(cleaned); + if (!x) + return -ENOMEM; + + r = set_consume(done, x); + if (r < 0) + return r; + } + + while ((x = set_steal_first(todo))) { + + r = set_consume(done, x); + if (r == -EEXIST || r == 0) + continue; + if (r < 0) + return r; + + /* Try to reuse the original flag set, but + * don't care for errors, in case of + * obstructed mounts */ + orig_flags = 0; + (void) get_mount_flags(x, &orig_flags); + orig_flags &= ~MS_RDONLY; + + if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { + + /* Deal with mount points that are + * obstructed by a later mount */ + + if (errno != ENOENT) + return -errno; + } + + } + } +} + +int mount_move_root(const char *path) { + assert(path); + + if (chdir(path) < 0) + return -errno; + + if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + + if (chdir("/") < 0) + return -errno; + + return 0; +} + +bool fstype_is_network(const char *fstype) { + static const char table[] = + "afs\0" + "cifs\0" + "smbfs\0" + "sshfs\0" + "ncpfs\0" + "ncp\0" + "nfs\0" + "nfs4\0" + "gfs\0" + "gfs2\0" + "glusterfs\0"; + + const char *x; + + x = startswith(fstype, "fuse."); + if (x) + fstype = x; + + return nulstr_contains(table, fstype); +} + +int repeat_unmount(const char *path, int flags) { + bool done = false; + + assert(path); + + /* If there are multiple mounts on a mount point, this + * removes them all */ + + for (;;) { + if (umount2(path, flags) < 0) { + + if (errno == EINVAL) + return done; + + return -errno; + } + + done = true; + } +} diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h new file mode 100644 index 0000000000..48954c2d67 --- /dev/null +++ b/src/basic/mount-util.h @@ -0,0 +1,52 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <mntent.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "missing.h" + +int fd_is_mount_point(int fd, const char *filename, int flags); +int path_is_mount_point(const char *path, int flags); + +int repeat_unmount(const char *path, int flags); + +int umount_recursive(const char *target, int flags); +int bind_remount_recursive(const char *prefix, bool ro); + +int mount_move_root(const char *path); + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); +#define _cleanup_endmntent_ _cleanup_(endmntentp) + +bool fstype_is_network(const char *fstype); + +union file_handle_union { + struct file_handle handle; + char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; +}; + +#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c new file mode 100644 index 0000000000..b6358c459a --- /dev/null +++ b/src/basic/parse-util.c @@ -0,0 +1,460 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "extract-word.h" +#include "parse-util.h" +#include "string-util.h" +#include "util.h" + +int parse_boolean(const char *v) { + assert(v); + + if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on")) + return 1; + else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off")) + return 0; + + return -EINVAL; +} + +int parse_pid(const char *s, pid_t* ret_pid) { + unsigned long ul = 0; + pid_t pid; + int r; + + assert(s); + assert(ret_pid); + + r = safe_atolu(s, &ul); + if (r < 0) + return r; + + pid = (pid_t) ul; + + if ((unsigned long) pid != ul) + return -ERANGE; + + if (pid <= 0) + return -ERANGE; + + *ret_pid = pid; + return 0; +} + +int parse_mode(const char *s, mode_t *ret) { + char *x; + long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtol(s, &x, 8); + if (errno != 0) + return -errno; + + if (!x || x == s || *x) + return -EINVAL; + if (l < 0 || l > 07777) + return -ERANGE; + + *ret = (mode_t) l; + return 0; +} + +int parse_ifindex(const char *s, int *ret) { + int ifi, r; + + r = safe_atoi(s, &ifi); + if (r < 0) + return r; + if (ifi <= 0) + return -EINVAL; + + *ret = ifi; + return 0; +} + +int parse_size(const char *t, uint64_t base, uint64_t *size) { + + /* Soo, sometimes we want to parse IEC binary suffixes, and + * sometimes SI decimal suffixes. This function can parse + * both. Which one is the right way depends on the + * context. Wikipedia suggests that SI is customary for + * hardware metrics and network speeds, while IEC is + * customary for most data sizes used by software and volatile + * (RAM) memory. Hence be careful which one you pick! + * + * In either case we use just K, M, G as suffix, and not Ki, + * Mi, Gi or so (as IEC would suggest). That's because that's + * frickin' ugly. But this means you really need to make sure + * to document which base you are parsing when you use this + * call. */ + + struct table { + const char *suffix; + unsigned long long factor; + }; + + static const struct table iec[] = { + { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "G", 1024ULL*1024ULL*1024ULL }, + { "M", 1024ULL*1024ULL }, + { "K", 1024ULL }, + { "B", 1ULL }, + { "", 1ULL }, + }; + + static const struct table si[] = { + { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, + { "G", 1000ULL*1000ULL*1000ULL }, + { "M", 1000ULL*1000ULL }, + { "K", 1000ULL }, + { "B", 1ULL }, + { "", 1ULL }, + }; + + const struct table *table; + const char *p; + unsigned long long r = 0; + unsigned n_entries, start_pos = 0; + + assert(t); + assert(base == 1000 || base == 1024); + assert(size); + + if (base == 1000) { + table = si; + n_entries = ELEMENTSOF(si); + } else { + table = iec; + n_entries = ELEMENTSOF(iec); + } + + p = t; + do { + unsigned long long l, tmp; + double frac = 0; + char *e; + unsigned i; + + p += strspn(p, WHITESPACE); + if (*p == '-') + return -ERANGE; + + errno = 0; + l = strtoull(p, &e, 10); + if (errno > 0) + return -errno; + if (e == p) + return -EINVAL; + + if (*e == '.') { + e++; + + /* strtoull() itself would accept space/+/- */ + if (*e >= '0' && *e <= '9') { + unsigned long long l2; + char *e2; + + l2 = strtoull(e, &e2, 10); + if (errno > 0) + return -errno; + + /* Ignore failure. E.g. 10.M is valid */ + frac = l2; + for (; e < e2; e++) + frac /= 10; + } + } + + e += strspn(e, WHITESPACE); + + for (i = start_pos; i < n_entries; i++) + if (startswith(e, table[i].suffix)) + break; + + if (i >= n_entries) + return -EINVAL; + + if (l + (frac > 0) > ULLONG_MAX / table[i].factor) + return -ERANGE; + + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); + if (tmp > ULLONG_MAX - r) + return -ERANGE; + + r += tmp; + if ((unsigned long long) (uint64_t) r != r) + return -ERANGE; + + p = e + strlen(table[i].suffix); + + start_pos = i + 1; + + } while (*p); + + *size = r; + + return 0; +} + +int parse_range(const char *t, unsigned *lower, unsigned *upper) { + _cleanup_free_ char *word = NULL; + unsigned l, u; + int r; + + assert(lower); + assert(upper); + + /* Extract the lower bound. */ + r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + r = safe_atou(word, &l); + if (r < 0) + return r; + + /* Check for the upper bound and extract it if needed */ + if (!t) + /* Single number with no dashes. */ + u = l; + else if (!*t) + /* Trailing dash is an error. */ + return -EINVAL; + else { + r = safe_atou(t, &u); + if (r < 0) + return r; + } + + *lower = l; + *upper = u; + return 0; +} + +char *format_bytes(char *buf, size_t l, uint64_t t) { + unsigned i; + + /* This only does IEC units so far */ + + static const struct { + const char *suffix; + uint64_t factor; + } table[] = { + { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "M", UINT64_C(1024)*UINT64_C(1024) }, + { "K", UINT64_C(1024) }, + }; + + if (t == (uint64_t) -1) + return NULL; + + for (i = 0; i < ELEMENTSOF(table); i++) { + + if (t >= table[i].factor) { + snprintf(buf, l, + "%" PRIu64 ".%" PRIu64 "%s", + t / table[i].factor, + ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), + table[i].suffix); + + goto finish; + } + } + + snprintf(buf, l, "%" PRIu64 "B", t); + +finish: + buf[l-1] = 0; + return buf; + +} + +int safe_atou(const char *s, unsigned *ret_u) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((unsigned long) (unsigned) l != l) + return -ERANGE; + + *ret_u = (unsigned) l; + return 0; +} + +int safe_atoi(const char *s, int *ret_i) { + char *x = NULL; + long l; + + assert(s); + assert(ret_i); + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((long) (int) l != l) + return -ERANGE; + + *ret_i = (int) l; + return 0; +} + +int safe_atollu(const char *s, long long unsigned *ret_llu) { + char *x = NULL; + unsigned long long l; + + assert(s); + assert(ret_llu); + + errno = 0; + l = strtoull(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_llu = l; + return 0; +} + +int safe_atolli(const char *s, long long int *ret_lli) { + char *x = NULL; + long long l; + + assert(s); + assert(ret_lli); + + errno = 0; + l = strtoll(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno ? -errno : -EINVAL; + + *ret_lli = l; + return 0; +} + +int safe_atou8(const char *s, uint8_t *ret) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((unsigned long) (uint8_t) l != l) + return -ERANGE; + + *ret = (uint8_t) l; + return 0; +} + +int safe_atou16(const char *s, uint16_t *ret) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtoul(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((unsigned long) (uint16_t) l != l) + return -ERANGE; + + *ret = (uint16_t) l; + return 0; +} + +int safe_atoi16(const char *s, int16_t *ret) { + char *x = NULL; + long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtol(s, &x, 0); + + if (!x || x == s || *x || errno) + return errno > 0 ? -errno : -EINVAL; + + if ((long) (int16_t) l != l) + return -ERANGE; + + *ret = (int16_t) l; + return 0; +} + +int safe_atod(const char *s, double *ret_d) { + char *x = NULL; + double d = 0; + locale_t loc; + + assert(s); + assert(ret_d); + + loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); + if (loc == (locale_t) 0) + return -errno; + + errno = 0; + d = strtod_l(s, &x, loc); + + if (!x || x == s || *x || errno) { + freelocale(loc); + return errno ? -errno : -EINVAL; + } + + freelocale(loc); + *ret_d = (double) d; + return 0; +} diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h new file mode 100644 index 0000000000..408690d0b3 --- /dev/null +++ b/src/basic/parse-util.h @@ -0,0 +1,92 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <inttypes.h> +#include <sys/types.h> + +#include "macro.h" + +#define MODE_INVALID ((mode_t) -1) + +int parse_boolean(const char *v) _pure_; +int parse_pid(const char *s, pid_t* ret_pid); +int parse_mode(const char *s, mode_t *ret); +int parse_ifindex(const char *s, int *ret); + +int parse_size(const char *t, uint64_t base, uint64_t *size); +int parse_range(const char *t, unsigned *lower, unsigned *upper); + +#define FORMAT_BYTES_MAX 8 +char *format_bytes(char *buf, size_t l, uint64_t t); + +int safe_atou(const char *s, unsigned *ret_u); +int safe_atoi(const char *s, int *ret_i); +int safe_atollu(const char *s, unsigned long long *ret_u); +int safe_atolli(const char *s, long long int *ret_i); + +int safe_atou8(const char *s, uint8_t *ret); + +int safe_atou16(const char *s, uint16_t *ret); +int safe_atoi16(const char *s, int16_t *ret); + +static inline int safe_atou32(const char *s, uint32_t *ret_u) { + assert_cc(sizeof(uint32_t) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} + +static inline int safe_atoi32(const char *s, int32_t *ret_i) { + assert_cc(sizeof(int32_t) == sizeof(int)); + return safe_atoi(s, (int*) ret_i); +} + +static inline int safe_atou64(const char *s, uint64_t *ret_u) { + assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} + +static inline int safe_atoi64(const char *s, int64_t *ret_i) { + assert_cc(sizeof(int64_t) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_i); +} + +#if LONG_MAX == INT_MAX +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(int)); + return safe_atoi(s, (int*) ret_u); +} +#else +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_u); +} +#endif + +int safe_atod(const char *s, double *ret_d); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 5cbfc145a4..ec90c432a4 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -19,21 +19,33 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> #include <errno.h> -#include <stdlib.h> -#include <stdio.h> #include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/statvfs.h> +#include <unistd.h> -#include "macro.h" -#include "util.h" +/* When we include libgen.h because we need dirname() we immediately + * undefine basename() since libgen.h defines it as a macro to the + * POSIX version which is really broken. We prefer GNU basename(). */ +#include <libgen.h> +#undef basename + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "log.h" -#include "strv.h" -#include "path-util.h" +#include "macro.h" #include "missing.h" -#include "fileio.h" +#include "parse-util.h" +#include "path-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" bool path_is_absolute(const char *p) { return p[0] == '/'; @@ -43,61 +55,25 @@ bool is_path(const char *p) { return !!strchr(p, '/'); } -int path_get_parent(const char *path, char **_r) { - const char *e, *a = NULL, *b = NULL, *p; - char *r; - bool slash = false; - - assert(path); - assert(_r); - - if (!*path) - return -EINVAL; - - for (e = path; *e; e++) { - - if (!slash && *e == '/') { - a = b; - b = e; - slash = true; - } else if (slash && *e != '/') - slash = false; - } - - if (*(e-1) == '/') - p = a; - else - p = b; - - if (!p) - return -EINVAL; - - if (p == path) - r = strdup("/"); - else - r = strndup(path, p-path); - - if (!r) - return -ENOMEM; - - *_r = r; - return 0; -} - -char **path_split_and_make_absolute(const char *p) { +int path_split_and_make_absolute(const char *p, char ***ret) { char **l; + int r; + assert(p); + assert(ret); l = strv_split(p, ":"); if (!l) - return NULL; + return -ENOMEM; - if (!path_strv_make_absolute_cwd(l)) { + r = path_strv_make_absolute_cwd(l); + if (r < 0) { strv_free(l); - return NULL; + return r; } - return l; + *ret = l; + return r; } char *path_make_absolute(const char *p, const char *prefix) { @@ -112,22 +88,31 @@ char *path_make_absolute(const char *p, const char *prefix) { return strjoin(prefix, "/", p, NULL); } -char *path_make_absolute_cwd(const char *p) { - _cleanup_free_ char *cwd = NULL; +int path_make_absolute_cwd(const char *p, char **ret) { + char *c; assert(p); + assert(ret); /* Similar to path_make_absolute(), but prefixes with the * current working directory. */ if (path_is_absolute(p)) - return strdup(p); + c = strdup(p); + else { + _cleanup_free_ char *cwd = NULL; - cwd = get_current_dir_name(); - if (!cwd) - return NULL; + cwd = get_current_dir_name(); + if (!cwd) + return -errno; + + c = strjoin(cwd, "/", p, NULL); + } + if (!c) + return -ENOMEM; - return strjoin(cwd, "/", p, NULL); + *ret = c; + return 0; } int path_make_relative(const char *from_dir, const char *to_path, char **_r) { @@ -215,8 +200,9 @@ int path_make_relative(const char *from_dir, const char *to_path, char **_r) { return 0; } -char **path_strv_make_absolute_cwd(char **l) { +int path_strv_make_absolute_cwd(char **l) { char **s; + int r; /* Goes through every item in the string list and makes it * absolute. This works in place and won't rollback any @@ -225,15 +211,15 @@ char **path_strv_make_absolute_cwd(char **l) { STRV_FOREACH(s, l) { char *t; - t = path_make_absolute_cwd(*s); - if (!t) - return NULL; + r = path_make_absolute_cwd(*s, &t); + if (r < 0) + return r; free(*s); *s = t; } - return l; + return 0; } char **path_strv_resolve(char **l, const char *prefix) { @@ -411,7 +397,7 @@ int path_compare(const char *a, const char *b) { * Which one is sorted before the other does not really matter. * Here a relative path is ordered before an absolute path. */ d = (a[0] == '/') - (b[0] == '/'); - if (d) + if (d != 0) return d; for (;;) { @@ -434,12 +420,12 @@ int path_compare(const char *a, const char *b) { /* Alphabetical sort: "/foo/aaa" before "/foo/b" */ d = memcmp(a, b, MIN(j, k)); - if (d) + if (d != 0) return (d > 0) - (d < 0); /* sign of d */ /* Sort "/foo/a" before "/foo/aaa" */ d = (j > k) - (j < k); /* sign of (j - k) */ - if (d) + if (d != 0) return d; a += j; @@ -471,294 +457,66 @@ char* path_join(const char *root, const char *path, const char *rest) { NULL); } -static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { - char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; - _cleanup_free_ char *fdinfo = NULL; - _cleanup_close_ int subfd = -1; - char *p; - int r; - - if ((flags & AT_EMPTY_PATH) && isempty(filename)) - xsprintf(path, "/proc/self/fdinfo/%i", fd); - else { - subfd = openat(fd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH); - if (subfd < 0) - return -errno; - - xsprintf(path, "/proc/self/fdinfo/%i", subfd); - } - - r = read_full_file(path, &fdinfo, NULL); - if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ - return -EOPNOTSUPP; - if (r < 0) - return -errno; - - p = startswith(fdinfo, "mnt_id:"); - if (!p) { - p = strstr(fdinfo, "\nmnt_id:"); - if (!p) /* The mnt_id field is a relatively new addition */ - return -EOPNOTSUPP; - - p += 8; - } - - p += strspn(p, WHITESPACE); - p[strcspn(p, WHITESPACE)] = 0; - - return safe_atoi(p, mnt_id); -} - -int fd_is_mount_point(int fd, const char *filename, int flags) { - union file_handle_union h = FILE_HANDLE_INIT, h_parent = FILE_HANDLE_INIT; - int mount_id = -1, mount_id_parent = -1; - bool nosupp = false, check_st_dev = true; - struct stat a, b; - int r; +int find_binary(const char *name, char **ret) { + int last_error, r; + const char *p; - assert(fd >= 0); - assert(filename); - - /* First we will try the name_to_handle_at() syscall, which - * tells us the mount id and an opaque file "handle". It is - * not supported everywhere though (kernel compile-time - * option, not all file systems are hooked up). If it works - * the mount id is usually good enough to tell us whether - * something is a mount point. - * - * If that didn't work we will try to read the mount id from - * /proc/self/fdinfo/<fd>. This is almost as good as - * name_to_handle_at(), however, does not return the - * opaque file handle. The opaque file handle is pretty useful - * to detect the root directory, which we should always - * consider a mount point. Hence we use this only as - * fallback. Exporting the mnt_id in fdinfo is a pretty recent - * kernel addition. - * - * As last fallback we do traditional fstat() based st_dev - * comparisons. This is how things were traditionally done, - * but unionfs breaks breaks this since it exposes file - * systems with a variety of st_dev reported. Also, btrfs - * subvolumes have different st_dev, even though they aren't - * real mounts of their own. */ - - r = name_to_handle_at(fd, filename, &h.handle, &mount_id, flags); - if (r < 0) { - if (errno == ENOSYS) - /* This kernel does not support name_to_handle_at() - * fall back to simpler logic. */ - goto fallback_fdinfo; - else if (errno == EOPNOTSUPP) - /* This kernel or file system does not support - * name_to_handle_at(), hence let's see if the - * upper fs supports it (in which case it is a - * mount point), otherwise fallback to the - * traditional stat() logic */ - nosupp = true; - else - return -errno; - } + assert(name); - r = name_to_handle_at(fd, "", &h_parent.handle, &mount_id_parent, AT_EMPTY_PATH); - if (r < 0) { - if (errno == EOPNOTSUPP) { - if (nosupp) - /* Neither parent nor child do name_to_handle_at()? - We have no choice but to fall back. */ - goto fallback_fdinfo; - else - /* The parent can't do name_to_handle_at() but the - * directory we are interested in can? - * If so, it must be a mount point. */ - return 1; - } else + if (is_path(name)) { + if (access(name, X_OK) < 0) return -errno; - } - - /* The parent can do name_to_handle_at() but the - * directory we are interested in can't? If so, it - * must be a mount point. */ - if (nosupp) - return 1; - - /* If the file handle for the directory we are - * interested in and its parent are identical, we - * assume this is the root directory, which is a mount - * point. */ - - if (h.handle.handle_bytes == h_parent.handle.handle_bytes && - h.handle.handle_type == h_parent.handle.handle_type && - memcmp(h.handle.f_handle, h_parent.handle.f_handle, h.handle.handle_bytes) == 0) - return 1; - - return mount_id != mount_id_parent; - -fallback_fdinfo: - r = fd_fdinfo_mnt_id(fd, filename, flags, &mount_id); - if (r == -EOPNOTSUPP) - goto fallback_fstat; - if (r < 0) - return r; - - r = fd_fdinfo_mnt_id(fd, "", AT_EMPTY_PATH, &mount_id_parent); - if (r < 0) - return r; - - if (mount_id != mount_id_parent) - return 1; - - /* Hmm, so, the mount ids are the same. This leaves one - * special case though for the root file system. For that, - * let's see if the parent directory has the same inode as we - * are interested in. Hence, let's also do fstat() checks now, - * too, but avoid the st_dev comparisons, since they aren't - * that useful on unionfs mounts. */ - check_st_dev = false; - -fallback_fstat: - /* yay for fstatat() taking a different set of flags than the other - * _at() above */ - if (flags & AT_SYMLINK_FOLLOW) - flags &= ~AT_SYMLINK_FOLLOW; - else - flags |= AT_SYMLINK_NOFOLLOW; - if (fstatat(fd, filename, &a, flags) < 0) - return -errno; - - if (fstatat(fd, "", &b, AT_EMPTY_PATH) < 0) - return -errno; - - /* A directory with same device and inode as its parent? Must - * be the root directory */ - if (a.st_dev == b.st_dev && - a.st_ino == b.st_ino) - return 1; - - return check_st_dev && (a.st_dev != b.st_dev); -} -/* flags can be AT_SYMLINK_FOLLOW or 0 */ -int path_is_mount_point(const char *t, int flags) { - _cleanup_close_ int fd = -1; - _cleanup_free_ char *canonical = NULL, *parent = NULL; - int r; - - assert(t); - - if (path_equal(t, "/")) - return 1; - - /* we need to resolve symlinks manually, we can't just rely on - * fd_is_mount_point() to do that for us; if we have a structure like - * /bin -> /usr/bin/ and /usr is a mount point, then the parent that we - * look at needs to be /usr, not /. */ - if (flags & AT_SYMLINK_FOLLOW) { - canonical = canonicalize_file_name(t); - if (!canonical) - return -errno; + if (ret) { + r = path_make_absolute_cwd(name, ret); + if (r < 0) + return r; + } - t = canonical; + return 0; } - r = path_get_parent(t, &parent); - if (r < 0) - return r; - - fd = openat(AT_FDCWD, parent, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_PATH); - if (fd < 0) - return -errno; - - return fd_is_mount_point(fd, basename(t), flags); -} - -int path_is_read_only_fs(const char *path) { - struct statvfs st; - - assert(path); - - if (statvfs(path, &st) < 0) - return -errno; - - if (st.f_flag & ST_RDONLY) - return true; - - /* On NFS, statvfs() might not reflect whether we can actually - * write to the remote share. Let's try again with - * access(W_OK) which is more reliable, at least sometimes. */ - if (access(path, W_OK) < 0 && errno == EROFS) - return true; - - return false; -} - -int path_is_os_tree(const char *path) { - char *p; - int r; - - /* We use /usr/lib/os-release as flag file if something is an OS */ - p = strjoina(path, "/usr/lib/os-release"); - r = access(p, F_OK); - - if (r >= 0) - return 1; - - /* Also check for the old location in /etc, just in case. */ - p = strjoina(path, "/etc/os-release"); - r = access(p, F_OK); - - return r >= 0; -} - -int find_binary(const char *name, bool local, char **filename) { - assert(name); + /** + * Plain getenv, not secure_getenv, because we want + * to actually allow the user to pick the binary. + */ + p = getenv("PATH"); + if (!p) + p = DEFAULT_PATH; - if (is_path(name)) { - if (local && access(name, X_OK) < 0) - return -errno; + last_error = -ENOENT; - if (filename) { - char *p; + for (;;) { + _cleanup_free_ char *j = NULL, *element = NULL; - p = path_make_absolute_cwd(name); - if (!p) - return -ENOMEM; + r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + break; - *filename = p; - } + if (!path_is_absolute(element)) + continue; - return 0; - } else { - const char *path; - const char *word, *state; - size_t l; - - /** - * Plain getenv, not secure_getenv, because we want - * to actually allow the user to pick the binary. - */ - path = getenv("PATH"); - if (!path) - path = DEFAULT_PATH; - - FOREACH_WORD_SEPARATOR(word, l, path, ":", state) { - _cleanup_free_ char *p = NULL; - - if (asprintf(&p, "%.*s/%s", (int) l, word, name) < 0) - return -ENOMEM; + j = strjoin(element, "/", name, NULL); + if (!j) + return -ENOMEM; - if (access(p, X_OK) < 0) - continue; + if (access(j, X_OK) >= 0) { + /* Found it! */ - if (filename) { - *filename = path_kill_slashes(p); - p = NULL; + if (ret) { + *ret = path_kill_slashes(j); + j = NULL; } return 0; } - return -ENOENT; + last_error = -errno; } + + return last_error; } bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) { @@ -796,14 +554,13 @@ bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool upd return changed; } -int fsck_exists(const char *fstype) { +static int binary_is_good(const char *binary) { _cleanup_free_ char *p = NULL, *d = NULL; - const char *checker; int r; - checker = strjoina("fsck.", fstype); - - r = find_binary(checker, true, &p); + r = find_binary(binary, &p); + if (r == -ENOENT) + return 0; if (r < 0) return r; @@ -811,13 +568,39 @@ int fsck_exists(const char *fstype) { * fsck */ r = readlink_malloc(p, &d); - if (r >= 0 && - (path_equal(d, "/bin/true") || - path_equal(d, "/usr/bin/true") || - path_equal(d, "/dev/null"))) - return -ENOENT; + if (r == -EINVAL) /* not a symlink */ + return 1; + if (r < 0) + return r; - return 0; + return !path_equal(d, "true") && + !path_equal(d, "/bin/true") && + !path_equal(d, "/usr/bin/true") && + !path_equal(d, "/dev/null"); +} + +int fsck_exists(const char *fstype) { + const char *checker; + + assert(fstype); + + if (streq(fstype, "auto")) + return -EINVAL; + + checker = strjoina("fsck.", fstype); + return binary_is_good(checker); +} + +int mkfs_exists(const char *fstype) { + const char *mkfs; + + assert(fstype); + + if (streq(fstype, "auto")) + return -EINVAL; + + mkfs = strjoina("mkfs.", fstype); + return binary_is_good(mkfs); } char *prefix_root(const char *root, const char *path) { @@ -853,3 +636,166 @@ char *prefix_root(const char *root, const char *path) { strcpy(p, path); return n; } + +int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) { + char *p; + int r; + + /* + * This function is intended to be used in command line + * parsers, to handle paths that are passed in. It makes the + * path absolute, and reduces it to NULL if omitted or + * root (the latter optionally). + * + * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON + * SUCCESS! Hence, do not pass in uninitialized pointers. + */ + + if (isempty(path)) { + *arg = mfree(*arg); + return 0; + } + + r = path_make_absolute_cwd(path, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); + + path_kill_slashes(p); + if (suppress_root && path_equal(p, "/")) + p = mfree(p); + + free(*arg); + *arg = p; + return 0; +} + +char* dirname_malloc(const char *path) { + char *d, *dir, *dir2; + + assert(path); + + d = strdup(path); + if (!d) + return NULL; + + dir = dirname(d); + assert(dir); + + if (dir == d) + return d; + + dir2 = strdup(dir); + free(d); + + return dir2; +} + +bool filename_is_valid(const char *p) { + const char *e; + + if (isempty(p)) + return false; + + if (streq(p, ".")) + return false; + + if (streq(p, "..")) + return false; + + e = strchrnul(p, '/'); + if (*e != 0) + return false; + + if (e - p > FILENAME_MAX) + return false; + + return true; +} + +bool path_is_safe(const char *p) { + + if (isempty(p)) + return false; + + if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) + return false; + + if (strlen(p)+1 > PATH_MAX) + return false; + + /* The following two checks are not really dangerous, but hey, they still are confusing */ + if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) + return false; + + if (strstr(p, "//")) + return false; + + return true; +} + +char *file_in_same_dir(const char *path, const char *filename) { + char *e, *ret; + size_t k; + + assert(path); + assert(filename); + + /* This removes the last component of path and appends + * filename, unless the latter is absolute anyway or the + * former isn't */ + + if (path_is_absolute(filename)) + return strdup(filename); + + e = strrchr(path, '/'); + if (!e) + return strdup(filename); + + k = strlen(filename); + ret = new(char, (e + 1 - path) + k + 1); + if (!ret) + return NULL; + + memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1); + return ret; +} + +bool hidden_file_allow_backup(const char *filename) { + assert(filename); + + return + filename[0] == '.' || + streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || + endswith(filename, ".rpmnew") || + endswith(filename, ".rpmsave") || + endswith(filename, ".rpmorig") || + endswith(filename, ".dpkg-old") || + endswith(filename, ".dpkg-new") || + endswith(filename, ".dpkg-tmp") || + endswith(filename, ".dpkg-dist") || + endswith(filename, ".dpkg-bak") || + endswith(filename, ".dpkg-backup") || + endswith(filename, ".dpkg-remove") || + endswith(filename, ".swp"); +} + +bool hidden_file(const char *filename) { + assert(filename); + + if (endswith(filename, "~")) + return true; + + return hidden_file_allow_backup(filename); +} + +bool is_device_path(const char *path) { + + /* Returns true on paths that refer to a device, either in + * sysfs or in /dev */ + + return + path_startswith(path, "/dev/") || + path_startswith(path, "/sys/"); +} diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 1eac89c51b..989e0f9004 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -36,11 +36,10 @@ #endif bool is_path(const char *p) _pure_; -char** path_split_and_make_absolute(const char *p); -int path_get_parent(const char *path, char **parent); +int path_split_and_make_absolute(const char *p, char ***ret); bool path_is_absolute(const char *p) _pure_; char* path_make_absolute(const char *p, const char *prefix); -char* path_make_absolute_cwd(const char *p); +int path_make_absolute_cwd(const char *p, char **ret); int path_make_relative(const char *from_dir, const char *to_path, char **_r); char* path_kill_slashes(char *path); char* path_startswith(const char *path, const char *prefix) _pure_; @@ -49,20 +48,16 @@ bool path_equal(const char *a, const char *b) _pure_; bool path_equal_or_files_same(const char *a, const char *b); char* path_join(const char *root, const char *path, const char *rest); -char** path_strv_make_absolute_cwd(char **l); +int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *prefix); char** path_strv_resolve_uniq(char **l, const char *prefix); -int fd_is_mount_point(int fd, const char *filename, int flags); -int path_is_mount_point(const char *path, int flags); -int path_is_read_only_fs(const char *path); -int path_is_os_tree(const char *path); - -int find_binary(const char *name, bool local, char **filename); +int find_binary(const char *name, char **filename); bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); int fsck_exists(const char *fstype); +int mkfs_exists(const char *fstype); /* Iterates through the path prefixes of the specified path, going up * the tree, to root. Also returns "" (and not "/"!) for the root @@ -100,3 +95,17 @@ char *prefix_root(const char *root, const char *path); } \ _ret; \ }) + +int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg); + +char* dirname_malloc(const char *path); + +bool filename_is_valid(const char *p) _pure_; +bool path_is_safe(const char *p) _pure_; + +char *file_in_same_dir(const char *path, const char *filename); + +bool hidden_file_allow_backup(const char *filename); +bool hidden_file(const char *filename) _pure_; + +bool is_device_path(const char *path); diff --git a/src/basic/prioq.c b/src/basic/prioq.c index b89888be0e..7590698911 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -19,8 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +/* + * Priority Queue + * The prioq object implements a priority queue. That is, it orders objects by + * their priority and allows O(1) access to the object with the highest + * priority. Insertion and removal are Θ(log n). Optionally, the caller can + * provide a pointer to an index which will be kept up-to-date by the prioq. + * + * The underlying algorithm used in this implementation is a Heap. + */ + +#include "alloc-util.h" #include "prioq.h" +#include "util.h" struct prioq_item { void *data; @@ -101,7 +112,7 @@ static unsigned shuffle_up(Prioq *q, unsigned idx) { k = (idx-1)/2; - if (q->compare_func(q->items[k].data, q->items[idx].data) < 0) + if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0) break; swap(q, idx, k); diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c new file mode 100644 index 0000000000..4464573c5b --- /dev/null +++ b/src/basic/proc-cmdline.c @@ -0,0 +1,174 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "extract-word.h" +#include "fileio.h" +#include "macro.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "special.h" +#include "string-util.h" +#include "util.h" +#include "virt.h" + +int proc_cmdline(char **ret) { + assert(ret); + + if (detect_container() > 0) + return get_process_cmdline(1, 0, false, ret); + else + return read_one_line_file("/proc/cmdline", ret); +} + +int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { + _cleanup_free_ char *line = NULL; + const char *p; + int r; + + assert(parse_item); + + r = proc_cmdline(&line); + if (r < 0) + return r; + + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + char *value = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + if (r < 0) + return r; + if (r == 0) + break; + + /* Filter out arguments that are intended only for the + * initrd */ + if (!in_initrd() && startswith(word, "rd.")) + continue; + + value = strchr(word, '='); + if (value) + *(value++) = 0; + + r = parse_item(word, value); + if (r < 0) + return r; + } + + return 0; +} + +int get_proc_cmdline_key(const char *key, char **value) { + _cleanup_free_ char *line = NULL, *ret = NULL; + bool found = false; + const char *p; + int r; + + assert(key); + + r = proc_cmdline(&line); + if (r < 0) + return r; + + p = line; + for (;;) { + _cleanup_free_ char *word = NULL; + const char *e; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + if (r < 0) + return r; + if (r == 0) + break; + + /* Filter out arguments that are intended only for the + * initrd */ + if (!in_initrd() && startswith(word, "rd.")) + continue; + + if (value) { + e = startswith(word, key); + if (!e) + continue; + + r = free_and_strdup(&ret, e); + if (r < 0) + return r; + + found = true; + } else { + if (streq(word, key)) + found = true; + } + } + + if (value) { + *value = ret; + ret = NULL; + } + + return found; + +} + +int shall_restore_state(void) { + _cleanup_free_ char *value = NULL; + int r; + + r = get_proc_cmdline_key("systemd.restore_state=", &value); + if (r < 0) + return r; + if (r == 0) + return true; + + return parse_boolean(value); +} + +static const char * const rlmap[] = { + "emergency", SPECIAL_EMERGENCY_TARGET, + "-b", SPECIAL_EMERGENCY_TARGET, + "rescue", SPECIAL_RESCUE_TARGET, + "single", SPECIAL_RESCUE_TARGET, + "-s", SPECIAL_RESCUE_TARGET, + "s", SPECIAL_RESCUE_TARGET, + "S", SPECIAL_RESCUE_TARGET, + "1", SPECIAL_RESCUE_TARGET, + "2", SPECIAL_MULTI_USER_TARGET, + "3", SPECIAL_MULTI_USER_TARGET, + "4", SPECIAL_MULTI_USER_TARGET, + "5", SPECIAL_GRAPHICAL_TARGET, +}; + +const char* runlevel_to_target(const char *word) { + size_t i; + + if (!word) + return NULL; + + for (i = 0; i < ELEMENTSOF(rlmap); i += 2) + if (streq(word, rlmap[i])) + return rlmap[i+1]; + + return NULL; +} diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h new file mode 100644 index 0000000000..ce6e84995a --- /dev/null +++ b/src/basic/proc-cmdline.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +int proc_cmdline(char **ret); +int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value)); +int get_proc_cmdline_key(const char *parameter, char **value); + +int shall_restore_state(void); +const char* runlevel_to_target(const char *rl); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index cff2d2a034..7631928d5f 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -17,22 +17,33 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> -#include <sys/types.h> -#include <string.h> -#include <stdio.h> #include <assert.h> +#include <ctype.h> #include <errno.h> -#include <unistd.h> -#include <sys/wait.h> +#include <sched.h> #include <signal.h> -#include <ctype.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h> +#include <sys/personality.h> +#include <sys/prctl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" -#include "util.h" +#include "fs-util.h" +#include "ioprio.h" #include "log.h" -#include "signal-util.h" #include "process-util.h" +#include "signal-util.h" +#include "string-table.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" int get_process_state(pid_t pid) { const char *p; @@ -174,6 +185,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char * return 0; } +void rename_process(const char name[8]) { + assert(name); + + /* This is a like a poor man's setproctitle(). It changes the + * comm field, argv[0], and also the glibc's internally used + * name of the process. For the first one a limit of 16 chars + * applies, to the second one usually one of 10 (i.e. length + * of "/sbin/init"), to the third one one of 7 (i.e. length of + * "systemd"). If you pass a longer string it will be + * truncated */ + + prctl(PR_SET_NAME, name); + + if (program_invocation_name) + strncpy(program_invocation_name, name, strlen(program_invocation_name)); + + if (saved_argc > 0) { + int i; + + if (saved_argv[0]) + strncpy(saved_argv[0], name, strlen(saved_argv[0])); + + for (i = 1; i < saved_argc; i++) { + if (!saved_argv[i]) + break; + + memzero(saved_argv[i], strlen(saved_argv[i])); + } + } +} + int is_kernel_thread(pid_t pid) { const char *p; size_t count; @@ -215,7 +257,7 @@ int get_process_capeff(pid_t pid, char **capeff) { p = procfs_file_alloca(pid, "status"); - r = get_status_field(p, "\nCapEff:", capeff); + r = get_proc_field(p, "CapEff", WHITESPACE, capeff); if (r == -ENOENT) return -ESRCH; @@ -364,7 +406,7 @@ int get_process_environ(pid_t pid, char **env) { return 0; } -int get_parent_of_pid(pid_t pid, pid_t *_ppid) { +int get_process_ppid(pid_t pid, pid_t *_ppid) { int r; _cleanup_free_ char *line = NULL; long unsigned ppid; @@ -476,6 +518,16 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_cod return -EPROTO; } +void sigkill_wait(pid_t *pid) { + if (!pid) + return; + if (*pid <= 1) + return; + + if (kill(*pid, SIGKILL) > 0) + (void) wait_for_terminate(*pid, NULL); +} + int kill_and_sigcont(pid_t pid, int sig) { int r; @@ -547,9 +599,12 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) { bool pid_is_unwaited(pid_t pid) { /* Checks whether a PID is still valid at all, including a zombie */ - if (pid <= 0) + if (pid < 0) return false; + if (pid <= 1) /* If we or PID 1 would be dead and have been waited for, this code would not be running */ + return true; + if (kill(pid, 0) >= 0) return true; @@ -561,12 +616,141 @@ bool pid_is_alive(pid_t pid) { /* Checks whether a PID is still valid and not a zombie */ - if (pid <= 0) + if (pid < 0) return false; + if (pid <= 1) /* If we or PID 1 would be a zombie, this code would not be running */ + return true; + r = get_process_state(pid); if (r == -ESRCH || r == 'Z') return false; return true; } + +bool is_main_thread(void) { + static thread_local int cached = 0; + + if (_unlikely_(cached == 0)) + cached = getpid() == gettid() ? 1 : -1; + + return cached > 0; +} + +noreturn void freeze(void) { + + /* Make sure nobody waits for us on a socket anymore */ + close_all_fds(NULL, 0); + + sync(); + + for (;;) + pause(); +} + +bool oom_score_adjust_is_valid(int oa) { + return oa >= OOM_SCORE_ADJ_MIN && oa <= OOM_SCORE_ADJ_MAX; +} + +unsigned long personality_from_string(const char *p) { + + /* Parse a personality specifier. We introduce our own + * identifiers that indicate specific ABIs, rather than just + * hints regarding the register size, since we want to keep + * things open for multiple locally supported ABIs for the + * same register size. We try to reuse the ABI identifiers + * used by libseccomp. */ + +#if defined(__x86_64__) + + if (streq(p, "x86")) + return PER_LINUX32; + + if (streq(p, "x86-64")) + return PER_LINUX; + +#elif defined(__i386__) + + if (streq(p, "x86")) + return PER_LINUX; + +#elif defined(__s390x__) + + if (streq(p, "s390")) + return PER_LINUX32; + + if (streq(p, "s390x")) + return PER_LINUX; + +#elif defined(__s390__) + + if (streq(p, "s390")) + return PER_LINUX; +#endif + + return PERSONALITY_INVALID; +} + +const char* personality_to_string(unsigned long p) { + +#if defined(__x86_64__) + + if (p == PER_LINUX32) + return "x86"; + + if (p == PER_LINUX) + return "x86-64"; + +#elif defined(__i386__) + + if (p == PER_LINUX) + return "x86"; + +#elif defined(__s390x__) + + if (p == PER_LINUX) + return "s390x"; + + if (p == PER_LINUX32) + return "s390"; + +#elif defined(__s390__) + + if (p == PER_LINUX) + return "s390"; + +#endif + + return NULL; +} + +static const char *const ioprio_class_table[] = { + [IOPRIO_CLASS_NONE] = "none", + [IOPRIO_CLASS_RT] = "realtime", + [IOPRIO_CLASS_BE] = "best-effort", + [IOPRIO_CLASS_IDLE] = "idle" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); + +static const char *const sigchld_code_table[] = { + [CLD_EXITED] = "exited", + [CLD_KILLED] = "killed", + [CLD_DUMPED] = "dumped", + [CLD_TRAPPED] = "trapped", + [CLD_STOPPED] = "stopped", + [CLD_CONTINUED] = "continued", +}; + +DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); + +static const char* const sched_policy_table[] = { + [SCHED_OTHER] = "other", + [SCHED_BATCH] = "batch", + [SCHED_IDLE] = "idle", + [SCHED_FIFO] = "fifo", + [SCHED_RR] = "rr" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 07431d043b..72633ebf70 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -27,6 +27,7 @@ #include <signal.h> #include "formats-util.h" +#include "macro.h" #define procfs_file_alloca(pid, field) \ ({ \ @@ -51,15 +52,48 @@ int get_process_capeff(pid_t pid, char **capeff); int get_process_cwd(pid_t pid, char **cwd); int get_process_root(pid_t pid, char **root); int get_process_environ(pid_t pid, char **environ); +int get_process_ppid(pid_t pid, pid_t *ppid); int wait_for_terminate(pid_t pid, siginfo_t *status); int wait_for_terminate_and_warn(const char *name, pid_t pid, bool check_exit_code); +void sigkill_wait(pid_t *pid); +#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait) + int kill_and_sigcont(pid_t pid, int sig); -pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); + void rename_process(const char name[8]); int is_kernel_thread(pid_t pid); + int getenv_for_pid(pid_t pid, const char *field, char **_value); bool pid_is_alive(pid_t pid); bool pid_is_unwaited(pid_t pid); + +bool is_main_thread(void); + +noreturn void freeze(void); + +bool oom_score_adjust_is_valid(int oa); + +#ifndef PERSONALITY_INVALID +/* personality(7) documents that 0xffffffffUL is used for querying the + * current personality, hence let's use that here as error + * indicator. */ +#define PERSONALITY_INVALID 0xffffffffLU +#endif + +unsigned long personality_from_string(const char *p); +const char *personality_to_string(unsigned long); + +int ioprio_class_to_string_alloc(int i, char **s); +int ioprio_class_from_string(const char *s); + +const char *sigchld_code_to_string(int i) _const_; +int sigchld_code_from_string(const char *s) _pure_; + +int sched_policy_to_string_alloc(int i, char **s); +int sched_policy_from_string(const char *s); + +#define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) +#define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) diff --git a/src/basic/random-util.c b/src/basic/random-util.c index b230044f50..2f5c16e2af 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -17,20 +17,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdint.h> #include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> -#include <time.h> +#include <linux/random.h> +#include <stdint.h> #ifdef HAVE_SYS_AUXV_H #include <sys/auxv.h> #endif -#include <linux/random.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include "fd-util.h" +#include "io-util.h" +#include "missing.h" #include "random-util.h" #include "time-util.h" -#include "missing.h" #include "util.h" int dev_urandom(void *p, size_t n) { diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c index 478fc43a38..bf757cbc48 100644 --- a/src/basic/replace-var.c +++ b/src/basic/replace-var.c @@ -21,10 +21,11 @@ #include <string.h> +#include "alloc-util.h" #include "macro.h" -#include "util.h" #include "replace-var.h" -#include "def.h" +#include "string-util.h" +#include "util.h" /* * Generic infrastructure for replacing @FOO@ style variables in diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c new file mode 100644 index 0000000000..2627c813fc --- /dev/null +++ b/src/basic/rlimit-util.c @@ -0,0 +1,70 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "missing.h" +#include "rlimit-util.h" +#include "string-table.h" +#include "util.h" + +int setrlimit_closest(int resource, const struct rlimit *rlim) { + struct rlimit highest, fixed; + + assert(rlim); + + if (setrlimit(resource, rlim) >= 0) + return 0; + + if (errno != EPERM) + return -errno; + + /* So we failed to set the desired setrlimit, then let's try + * to get as close as we can */ + assert_se(getrlimit(resource, &highest) == 0); + + fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); + fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); + + if (setrlimit(resource, &fixed) < 0) + return -errno; + + return 0; +} + +static const char* const rlimit_table[_RLIMIT_MAX] = { + [RLIMIT_CPU] = "LimitCPU", + [RLIMIT_FSIZE] = "LimitFSIZE", + [RLIMIT_DATA] = "LimitDATA", + [RLIMIT_STACK] = "LimitSTACK", + [RLIMIT_CORE] = "LimitCORE", + [RLIMIT_RSS] = "LimitRSS", + [RLIMIT_NOFILE] = "LimitNOFILE", + [RLIMIT_AS] = "LimitAS", + [RLIMIT_NPROC] = "LimitNPROC", + [RLIMIT_MEMLOCK] = "LimitMEMLOCK", + [RLIMIT_LOCKS] = "LimitLOCKS", + [RLIMIT_SIGPENDING] = "LimitSIGPENDING", + [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", + [RLIMIT_NICE] = "LimitNICE", + [RLIMIT_RTPRIO] = "LimitRTPRIO", + [RLIMIT_RTTIME] = "LimitRTTIME" +}; + +DEFINE_STRING_TABLE_LOOKUP(rlimit, int); diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h new file mode 100644 index 0000000000..262f86dd04 --- /dev/null +++ b/src/basic/rlimit-util.h @@ -0,0 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/resource.h> + +#include "macro.h" + +const char *rlimit_to_string(int i) _const_; +int rlimit_from_string(const char *s) _pure_; + +int setrlimit_closest(int resource, const struct rlimit *rlim); + +#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index dbbe817684..8ec7dd75ee 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -19,10 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "path-util.h" #include "btrfs-util.h" +#include "fd-util.h" +#include "mount-util.h" +#include "path-util.h" #include "rm-rf.h" +#include "stat-util.h" +#include "string-util.h" +#include "util.h" int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { _cleanup_closedir_ DIR *d = NULL; @@ -120,7 +124,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { /* This could be a subvolume, try to remove it */ - r = btrfs_subvol_remove_fd(fd, de->d_name, true); + r = btrfs_subvol_remove_fd(fd, de->d_name, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (r < 0) { if (r != -ENOTTY && r != -EINVAL) { if (ret == 0) @@ -178,7 +182,7 @@ int rm_rf(const char *path, RemoveFlags flags) { if ((flags & (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) == (REMOVE_SUBVOLUME|REMOVE_ROOT|REMOVE_PHYSICAL)) { /* Try to remove as subvolume first */ - r = btrfs_subvol_remove(path, true); + r = btrfs_subvol_remove(path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (r >= 0) return r; diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index a39a0f775a..a821a3d5bb 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -29,6 +29,7 @@ #include <selinux/context.h> #endif +#include "alloc-util.h" #include "strv.h" #include "path-util.h" #include "selinux-util.h" @@ -171,15 +172,15 @@ int mac_selinux_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { int mac_selinux_apply(const char *path, const char *label) { #ifdef HAVE_SELINUX - assert(path); - assert(label); - if (!mac_selinux_use()) return 0; + assert(path); + assert(label); + if (setfilecon(path, (security_context_t) label) < 0) { log_enforcing("Failed to set SELinux security context %s on path %s: %m", label, path); - if (security_getenforce() == 1) + if (security_getenforce() > 0) return -errno; } #endif @@ -295,21 +296,27 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * return r; } -void mac_selinux_free(char *label) { +char* mac_selinux_free(char *label) { #ifdef HAVE_SELINUX + if (!label) + return NULL; + if (!mac_selinux_use()) - return; + return NULL; + freecon((security_context_t) label); #endif + + return NULL; } int mac_selinux_create_file_prepare(const char *path, mode_t mode) { - int r = 0; #ifdef HAVE_SELINUX _cleanup_security_context_free_ security_context_t filecon = NULL; + int r; assert(path); @@ -319,34 +326,33 @@ int mac_selinux_create_file_prepare(const char *path, mode_t mode) { if (path_is_absolute(path)) r = selabel_lookup_raw(label_hnd, &filecon, path, mode); else { - _cleanup_free_ char *newpath; + _cleanup_free_ char *newpath = NULL; - newpath = path_make_absolute_cwd(path); - if (!newpath) - return -ENOMEM; + r = path_make_absolute_cwd(path, &newpath); + if (r < 0) + return r; r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode); } - /* No context specified by the policy? Proceed without setting it. */ - if (r < 0 && errno == ENOENT) - return 0; + if (r < 0) { + /* No context specified by the policy? Proceed without setting it. */ + if (errno == ENOENT) + return 0; - if (r < 0) - r = -errno; - else { - r = setfscreatecon(filecon); - if (r < 0) { - log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); - r = -errno; - } + log_enforcing("Failed to determine SELinux security context for %s: %m", path); + } else { + if (setfscreatecon(filecon) >= 0) + return 0; /* Success! */ + + log_enforcing("Failed to set SELinux security context %s for %s: %m", filecon, path); } - if (r < 0 && security_getenforce() == 0) - r = 0; -#endif + if (security_getenforce() > 0) + return -errno; - return r; +#endif + return 0; } void mac_selinux_create_file_clear(void) { @@ -399,6 +405,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { #ifdef HAVE_SELINUX _cleanup_security_context_free_ security_context_t fcon = NULL; const struct sockaddr_un *un; + bool context_changed = false; char *path; int r; @@ -414,7 +421,7 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { goto skipped; /* Filter out anonymous sockets */ - if (addrlen < sizeof(sa_family_t) + 1) + if (addrlen < offsetof(struct sockaddr_un, sun_path) + 1) goto skipped; /* Filter out abstract namespace sockets */ @@ -427,36 +434,44 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { if (path_is_absolute(path)) r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); else { - _cleanup_free_ char *newpath; + _cleanup_free_ char *newpath = NULL; - newpath = path_make_absolute_cwd(path); - if (!newpath) - return -ENOMEM; + r = path_make_absolute_cwd(path, &newpath); + if (r < 0) + return r; r = selabel_lookup_raw(label_hnd, &fcon, newpath, S_IFSOCK); } - if (r == 0) - r = setfscreatecon(fcon); + if (r < 0) { + /* No context specified by the policy? Proceed without setting it */ + if (errno == ENOENT) + goto skipped; - if (r < 0 && errno != ENOENT) { - log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); + log_enforcing("Failed to determine SELinux security context for %s: %m", path); + if (security_getenforce() > 0) + return -errno; - if (security_getenforce() == 1) { - r = -errno; - goto finish; - } + } else { + if (setfscreatecon(fcon) < 0) { + log_enforcing("Failed to set SELinux security context %s for %s: %m", fcon, path); + if (security_getenforce() > 0) + return -errno; + } else + context_changed = true; } - r = bind(fd, addr, addrlen); - if (r < 0) - r = -errno; + r = bind(fd, addr, addrlen) < 0 ? -errno : 0; + + if (context_changed) + setfscreatecon(NULL); -finish: - setfscreatecon(NULL); return r; skipped: #endif - return bind(fd, addr, addrlen) < 0 ? -errno : 0; + if (bind(fd, addr, addrlen) < 0) + return -errno; + + return 0; } diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 8467185291..2afcaec183 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -24,6 +24,8 @@ #include <sys/socket.h> #include <stdbool.h> +#include "macro.h" + bool mac_selinux_use(void); void mac_selinux_retest(void); @@ -36,7 +38,7 @@ int mac_selinux_apply(const char *path, const char *label); int mac_selinux_get_create_label_from_exe(const char *exe, char **label); int mac_selinux_get_our_label(char **label); int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *exec_label, char **label); -void mac_selinux_free(char *label); +char* mac_selinux_free(char *label); int mac_selinux_create_file_prepare(const char *path, mode_t mode); void mac_selinux_create_file_clear(void); @@ -45,3 +47,5 @@ int mac_selinux_create_socket_prepare(const char *label); void mac_selinux_create_socket_clear(void); int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen); + +DEFINE_TRIVIAL_CLEANUP_FUNC(char*, mac_selinux_free); diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 90abe8af81..8038bc891d 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -19,8 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "parse-util.h" #include "signal-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" int reset_all_signal_handlers(void) { static const struct sigaction sa = { @@ -266,3 +269,7 @@ int signal_from_string_try_harder(const char *s) { return signo; } + +void nop_signal_handler(int sig) { + /* nothing here */ +} diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index 5e6eb50b07..e7393e2dac 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -39,3 +39,5 @@ const char *signal_to_string(int i) _const_; int signal_from_string(const char *s) _pure_; int signal_from_string_try_harder(const char *s); + +void nop_signal_handler(int sig); diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index f68bd283a1..3b61961389 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -13,123 +13,170 @@ this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>. (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) + (Refactored by Tom Gundersen to split up in several functions and follow systemd + coding style) */ -#include <stdint.h> -#include <stdio.h> -#include <string.h> + +#include "sparse-endian.h" #include "siphash24.h" +#include "util.h" -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint8_t u8; - -#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) ) - -#define U32TO8_LE(p, v) \ - (p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \ - (p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24); - -#define U64TO8_LE(p, v) \ - U32TO8_LE((p), (u32)((v) )); \ - U32TO8_LE((p) + 4, (u32)((v) >> 32)); - -#define U8TO64_LE(p) \ - (((u64)((p)[0]) ) | \ - ((u64)((p)[1]) << 8) | \ - ((u64)((p)[2]) << 16) | \ - ((u64)((p)[3]) << 24) | \ - ((u64)((p)[4]) << 32) | \ - ((u64)((p)[5]) << 40) | \ - ((u64)((p)[6]) << 48) | \ - ((u64)((p)[7]) << 56)) - -#define SIPROUND \ - do { \ - v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \ - v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \ - v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \ - v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \ - } while(0) +static inline uint64_t rotate_left(uint64_t x, uint8_t b) { + assert(b < 64); + + return (x << b) | (x >> (64 - b)); +} + +static inline void sipround(struct siphash *state) { + assert(state); + + state->v0 += state->v1; + state->v1 = rotate_left(state->v1, 13); + state->v1 ^= state->v0; + state->v0 = rotate_left(state->v0, 32); + state->v2 += state->v3; + state->v3 = rotate_left(state->v3, 16); + state->v3 ^= state->v2; + state->v0 += state->v3; + state->v3 = rotate_left(state->v3, 21); + state->v3 ^= state->v0; + state->v2 += state->v1; + state->v1 = rotate_left(state->v1, 17); + state->v1 ^= state->v2; + state->v2 = rotate_left(state->v2, 32); +} + +void siphash24_init(struct siphash *state, const uint8_t k[16]) { + uint64_t k0, k1; + + assert(state); + assert(k); + + k0 = le64toh(*(le64_t*) k); + k1 = le64toh(*(le64_t*) (k + 8)); + + /* "somepseudorandomlygeneratedbytes" */ + state->v0 = 0x736f6d6570736575ULL ^ k0; + state->v1 = 0x646f72616e646f6dULL ^ k1; + state->v2 = 0x6c7967656e657261ULL ^ k0; + state->v3 = 0x7465646279746573ULL ^ k1; + state->padding = 0; + state->inlen = 0; +} + +void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { + uint64_t m; + const uint8_t *in = _in; + const uint8_t *end = in + inlen; + unsigned left = state->inlen & 7; + + assert(in); + assert(state); + + /* update total length */ + state->inlen += inlen; + + /* if padding exists, fill it out */ + if (left > 0) { + for ( ; in < end && left < 8; in ++, left ++ ) + state->padding |= ( ( uint64_t )*in ) << (left * 8); + + if (in == end && left < 8) + /* we did not have enough input to fill out the padding completely */ + return; -/* SipHash-2-4 */ -void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) -{ - /* "somepseudorandomlygeneratedbytes" */ - u64 v0 = 0x736f6d6570736575ULL; - u64 v1 = 0x646f72616e646f6dULL; - u64 v2 = 0x6c7967656e657261ULL; - u64 v3 = 0x7465646279746573ULL; - u64 b; - u64 k0 = U8TO64_LE( k ); - u64 k1 = U8TO64_LE( k + 8 ); - u64 m; - const u8 *in = _in; - const u8 *end = in + inlen - ( inlen % sizeof( u64 ) ); - const int left = inlen & 7; - b = ( ( u64 )inlen ) << 56; - v3 ^= k1; - v2 ^= k0; - v1 ^= k1; - v0 ^= k0; - - for ( ; in != end; in += 8 ) - { - m = U8TO64_LE( in ); #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m ); + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); + printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding); #endif - v3 ^= m; - SIPROUND; - SIPROUND; - v0 ^= m; - } + state->v3 ^= state->padding; + sipround(state); + sipround(state); + state->v0 ^= state->padding; - switch( left ) - { - case 7: b |= ( ( u64 )in[ 6] ) << 48; + state->padding = 0; + } - case 6: b |= ( ( u64 )in[ 5] ) << 40; + end -= ( state->inlen % sizeof (uint64_t) ); - case 5: b |= ( ( u64 )in[ 4] ) << 32; + for ( ; in < end; in += 8 ) { + m = le64toh(*(le64_t*) in); +#ifdef DEBUG + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); + printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m); +#endif + state->v3 ^= m; + sipround(state); + sipround(state); + state->v0 ^= m; + } + + left = state->inlen & 7; + + switch(left) + { + case 7: state->padding |= ((uint64_t) in[6]) << 48; - case 4: b |= ( ( u64 )in[ 3] ) << 24; + case 6: state->padding |= ((uint64_t) in[5]) << 40; - case 3: b |= ( ( u64 )in[ 2] ) << 16; + case 5: state->padding |= ((uint64_t) in[4]) << 32; - case 2: b |= ( ( u64 )in[ 1] ) << 8; + case 4: state->padding |= ((uint64_t) in[3]) << 24; - case 1: b |= ( ( u64 )in[ 0] ); break; + case 3: state->padding |= ((uint64_t) in[2]) << 16; + + case 2: state->padding |= ((uint64_t) in[1]) << 8; + + case 1: state->padding |= ((uint64_t) in[0]); break; + + case 0: break; + } +} - case 0: break; - } +void siphash24_finalize(uint8_t out[8], struct siphash *state) { + uint64_t b; + b = state->padding | (( ( uint64_t )state->inlen ) << 56); #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b ); + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t)state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t)state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t)state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t)state->v3); + printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding); #endif - v3 ^= b; - SIPROUND; - SIPROUND; - v0 ^= b; + state->v3 ^= b; + sipround(state); + sipround(state); + state->v0 ^= b; + #ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); #endif - v2 ^= 0xff; - SIPROUND; - SIPROUND; - SIPROUND; - SIPROUND; - b = v0 ^ v1 ^ v2 ^ v3; - U64TO8_LE( out, b ); + state->v2 ^= 0xff; + + sipround(state); + sipround(state); + sipround(state); + sipround(state); + + *(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3); +} + +/* SipHash-2-4 */ +void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) { + struct siphash state; + + siphash24_init(&state, k); + siphash24_compress(_in, inlen, &state); + siphash24_finalize(out, &state); } diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index 62e1168a79..6c5cd98ee8 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -3,4 +3,17 @@ #include <inttypes.h> #include <sys/types.h> +struct siphash { + uint64_t v0; + uint64_t v1; + uint64_t v2; + uint64_t v3; + uint64_t padding; + size_t inlen; +}; + +void siphash24_init(struct siphash *state, const uint8_t k[16]); +void siphash24_compress(const void *in, size_t inlen, struct siphash *state); +void siphash24_finalize(uint8_t out[8], struct siphash *state); + void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index 9e221d6eab..fcc046098d 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -23,14 +23,14 @@ #include <sys/xattr.h> -#include "util.h" -#include "process-util.h" -#include "path-util.h" +#include "alloc-util.h" #include "fileio.h" +#include "path-util.h" +#include "process-util.h" #include "smack-util.h" - -#define SMACK_FLOOR_LABEL "_" -#define SMACK_STAR_LABEL "*" +#include "string-table.h" +#include "util.h" +#include "xattr-util.h" #ifdef HAVE_SMACK bool mac_smack_use(void) { diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index b3aa55eb8a..e756dc8c28 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -27,6 +27,9 @@ #include "macro.h" +#define SMACK_FLOOR_LABEL "_" +#define SMACK_STAR_LABEL "*" + typedef enum SmackAttr { SMACK_ATTR_ACCESS = 0, SMACK_ATTR_EXEC = 1, diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index 144e6fd86e..e5d4efc719 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -19,18 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> #include <errno.h> -#include <sys/stat.h> #include <stddef.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" #include "macro.h" -#include "util.h" -#include "mkdir.h" #include "missing.h" +#include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" +#include "util.h" int socket_address_listen( const SocketAddress *a, @@ -146,11 +148,8 @@ int make_socket_fd(int log_level, const char* address, int flags) { int fd, r; r = socket_address_parse(&a, address); - if (r < 0) { - log_error("Failed to parse socket address \"%s\": %s", - address, strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address); fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, NULL, false, false, false, 0755, 0644, NULL); diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 8fd3149276..1acab1ef95 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -19,23 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> -#include <errno.h> #include <arpa/inet.h> -#include <stdio.h> +#include <errno.h> #include <net/if.h> -#include <sys/types.h> -#include <stddef.h> #include <netdb.h> +#include <netinet/ip.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" #include "macro.h" +#include "missing.h" +#include "parse-util.h" #include "path-util.h" -#include "util.h" #include "socket-util.h" -#include "missing.h" -#include "fileio.h" -#include "formats-util.h" +#include "string-table.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" int socket_address_parse(SocketAddress *a, const char *s) { char *e, *n; @@ -749,21 +756,182 @@ bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b return false; } -char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]) { - assert(addr); - assert(buffer); +int fd_inc_sndbuf(int fd, size_t n) { + int r, value; + socklen_t l = sizeof(value); - /* Like ether_ntoa() but uses %02x instead of %x to print - * ethernet addresses, which makes them look less funny. Also, - * doesn't use a static buffer. */ + r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + return 0; - sprintf(buffer, "%02x:%02x:%02x:%02x:%02x:%02x", - addr->ether_addr_octet[0], - addr->ether_addr_octet[1], - addr->ether_addr_octet[2], - addr->ether_addr_octet[3], - addr->ether_addr_octet[4], - addr->ether_addr_octet[5]); + /* If we have the privileges we will ignore the kernel limit. */ + + value = (int) n; + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) + return -errno; + + return 1; +} + +int fd_inc_rcvbuf(int fd, size_t n) { + int r, value; + socklen_t l = sizeof(value); + + r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); + if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) + return 0; + + /* If we have the privileges we will ignore the kernel limit. */ + + value = (int) n; + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) + if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) + return -errno; + return 1; +} + +static const char* const ip_tos_table[] = { + [IPTOS_LOWDELAY] = "low-delay", + [IPTOS_THROUGHPUT] = "throughput", + [IPTOS_RELIABILITY] = "reliability", + [IPTOS_LOWCOST] = "low-cost", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); + +int getpeercred(int fd, struct ucred *ucred) { + socklen_t n = sizeof(struct ucred); + struct ucred u; + int r; + + assert(fd >= 0); + assert(ucred); + + r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); + if (r < 0) + return -errno; + + if (n != sizeof(struct ucred)) + return -EIO; + + /* Check if the data is actually useful and not suppressed due + * to namespacing issues */ + if (u.pid <= 0) + return -ENODATA; + if (u.uid == UID_INVALID) + return -ENODATA; + if (u.gid == GID_INVALID) + return -ENODATA; + + *ucred = u; + return 0; +} + +int getpeersec(int fd, char **ret) { + socklen_t n = 64; + char *s; + int r; + + assert(fd >= 0); + assert(ret); + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + + if (errno != ERANGE) + return -errno; + + s = new0(char, n); + if (!s) + return -ENOMEM; + + r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); + if (r < 0) { + free(s); + return -errno; + } + } + + if (isempty(s)) { + free(s); + return -EOPNOTSUPP; + } + + *ret = s; + return 0; +} + +int send_one_fd(int transport_fd, int fd, int flags) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + + assert(transport_fd >= 0); + assert(fd >= 0); + + cmsg = CMSG_FIRSTHDR(&mh); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); + + mh.msg_controllen = CMSG_SPACE(sizeof(int)); + if (sendmsg(transport_fd, &mh, MSG_NOSIGNAL | flags) < 0) + return -errno; + + return 0; +} + +int receive_one_fd(int transport_fd, int flags) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg, *found = NULL; + + assert(transport_fd >= 0); + + /* + * Receive a single FD via @transport_fd. We don't care for + * the transport-type. We retrieve a single FD at most, so for + * packet-based transports, the caller must ensure to send + * only a single FD per packet. This is best used in + * combination with send_one_fd(). + */ + + if (recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC | flags) < 0) + return -errno; + + CMSG_FOREACH(cmsg, &mh) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS && + cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + assert(!found); + found = cmsg; + break; + } + } + + if (!found) { + cmsg_close_all(&mh); + return -EIO; + } - return buffer; + return *(int*) CMSG_DATA(found); } diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 6b0ce7836f..c60f2556af 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -116,6 +116,17 @@ int netlink_family_from_string(const char *s) _pure_; bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b); -#define ETHER_ADDR_TO_STRING_MAX (3*6) +int fd_inc_sndbuf(int fd, size_t n); +int fd_inc_rcvbuf(int fd, size_t n); -char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); +int ip_tos_to_string_alloc(int i, char **s); +int ip_tos_from_string(const char *s); + +int getpeercred(int fd, struct ucred *ucred); +int getpeersec(int fd, char **ret); + +int send_one_fd(int transport_fd, int fd, int flags); +int receive_one_fd(int transport_fd, int flags); + +#define CMSG_FOREACH(cmsg, mh) \ + for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c new file mode 100644 index 0000000000..3bc66b3be7 --- /dev/null +++ b/src/basic/stat-util.c @@ -0,0 +1,216 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <fcntl.h> +#include <linux/magic.h> +#include <sys/statvfs.h> +#include <unistd.h> + +#include "dirent-util.h" +#include "fd-util.h" +#include "macro.h" +#include "missing.h" +#include "stat-util.h" +#include "string-util.h" + +int is_symlink(const char *path) { + struct stat info; + + assert(path); + + if (lstat(path, &info) < 0) + return -errno; + + return !!S_ISLNK(info.st_mode); +} + +int is_dir(const char* path, bool follow) { + struct stat st; + int r; + + assert(path); + + if (follow) + r = stat(path, &st); + else + r = lstat(path, &st); + if (r < 0) + return -errno; + + return !!S_ISDIR(st.st_mode); +} + +int is_device_node(const char *path) { + struct stat info; + + assert(path); + + if (lstat(path, &info) < 0) + return -errno; + + return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); +} + +int dir_is_empty(const char *path) { + _cleanup_closedir_ DIR *d; + struct dirent *de; + + d = opendir(path); + if (!d) + return -errno; + + FOREACH_DIRENT(de, d, return -errno) + return 0; + + return 1; +} + +bool null_or_empty(struct stat *st) { + assert(st); + + if (S_ISREG(st->st_mode) && st->st_size <= 0) + return true; + + /* We don't want to hardcode the major/minor of /dev/null, + * hence we do a simpler "is this a device node?" check. */ + + if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) + return true; + + return false; +} + +int null_or_empty_path(const char *fn) { + struct stat st; + + assert(fn); + + if (stat(fn, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +int null_or_empty_fd(int fd) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + return null_or_empty(&st); +} + +int path_is_read_only_fs(const char *path) { + struct statvfs st; + + assert(path); + + if (statvfs(path, &st) < 0) + return -errno; + + if (st.f_flag & ST_RDONLY) + return true; + + /* On NFS, statvfs() might not reflect whether we can actually + * write to the remote share. Let's try again with + * access(W_OK) which is more reliable, at least sometimes. */ + if (access(path, W_OK) < 0 && errno == EROFS) + return true; + + return false; +} + +int path_is_os_tree(const char *path) { + char *p; + int r; + + assert(path); + + /* We use /usr/lib/os-release as flag file if something is an OS */ + p = strjoina(path, "/usr/lib/os-release"); + r = access(p, F_OK); + if (r >= 0) + return 1; + + /* Also check for the old location in /etc, just in case. */ + p = strjoina(path, "/etc/os-release"); + r = access(p, F_OK); + + return r >= 0; +} + +int files_same(const char *filea, const char *fileb) { + struct stat a, b; + + assert(filea); + assert(fileb); + + if (stat(filea, &a) < 0) + return -errno; + + if (stat(fileb, &b) < 0) + return -errno; + + return a.st_dev == b.st_dev && + a.st_ino == b.st_ino; +} + +bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) { + assert(s); + assert_cc(sizeof(statfs_f_type_t) >= sizeof(s->f_type)); + + return F_TYPE_EQUAL(s->f_type, magic_value); +} + +int fd_check_fstype(int fd, statfs_f_type_t magic_value) { + struct statfs s; + + if (fstatfs(fd, &s) < 0) + return -errno; + + return is_fs_type(&s, magic_value); +} + +int path_check_fstype(const char *path, statfs_f_type_t magic_value) { + _cleanup_close_ int fd = -1; + + fd = open(path, O_RDONLY); + if (fd < 0) + return -errno; + + return fd_check_fstype(fd, magic_value); +} + +bool is_temporary_fs(const struct statfs *s) { + return is_fs_type(s, TMPFS_MAGIC) || + is_fs_type(s, RAMFS_MAGIC); +} + +int fd_is_temporary_fs(int fd) { + struct statfs s; + + if (fstatfs(fd, &s) < 0) + return -errno; + + return is_temporary_fs(&s); +} diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h new file mode 100644 index 0000000000..909b220a24 --- /dev/null +++ b/src/basic/stat-util.h @@ -0,0 +1,70 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/vfs.h> + +#include "macro.h" + +int is_symlink(const char *path); +int is_dir(const char *path, bool follow); +int is_device_node(const char *path); + +int dir_is_empty(const char *path); + +static inline int dir_is_populated(const char *path) { + int r; + r = dir_is_empty(path); + if (r < 0) + return r; + return !r; +} + +bool null_or_empty(struct stat *st) _pure_; +int null_or_empty_path(const char *fn); +int null_or_empty_fd(int fd); + +int path_is_read_only_fs(const char *path); +int path_is_os_tree(const char *path); + +int files_same(const char *filea, const char *fileb); + +/* The .f_type field of struct statfs is really weird defined on + * different archs. Let's use our own type we know is sufficiently + * larger to store the possible values. */ +typedef long statfs_f_type_t; + +bool is_fs_type(const struct statfs *s, statfs_f_type_t magic_value) _pure_; +int fd_check_fstype(int fd, statfs_f_type_t magic_value); +int path_check_fstype(const char *path, statfs_f_type_t magic_value); + +bool is_temporary_fs(const struct statfs *s) _pure_; +int fd_is_temporary_fs(int fd); + +/* Because statfs.t_type can be int on some architectures, we have to cast + * the const magic to the type, otherwise the compiler warns about + * signed/unsigned comparison, because the magic can be 32 bit unsigned. + */ +#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) diff --git a/src/basic/stdio-util.h b/src/basic/stdio-util.h new file mode 100644 index 0000000000..b36e8a947e --- /dev/null +++ b/src/basic/stdio-util.h @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <printf.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> + +#include "macro.h" + +#define xsprintf(buf, fmt, ...) \ + assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), "xsprintf: " #buf "[] must be big enough") + + +#define VA_FORMAT_ADVANCE(format, ap) \ +do { \ + int _argtypes[128]; \ + size_t _i, _k; \ + _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ + assert(_k < ELEMENTSOF(_argtypes)); \ + for (_i = 0; _i < _k; _i++) { \ + if (_argtypes[_i] & PA_FLAG_PTR) { \ + (void) va_arg(ap, void*); \ + continue; \ + } \ + \ + switch (_argtypes[_i]) { \ + case PA_INT: \ + case PA_INT|PA_FLAG_SHORT: \ + case PA_CHAR: \ + (void) va_arg(ap, int); \ + break; \ + case PA_INT|PA_FLAG_LONG: \ + (void) va_arg(ap, long int); \ + break; \ + case PA_INT|PA_FLAG_LONG_LONG: \ + (void) va_arg(ap, long long int); \ + break; \ + case PA_WCHAR: \ + (void) va_arg(ap, wchar_t); \ + break; \ + case PA_WSTRING: \ + case PA_STRING: \ + case PA_POINTER: \ + (void) va_arg(ap, void*); \ + break; \ + case PA_FLOAT: \ + case PA_DOUBLE: \ + (void) va_arg(ap, double); \ + break; \ + case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ + (void) va_arg(ap, long double); \ + break; \ + default: \ + assert_not_reached("Unknown format string argument."); \ + } \ + } \ +} while(false) diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index 01a076c2ba..f4f702a05a 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -22,8 +22,9 @@ #include <stdlib.h> #include <string.h> -#include "util.h" +#include "alloc-util.h" #include "strbuf.h" +#include "util.h" /* * Strbuf stores given strings in a single continuous allocated memory diff --git a/src/basic/string-table.c b/src/basic/string-table.c new file mode 100644 index 0000000000..a860324fc9 --- /dev/null +++ b/src/basic/string-table.c @@ -0,0 +1,35 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "string-table.h" + +ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { + size_t i; + + if (!key) + return -1; + + for (i = 0; i < len; ++i) + if (streq_ptr(table[i], key)) + return (ssize_t) i; + + return -1; +} diff --git a/src/basic/string-table.h b/src/basic/string-table.h new file mode 100644 index 0000000000..51b6007214 --- /dev/null +++ b/src/basic/string-table.h @@ -0,0 +1,88 @@ + +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "macro.h" +#include "parse-util.h" +#include "string-util.h" + +ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); + +/* For basic lookup tables with strictly enumerated entries */ +#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + scope const char *name##_to_string(type i) { \ + if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ + return NULL; \ + return name##_table[i]; \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + scope type name##_from_string(const char *s) { \ + return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) + +/* For string conversions where numbers are also acceptable */ +#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ + int name##_to_string_alloc(type i, char **str) { \ + char *s; \ + if (i < 0 || i > max) \ + return -ERANGE; \ + if (i < (type) ELEMENTSOF(name##_table)) { \ + s = strdup(name##_table[i]); \ + if (!s) \ + return -ENOMEM; \ + } else { \ + if (asprintf(&s, "%i", i) < 0) \ + return -ENOMEM; \ + } \ + *str = s; \ + return 0; \ + } \ + type name##_from_string(const char *s) { \ + type i; \ + unsigned u = 0; \ + if (!s) \ + return (type) -1; \ + for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ + if (streq_ptr(name##_table[i], s)) \ + return i; \ + if (safe_atou(s, &u) >= 0 && u <= max) \ + return (type) u; \ + return (type) -1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ diff --git a/src/basic/string-util.c b/src/basic/string-util.c new file mode 100644 index 0000000000..6006767daa --- /dev/null +++ b/src/basic/string-util.c @@ -0,0 +1,800 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "gunicode.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" + +int strcmp_ptr(const char *a, const char *b) { + + /* Like strcmp(), but tries to make sense of NULL pointers */ + if (a && b) + return strcmp(a, b); + + if (!a && b) + return -1; + + if (a && !b) + return 1; + + return 0; +} + +char* endswith(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +char* endswith_no_case(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (strcasecmp(s + sl - pl, postfix) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +char* first_word(const char *s, const char *word) { + size_t sl, wl; + const char *p; + + assert(s); + assert(word); + + /* Checks if the string starts with the specified word, either + * followed by NUL or by whitespace. Returns a pointer to the + * NUL or the first character after the whitespace. */ + + sl = strlen(s); + wl = strlen(word); + + if (sl < wl) + return NULL; + + if (wl == 0) + return (char*) s; + + if (memcmp(s, word, wl) != 0) + return NULL; + + p = s + wl; + if (*p == 0) + return (char*) p; + + if (!strchr(WHITESPACE, *p)) + return NULL; + + p += strspn(p, WHITESPACE); + return (char*) p; +} + +static size_t strcspn_escaped(const char *s, const char *reject) { + bool escaped = false; + int n; + + for (n=0; s[n]; n++) { + if (escaped) + escaped = false; + else if (s[n] == '\\') + escaped = true; + else if (strchr(reject, s[n])) + break; + } + + /* if s ends in \, return index of previous char */ + return n - escaped; +} + +/* Split a string into words. */ +const char* split(const char **state, size_t *l, const char *separator, bool quoted) { + const char *current; + + current = *state; + + if (!*current) { + assert(**state == '\0'); + return NULL; + } + + current += strspn(current, separator); + if (!*current) { + *state = current; + return NULL; + } + + if (quoted && strchr("\'\"", *current)) { + char quotechars[2] = {*current, '\0'}; + + *l = strcspn_escaped(current + 1, quotechars); + if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || + (current[*l + 2] && !strchr(separator, current[*l + 2]))) { + /* right quote missing or garbage at the end */ + *state = current; + return NULL; + } + *state = current++ + *l + 2; + } else if (quoted) { + *l = strcspn_escaped(current, separator); + if (current[*l] && !strchr(separator, current[*l])) { + /* unfinished escape */ + *state = current; + return NULL; + } + *state = current + *l; + } else { + *l = strcspn(current, separator); + *state = current + *l; + } + + return current; +} + +char *strnappend(const char *s, const char *suffix, size_t b) { + size_t a; + char *r; + + if (!s && !suffix) + return strdup(""); + + if (!s) + return strndup(suffix, b); + + if (!suffix) + return strdup(s); + + assert(s); + assert(suffix); + + a = strlen(s); + if (b > ((size_t) -1) - a) + return NULL; + + r = new(char, a+b+1); + if (!r) + return NULL; + + memcpy(r, s, a); + memcpy(r+a, suffix, b); + r[a+b] = 0; + + return r; +} + +char *strappend(const char *s, const char *suffix) { + return strnappend(s, suffix, suffix ? strlen(suffix) : 0); +} + +char *strjoin(const char *x, ...) { + va_list ap; + size_t l; + char *r, *p; + + va_start(ap, x); + + if (x) { + l = strlen(x); + + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + } else + l = 0; + + va_end(ap); + + r = new(char, l+1); + if (!r) + return NULL; + + if (x) { + p = stpcpy(r, x); + + va_start(ap, x); + + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + + va_end(ap); + } else + r[0] = 0; + + return r; +} + +char *strstrip(char *s) { + char *e; + + /* Drops trailing whitespace. Modifies the string in + * place. Returns pointer to first non-space character */ + + s += strspn(s, WHITESPACE); + + for (e = strchr(s, 0); e > s; e --) + if (!strchr(WHITESPACE, e[-1])) + break; + + *e = 0; + + return s; +} + +char *delete_chars(char *s, const char *bad) { + char *f, *t; + + /* Drops all whitespace, regardless where in the string */ + + for (f = s, t = s; *f; f++) { + if (strchr(bad, *f)) + continue; + + *(t++) = *f; + } + + *t = 0; + + return s; +} + +char *truncate_nl(char *s) { + assert(s); + + s[strcspn(s, NEWLINE)] = 0; + return s; +} + +char *ascii_strlower(char *t) { + char *p; + + assert(t); + + for (p = t; *p; p++) + if (*p >= 'A' && *p <= 'Z') + *p = *p - 'A' + 'a'; + + return t; +} + +bool chars_intersect(const char *a, const char *b) { + const char *p; + + /* Returns true if any of the chars in a are in b. */ + for (p = a; *p; p++) + if (strchr(b, *p)) + return true; + + return false; +} + +bool string_has_cc(const char *p, const char *ok) { + const char *t; + + assert(p); + + /* + * Check if a string contains control characters. If 'ok' is + * non-NULL it may be a string containing additional CCs to be + * considered OK. + */ + + for (t = p; *t; t++) { + if (ok && strchr(ok, *t)) + continue; + + if (*t > 0 && *t < ' ') + return true; + + if (*t == 127) + return true; + } + + return false; +} + +static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *r; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + r = new0(char, new_length+1); + if (!r) + return NULL; + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + memcpy(r, s, x); + r[x] = '.'; + r[x+1] = '.'; + r[x+2] = '.'; + memcpy(r + x + 3, + s + old_length - (new_length - x - 3), + new_length - x - 3); + + return r; +} + +char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *e; + const char *i, *j; + unsigned k, len, len2; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + /* if no multibyte characters use ascii_ellipsize_mem for speed */ + if (ascii_is_valid(s)) + return ascii_ellipsize_mem(s, old_length, new_length, percent); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + k = 0; + for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { + int c; + + c = utf8_encoded_to_unichar(i); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + + if (k > x) /* last character was wide and went over quota */ + x ++; + + for (j = s + old_length; k < new_length && j > i; ) { + int c; + + j = utf8_prev_char(j); + c = utf8_encoded_to_unichar(j); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + assert(i <= j); + + /* we don't actually need to ellipsize */ + if (i == j) + return memdup(s, old_length + 1); + + /* make space for ellipsis */ + j = utf8_next_char(j); + + len = i - s; + len2 = s + old_length - j; + e = new(char, len + 3 + len2 + 1); + if (!e) + return NULL; + + /* + printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", + old_length, new_length, x, len, len2, k); + */ + + memcpy(e, s, len); + e[len] = 0xe2; /* tri-dot ellipsis: … */ + e[len + 1] = 0x80; + e[len + 2] = 0xa6; + + memcpy(e + len + 3, j, len2 + 1); + + return e; +} + +char *ellipsize(const char *s, size_t length, unsigned percent) { + return ellipsize_mem(s, strlen(s), length, percent); +} + +bool nulstr_contains(const char*nulstr, const char *needle) { + const char *i; + + if (!nulstr) + return false; + + NULSTR_FOREACH(i, nulstr) + if (streq(i, needle)) + return true; + + return false; +} + +char* strshorten(char *s, size_t l) { + assert(s); + + if (l < strlen(s)) + s[l] = 0; + + return s; +} + +char *strreplace(const char *text, const char *old_string, const char *new_string) { + const char *f; + char *t, *r; + size_t l, old_len, new_len; + + assert(text); + assert(old_string); + assert(new_string); + + old_len = strlen(old_string); + new_len = strlen(new_string); + + l = strlen(text); + r = new(char, l+1); + if (!r) + return NULL; + + f = text; + t = r; + while (*f) { + char *a; + size_t d, nl; + + if (!startswith(f, old_string)) { + *(t++) = *(f++); + continue; + } + + d = t - r; + nl = l - old_len + new_len; + a = realloc(r, nl + 1); + if (!a) + goto oom; + + l = nl; + r = a; + t = r + d; + + t = stpcpy(t, new_string); + f += old_len; + } + + *t = 0; + return r; + +oom: + free(r); + return NULL; +} + +char *strip_tab_ansi(char **ibuf, size_t *_isz) { + const char *i, *begin = NULL; + enum { + STATE_OTHER, + STATE_ESCAPE, + STATE_BRACKET + } state = STATE_OTHER; + char *obuf = NULL; + size_t osz = 0, isz; + FILE *f; + + assert(ibuf); + assert(*ibuf); + + /* Strips ANSI color and replaces TABs by 8 spaces */ + + isz = _isz ? *_isz : strlen(*ibuf); + + f = open_memstream(&obuf, &osz); + if (!f) + return NULL; + + for (i = *ibuf; i < *ibuf + isz + 1; i++) { + + switch (state) { + + case STATE_OTHER: + if (i >= *ibuf + isz) /* EOT */ + break; + else if (*i == '\x1B') + state = STATE_ESCAPE; + else if (*i == '\t') + fputs(" ", f); + else + fputc(*i, f); + break; + + case STATE_ESCAPE: + if (i >= *ibuf + isz) { /* EOT */ + fputc('\x1B', f); + break; + } else if (*i == '[') { + state = STATE_BRACKET; + begin = i + 1; + } else { + fputc('\x1B', f); + fputc(*i, f); + state = STATE_OTHER; + } + + break; + + case STATE_BRACKET: + + if (i >= *ibuf + isz || /* EOT */ + (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { + fputc('\x1B', f); + fputc('[', f); + state = STATE_OTHER; + i = begin-1; + } else if (*i == 'm') + state = STATE_OTHER; + break; + } + } + + if (ferror(f)) { + fclose(f); + free(obuf); + return NULL; + } + + fclose(f); + + free(*ibuf); + *ibuf = obuf; + + if (_isz) + *_isz = osz; + + return obuf; +} + +char *strextend(char **x, ...) { + va_list ap; + size_t f, l; + char *r, *p; + + assert(x); + + l = f = *x ? strlen(*x) : 0; + + va_start(ap, x); + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + va_end(ap); + + r = realloc(*x, l+1); + if (!r) + return NULL; + + p = r + f; + + va_start(ap, x); + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + va_end(ap); + + *p = 0; + *x = r; + + return r + l; +} + +char *strrep(const char *s, unsigned n) { + size_t l; + char *r, *p; + unsigned i; + + assert(s); + + l = strlen(s); + p = r = malloc(l * n + 1); + if (!r) + return NULL; + + for (i = 0; i < n; i++) + p = stpcpy(p, s); + + *p = 0; + return r; +} + +int split_pair(const char *s, const char *sep, char **l, char **r) { + char *x, *a, *b; + + assert(s); + assert(sep); + assert(l); + assert(r); + + if (isempty(sep)) + return -EINVAL; + + x = strstr(s, sep); + if (!x) + return -EINVAL; + + a = strndup(s, x - s); + if (!a) + return -ENOMEM; + + b = strdup(x + strlen(sep)); + if (!b) { + free(a); + return -ENOMEM; + } + + *l = a; + *r = b; + + return 0; +} + +int free_and_strdup(char **p, const char *s) { + char *t; + + assert(p); + + /* Replaces a string pointer with an strdup()ed new string, + * possibly freeing the old one. */ + + if (streq_ptr(*p, s)) + return 0; + + if (s) { + t = strdup(s); + if (!t) + return -ENOMEM; + } else + t = NULL; + + free(*p); + *p = t; + + return 1; +} + +#pragma GCC push_options +#pragma GCC optimize("O0") + +void* memory_erase(void *p, size_t l) { + volatile uint8_t* x = (volatile uint8_t*) p; + + /* This basically does what memset() does, but hopefully isn't + * optimized away by the compiler. One of those days, when + * glibc learns memset_s() we should replace this call by + * memset_s(), but until then this has to do. */ + + for (; l > 0; l--) + *(x++) = 'x'; + + return p; +} + +#pragma GCC pop_options + +char* string_erase(char *x) { + + if (!x) + return NULL; + + /* A delicious drop of snake-oil! To be called on memory where + * we stored passphrases or so, after we used them. */ + + return memory_erase(x, strlen(x)); +} + +char *string_free_erase(char *s) { + return mfree(string_erase(s)); +} + +bool string_is_safe(const char *p) { + const char *t; + + if (!p) + return false; + + for (t = p; *t; t++) { + if (*t > 0 && *t < ' ') /* no control characters */ + return false; + + if (strchr(QUOTES "\\\x7f", *t)) + return false; + } + + return true; +} diff --git a/src/basic/string-util.h b/src/basic/string-util.h new file mode 100644 index 0000000000..54f9d3058c --- /dev/null +++ b/src/basic/string-util.h @@ -0,0 +1,184 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <string.h> + +#include "macro.h" + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n\r" +#define NEWLINE "\n\r" +#define QUOTES "\"\'" +#define COMMENTS "#;" +#define GLOB_CHARS "*?[" +#define DIGITS "0123456789" +#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +#define ALPHANUMERICAL LETTERS DIGITS + +#define streq(a,b) (strcmp((a),(b)) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +int strcmp_ptr(const char *a, const char *b) _pure_; + +static inline bool streq_ptr(const char *a, const char *b) { + return strcmp_ptr(a, b) == 0; +} + +static inline const char* strempty(const char *s) { + return s ? s : ""; +} + +static inline const char* strnull(const char *s) { + return s ? s : "(null)"; +} + +static inline const char *strna(const char *s) { + return s ? s : "n/a"; +} + +static inline bool isempty(const char *p) { + return !p || !p[0]; +} + +static inline char *startswith(const char *s, const char *prefix) { + size_t l; + + l = strlen(prefix); + if (strncmp(s, prefix, l) == 0) + return (char*) s + l; + + return NULL; +} + +static inline char *startswith_no_case(const char *s, const char *prefix) { + size_t l; + + l = strlen(prefix); + if (strncasecmp(s, prefix, l) == 0) + return (char*) s + l; + + return NULL; +} + +char *endswith(const char *s, const char *postfix) _pure_; +char *endswith_no_case(const char *s, const char *postfix) _pure_; + +char *first_word(const char *s, const char *word) _pure_; + +const char* split(const char **state, size_t *l, const char *separator, bool quoted); + +#define FOREACH_WORD(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, false, state) + +#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ + _FOREACH_WORD(word, length, s, separator, false, state) + +#define FOREACH_WORD_QUOTED(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, true, state) + +#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ + for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) + +char *strappend(const char *s, const char *suffix); +char *strnappend(const char *s, const char *suffix, size_t length); + +char *strjoin(const char *x, ...) _sentinel_; + +#define strjoina(a, ...) \ + ({ \ + const char *_appendees_[] = { a, __VA_ARGS__ }; \ + char *_d_, *_p_; \ + int _len_ = 0; \ + unsigned _i_; \ + for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ + _len_ += strlen(_appendees_[_i_]); \ + _p_ = _d_ = alloca(_len_ + 1); \ + for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ + _p_ = stpcpy(_p_, _appendees_[_i_]); \ + *_p_ = 0; \ + _d_; \ + }) + +char *strstrip(char *s); +char *delete_chars(char *s, const char *bad); +char *truncate_nl(char *s); + +char *ascii_strlower(char *path); + +bool chars_intersect(const char *a, const char *b) _pure_; + +static inline bool _pure_ in_charset(const char *s, const char* charset) { + assert(s); + assert(charset); + return s[strspn(s, charset)] == '\0'; +} + +bool string_has_cc(const char *p, const char *ok) _pure_; + +char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent); +char *ellipsize(const char *s, size_t length, unsigned percent); + +bool nulstr_contains(const char*nulstr, const char *needle); + +char* strshorten(char *s, size_t l); + +char *strreplace(const char *text, const char *old_string, const char *new_string); + +char *strip_tab_ansi(char **p, size_t *l); + +char *strextend(char **x, ...) _sentinel_; + +char *strrep(const char *s, unsigned n); + +int split_pair(const char *s, const char *sep, char **l, char **r); + +int free_and_strdup(char **p, const char *s); + +/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ +static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { + + if (needlelen <= 0) + return (void*) haystack; + + if (haystacklen < needlelen) + return NULL; + + assert(haystack); + assert(needle); + + return memmem(haystack, haystacklen, needle, needlelen); +} + +void* memory_erase(void *p, size_t l); +char *string_erase(char *x); + +char *string_free_erase(char *s); +DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase); +#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep) + +bool string_is_safe(const char *p) _pure_; diff --git a/src/basic/strv.c b/src/basic/strv.c index b9aef64b15..ba6df716a7 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <errno.h> #include <stdarg.h> +#include <stdlib.h> #include <string.h> -#include <errno.h> +#include "alloc-util.h" +#include "escape.h" +#include "string-util.h" #include "util.h" #include "strv.h" @@ -86,6 +89,15 @@ char **strv_free(char **l) { return NULL; } +char **strv_free_erase(char **l) { + char **i; + + STRV_FOREACH(i, l) + string_erase(*i); + + return strv_free(l); +} + char **strv_copy(char * const *l) { char **r, **k; @@ -188,17 +200,48 @@ char **strv_new(const char *x, ...) { return r; } -int strv_extend_strv(char ***a, char **b) { - int r; - char **s; +int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { + char **s, **t; + size_t p, q, i = 0, j; + + assert(a); + + if (strv_isempty(b)) + return 0; + + p = strv_length(*a); + q = strv_length(b); + + t = realloc(*a, sizeof(char*) * (p + q + 1)); + if (!t) + return -ENOMEM; + + t[p] = NULL; + *a = t; STRV_FOREACH(s, b) { - r = strv_extend(a, *s); - if (r < 0) - return r; + + if (filter_duplicates && strv_contains(t, *s)) + continue; + + t[p+i] = strdup(*s); + if (!t[p+i]) + goto rollback; + + i++; + t[p+i] = NULL; } - return 0; + assert(i <= q); + + return (int) i; + +rollback: + for (j = 0; j < i; j++) + free(t[p + j]); + + t[p] = NULL; + return -ENOMEM; } int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { @@ -277,8 +320,8 @@ char **strv_split_newlines(const char *s) { } int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { - size_t n = 0, allocated = 0; _cleanup_strv_free_ char **l = NULL; + size_t n = 0, allocated = 0; int r; assert(t); @@ -302,13 +345,16 @@ int strv_split_extract(char ***t, const char *s, const char *separators, Extract l[n] = NULL; } - if (!l) + if (!l) { l = new0(char*, 1); + if (!l) + return -ENOMEM; + } *t = l; l = NULL; - return 0; + return (int) n; } char *strv_join(char **l, const char *separator) { @@ -615,6 +661,41 @@ char **strv_split_nulstr(const char *s) { return r; } +int strv_make_nulstr(char **l, char **p, size_t *q) { + size_t n_allocated = 0, n = 0; + _cleanup_free_ char *m = NULL; + char **i; + + assert(p); + assert(q); + + STRV_FOREACH(i, l) { + size_t z; + + z = strlen(*i); + + if (!GREEDY_REALLOC(m, n_allocated, n + z + 1)) + return -ENOMEM; + + memcpy(m + n, *i, z + 1); + n += z + 1; + } + + if (!m) { + m = new0(char, 1); + if (!m) + return -ENOMEM; + n = 0; + } + + *p = m; + *q = n; + + m = NULL; + + return 0; +} + bool strv_overlap(char **a, char **b) { char **i; @@ -641,8 +722,12 @@ char **strv_sort(char **l) { } bool strv_equal(char **a, char **b) { - if (!a || !b) - return a == b; + + if (strv_isempty(a)) + return strv_isempty(b); + + if (strv_isempty(b)) + return false; for ( ; *a || *b; ++a, ++b) if (!streq_ptr(*a, *b)) @@ -720,3 +805,66 @@ bool strv_fnmatch(char* const* patterns, const char *s, int flags) { return false; } + +char ***strv_free_free(char ***l) { + char ***i; + + if (!l) + return NULL; + + for (i = l; *i; i++) + strv_free(*i); + + free(l); + return NULL; +} + +char **strv_skip(char **l, size_t n) { + + while (n > 0) { + if (strv_isempty(l)) + return l; + + l++, n--; + } + + return l; +} + +int strv_extend_n(char ***l, const char *value, size_t n) { + size_t i, j, k; + char **nl; + + assert(l); + + if (!value) + return 0; + if (n == 0) + return 0; + + /* Adds the value value n times to l */ + + k = strv_length(*l); + + nl = realloc(*l, sizeof(char*) * (k + n + 1)); + if (!nl) + return -ENOMEM; + + *l = nl; + + for (i = k; i < k + n; i++) { + nl[i] = strdup(value); + if (!nl[i]) + goto rollback; + } + + nl[i] = NULL; + return 0; + +rollback: + for (j = k; j < i; j++) + free(nl[j]); + + nl[k] = NULL; + return -ENOMEM; +} diff --git a/src/basic/strv.h b/src/basic/strv.h index f07da8cdf3..e66794fc34 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -21,10 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fnmatch.h> #include <stdarg.h> #include <stdbool.h> -#include <fnmatch.h> +#include "extract-word.h" #include "util.h" char *strv_find(char **l, const char *name) _pure_; @@ -35,12 +36,16 @@ char **strv_free(char **l); DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); #define _cleanup_strv_free_ _cleanup_(strv_freep) +char **strv_free_erase(char **l); +DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); +#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep) + void strv_clear(char **l); char **strv_copy(char * const *l); unsigned strv_length(char * const *l) _pure_; -int strv_extend_strv(char ***a, char **b); +int strv_extend_strv(char ***a, char **b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char **b, const char *suffix); int strv_extend(char ***l, const char *value); int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); @@ -80,6 +85,7 @@ char *strv_join_quoted(char **l); char **strv_parse_nulstr(const char *s, size_t l); char **strv_split_nulstr(const char *s); +int strv_make_nulstr(char **l, char **p, size_t *n); bool strv_overlap(char **a, char **b) _pure_; @@ -154,3 +160,9 @@ static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, i return strv_isempty(patterns) || strv_fnmatch(patterns, s, flags); } + +char ***strv_free_free(char ***l); + +char **strv_skip(char **l, size_t n); + +int strv_extend_n(char ***l, const char *value, size_t n); diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c new file mode 100644 index 0000000000..01577941a0 --- /dev/null +++ b/src/basic/syslog-util.c @@ -0,0 +1,115 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <syslog.h> + +#include "assert.h" +#include "hexdecoct.h" +#include "string-table.h" +#include "syslog-util.h" + +int syslog_parse_priority(const char **p, int *priority, bool with_facility) { + int a = 0, b = 0, c = 0; + int k; + + assert(p); + assert(*p); + assert(priority); + + if ((*p)[0] != '<') + return 0; + + if (!strchr(*p, '>')) + return 0; + + if ((*p)[2] == '>') { + c = undecchar((*p)[1]); + k = 3; + } else if ((*p)[3] == '>') { + b = undecchar((*p)[1]); + c = undecchar((*p)[2]); + k = 4; + } else if ((*p)[4] == '>') { + a = undecchar((*p)[1]); + b = undecchar((*p)[2]); + c = undecchar((*p)[3]); + k = 5; + } else + return 0; + + if (a < 0 || b < 0 || c < 0 || + (!with_facility && (a || b || c > 7))) + return 0; + + if (with_facility) + *priority = a*100 + b*10 + c; + else + *priority = (*priority & LOG_FACMASK) | c; + + *p += k; + return 1; +} + +static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { + [LOG_FAC(LOG_KERN)] = "kern", + [LOG_FAC(LOG_USER)] = "user", + [LOG_FAC(LOG_MAIL)] = "mail", + [LOG_FAC(LOG_DAEMON)] = "daemon", + [LOG_FAC(LOG_AUTH)] = "auth", + [LOG_FAC(LOG_SYSLOG)] = "syslog", + [LOG_FAC(LOG_LPR)] = "lpr", + [LOG_FAC(LOG_NEWS)] = "news", + [LOG_FAC(LOG_UUCP)] = "uucp", + [LOG_FAC(LOG_CRON)] = "cron", + [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", + [LOG_FAC(LOG_FTP)] = "ftp", + [LOG_FAC(LOG_LOCAL0)] = "local0", + [LOG_FAC(LOG_LOCAL1)] = "local1", + [LOG_FAC(LOG_LOCAL2)] = "local2", + [LOG_FAC(LOG_LOCAL3)] = "local3", + [LOG_FAC(LOG_LOCAL4)] = "local4", + [LOG_FAC(LOG_LOCAL5)] = "local5", + [LOG_FAC(LOG_LOCAL6)] = "local6", + [LOG_FAC(LOG_LOCAL7)] = "local7" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); + +bool log_facility_unshifted_is_valid(int facility) { + return facility >= 0 && facility <= LOG_FAC(~0); +} + +static const char *const log_level_table[] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug" +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); + +bool log_level_is_valid(int level) { + return level >= 0 && level <= LOG_DEBUG; +} diff --git a/src/basic/syslog-util.h b/src/basic/syslog-util.h new file mode 100644 index 0000000000..eb79c6dbd8 --- /dev/null +++ b/src/basic/syslog-util.h @@ -0,0 +1,34 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +int log_facility_unshifted_to_string_alloc(int i, char **s); +int log_facility_unshifted_from_string(const char *s); +bool log_facility_unshifted_is_valid(int faciliy); + +int log_level_to_string_alloc(int i, char **s); +int log_level_from_string(const char *s); +bool log_level_is_valid(int level); + +int syslog_parse_priority(const char **p, int *priority, bool with_facility); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index dd3d525854..3931b03bc2 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -17,26 +17,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <assert.h> +#include <fcntl.h> +#include <linux/kd.h> +#include <linux/tiocl.h> +#include <linux/vt.h> +#include <poll.h> +#include <signal.h> #include <sys/ioctl.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include <termios.h> -#include <unistd.h> -#include <fcntl.h> -#include <signal.h> #include <time.h> -#include <assert.h> -#include <poll.h> -#include <linux/vt.h> -#include <linux/tiocl.h> -#include <linux/kd.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "process-util.h" +#include "socket-util.h" +#include "stat-util.h" +#include "string-util.h" #include "terminal-util.h" #include "time-util.h" -#include "process-util.h" #include "util.h" -#include "fileio.h" -#include "path-util.h" static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; @@ -48,7 +56,7 @@ int chvt(int vt) { if (fd < 0) return -errno; - if (vt < 0) { + if (vt <= 0) { int tiocl[2] = { TIOCL_GETKMSGREDIRECT, 0 @@ -412,7 +420,7 @@ int acquire_terminal( assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); - /* Sometimes it makes sense to ignore TIOCSCTTY + /* Sometimes, it makes sense to ignore TIOCSCTTY * returning EPERM, i.e. when very likely we already * are have this controlling terminal. */ if (r < 0 && r == -EPERM && ignore_tiocstty_eperm) @@ -480,10 +488,6 @@ int acquire_terminal( safe_close(notify); - r = reset_terminal_fd(fd, true); - if (r < 0) - log_warning_errno(r, "Failed to reset terminal: %m"); - return fd; fail: @@ -539,8 +543,9 @@ int terminal_vhangup(const char *name) { } int vt_disallocate(const char *name) { - int fd, r; + _cleanup_close_ int fd = -1; unsigned u; + int r; /* Deallocate the VT if possible. If not possible * (i.e. because it is the active one), at least clear it @@ -562,8 +567,6 @@ int vt_disallocate(const char *name) { "\033[H" /* move home */ "\033[2J", /* clear screen */ 10, false); - safe_close(fd); - return 0; } @@ -583,7 +586,7 @@ int vt_disallocate(const char *name) { return fd; r = ioctl(fd, VT_DISALLOCATE, u); - safe_close(fd); + fd = safe_close(fd); if (r >= 0) return 0; @@ -602,32 +605,9 @@ int vt_disallocate(const char *name) { "\033[H" /* move home */ "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */ 10, false); - safe_close(fd); - return 0; } -void warn_melody(void) { - _cleanup_close_ int fd = -1; - - fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return; - - /* Yeah, this is synchronous. Kinda sucks. But well... */ - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/440)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - (void) ioctl(fd, KIOCSOUND, 0); -} - int make_console_stdio(void) { int fd, r; @@ -637,6 +617,10 @@ int make_console_stdio(void) { if (fd < 0) return log_error_errno(fd, "Failed to acquire terminal: %m"); + r = reset_terminal_fd(fd, true); + if (r < 0) + log_warning_errno(r, "Failed to reset terminal, ignoring: %m"); + r = make_stdio(fd); if (r < 0) return log_error_errno(r, "Failed to duplicate terminal fd: %m"); @@ -644,84 +628,6 @@ int make_console_stdio(void) { return 0; } -int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { - static const char status_indent[] = " "; /* "[" STATUS "] " */ - _cleanup_free_ char *s = NULL; - _cleanup_close_ int fd = -1; - struct iovec iovec[6] = {}; - int n = 0; - static bool prev_ephemeral; - - assert(format); - - /* This is independent of logging, as status messages are - * optional and go exclusively to the console. */ - - if (vasprintf(&s, format, ap) < 0) - return log_oom(); - - fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - if (ellipse) { - char *e; - size_t emax, sl; - int c; - - c = fd_columns(fd); - if (c <= 0) - c = 80; - - sl = status ? sizeof(status_indent)-1 : 0; - - emax = c - sl - 1; - if (emax < 3) - emax = 3; - - e = ellipsize(s, emax, 50); - if (e) { - free(s); - s = e; - } - } - - if (prev_ephemeral) - IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); - prev_ephemeral = ephemeral; - - if (status) { - if (!isempty(status)) { - IOVEC_SET_STRING(iovec[n++], "["); - IOVEC_SET_STRING(iovec[n++], status); - IOVEC_SET_STRING(iovec[n++], "] "); - } else - IOVEC_SET_STRING(iovec[n++], status_indent); - } - - IOVEC_SET_STRING(iovec[n++], s); - if (!ephemeral) - IOVEC_SET_STRING(iovec[n++], "\n"); - - if (writev(fd, iovec, n) < 0) - return -errno; - - return 0; -} - -int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) { - va_list ap; - int r; - - assert(format); - - va_start(ap, format); - r = status_vprintf(status, ellipse, ephemeral, format, ap); - va_end(ap); - - return r; -} - bool tty_is_vc(const char *tty) { assert(tty); @@ -1075,6 +981,33 @@ int get_ctty(pid_t pid, dev_t *_devnr, char **r) { return 0; } +int ptsname_malloc(int fd, char **ret) { + size_t l = 100; + + assert(fd >= 0); + assert(ret); + + for (;;) { + char *c; + + c = new(char, l); + if (!c) + return -ENOMEM; + + if (ptsname_r(fd, c, l) == 0) { + *ret = c; + return 0; + } + if (errno != ERANGE) { + free(c); + return -errno; + } + + free(c); + l *= 2; + } +} + int ptsname_namespace(int pty, char **ret) { int no = -1, r; @@ -1093,3 +1026,104 @@ int ptsname_namespace(int pty, char **ret) { return 0; } + +int openpt_in_namespace(pid_t pid, int flags) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + int r; + + assert(pid > 0); + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC); + if (master < 0) + _exit(EXIT_FAILURE); + + if (unlockpt(master) < 0) + _exit(EXIT_FAILURE); + + if (send_one_fd(pair[1], master, 0) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + return receive_one_fd(pair[0], 0); +} + +int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + siginfo_t si; + pid_t child; + int r; + + r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); + if (r < 0) + return r; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return -errno; + + if (child == 0) { + int master; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); + if (r < 0) + _exit(EXIT_FAILURE); + + master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC); + if (master < 0) + _exit(EXIT_FAILURE); + + if (send_one_fd(pair[1], master, 0) < 0) + _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); + } + + pair[1] = safe_close(pair[1]); + + r = wait_for_terminate(child, &si); + if (r < 0) + return r; + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return -EIO; + + return receive_one_fd(pair[0], 0); +} diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index a9e325ccb3..f2185c1c11 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -67,15 +67,10 @@ bool tty_is_console(const char *tty) _pure_; int vtnr_from_tty(const char *tty); const char *default_term_for_tty(const char *tty); -void warn_melody(void); - int make_stdio(int fd); int make_null_stdio(void); int make_console_stdio(void); -int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); -int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); - int fd_columns(int fd); unsigned columns(void); int fd_lines(int fd); @@ -122,4 +117,8 @@ int get_ctty(pid_t, dev_t *_devnr, char **r); int getttyname_malloc(int fd, char **r); int getttyname_harder(int fd, char **r); +int ptsname_malloc(int fd, char **ret); int ptsname_namespace(int pty, char **ret); + +int openpt_in_namespace(pid_t pid, int flags); +int open_terminal_in_namespace(pid_t pid, const char *name, int mode); diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 531931f6e1..e629d91cb2 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -19,15 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <time.h> #include <string.h> -#include <sys/timex.h> #include <sys/timerfd.h> +#include <sys/timex.h> -#include "util.h" -#include "time-util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" +#include "time-util.h" +#include "util.h" usec_t now(clockid_t clock_id) { struct timespec ts; @@ -205,11 +209,8 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) return NULL; sec = (time_t) (t / USEC_PER_SEC); + localtime_or_gmtime_r(&sec, &tm, utc); - if (utc) - gmtime_r(&sec, &tm); - else - localtime_r(&sec, &tm); if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) return NULL; @@ -235,10 +236,7 @@ static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool ut return NULL; sec = (time_t) (t / USEC_PER_SEC); - if (utc) - gmtime_r(&sec, &tm); - else - localtime_r(&sec, &tm); + localtime_or_gmtime_r(&sec, &tm, utc); if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) return NULL; @@ -484,9 +482,10 @@ int parse_timestamp(const char *t, usec_t *usec) { }; const char *k; + const char *utc; struct tm tm, copy; time_t x; - usec_t plus = 0, minus = 0, ret; + usec_t x_usec, plus = 0, minus = 0, ret; int r, weekday = -1; unsigned i; @@ -511,28 +510,15 @@ int parse_timestamp(const char *t, usec_t *usec) { assert(t); assert(usec); - x = time(NULL); - assert_se(localtime_r(&x, &tm)); - tm.tm_isdst = -1; - - if (streq(t, "now")) - goto finish; - - else if (streq(t, "today")) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + if (t[0] == '@') + return parse_sec(t + 1, usec); - } else if (streq(t, "yesterday")) { - tm.tm_mday --; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + ret = now(CLOCK_REALTIME); - } else if (streq(t, "tomorrow")) { - tm.tm_mday ++; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + if (streq(t, "now")) goto finish; - } else if (t[0] == '+') { + else if (t[0] == '+') { r = parse_sec(t+1, &plus); if (r < 0) return r; @@ -546,35 +532,51 @@ int parse_timestamp(const char *t, usec_t *usec) { goto finish; - } else if (t[0] == '@') - return parse_sec(t + 1, usec); - - else if (endswith(t, " ago")) { - _cleanup_free_ char *z; + } else if ((k = endswith(t, " ago"))) { + t = strndupa(t, k - t); - z = strndup(t, strlen(t) - 4); - if (!z) - return -ENOMEM; - - r = parse_sec(z, &minus); + r = parse_sec(t, &minus); if (r < 0) return r; goto finish; - } else if (endswith(t, " left")) { - _cleanup_free_ char *z; - z = strndup(t, strlen(t) - 4); - if (!z) - return -ENOMEM; + } else if ((k = endswith(t, " left"))) { + t = strndupa(t, k - t); - r = parse_sec(z, &plus); + r = parse_sec(t, &plus); if (r < 0) return r; goto finish; } + utc = endswith_no_case(t, " UTC"); + if (utc) + t = strndupa(t, utc - t); + + x = ret / USEC_PER_SEC; + x_usec = 0; + + assert_se(localtime_or_gmtime_r(&x, &tm, utc)); + tm.tm_isdst = -1; + + if (streq(t, "today")) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + + } else if (streq(t, "yesterday")) { + tm.tm_mday --; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + + } else if (streq(t, "tomorrow")) { + tm.tm_mday ++; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + } + + for (i = 0; i < ELEMENTSOF(day_nr); i++) { size_t skip; @@ -592,66 +594,106 @@ int parse_timestamp(const char *t, usec_t *usec) { copy = tm; k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } tm = copy; k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } tm = copy; k = strptime(t, "%y-%m-%d %H:%M", &tm); if (k && *k == 0) { tm.tm_sec = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%Y-%m-%d %H:%M", &tm); if (k && *k == 0) { tm.tm_sec = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%y-%m-%d", &tm); if (k && *k == 0) { tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%Y-%m-%d", &tm); if (k && *k == 0) { tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; + goto from_tm; } tm = copy; k = strptime(t, "%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } tm = copy; k = strptime(t, "%H:%M", &tm); if (k && *k == 0) { tm.tm_sec = 0; - goto finish; + goto from_tm; } return -EINVAL; -finish: - x = mktime(&tm); +parse_usec: + { + char *end; + unsigned long long val; + size_t l; + + k++; + if (*k < '0' || *k > '9') + return -EINVAL; + + /* base 10 instead of base 0, .09 is not base 8 */ + errno = 0; + val = strtoull(k, &end, 10); + if (*end || errno) + return -EINVAL; + + l = end-k; + + /* val has l digits, make them 6 */ + for (; l < 6; l++) + val *= 10; + for (; l > 6; l--) + val /= 10; + + x_usec = val; + } + +from_tm: + x = mktime_or_timegm(&tm, utc); if (x == (time_t) -1) return -EINVAL; if (weekday >= 0 && tm.tm_wday != weekday) return -EINVAL; - ret = (usec_t) x * USEC_PER_SEC; + ret = (usec_t) x * USEC_PER_SEC + x_usec; +finish: ret += plus; if (ret > minus) ret -= minus; @@ -1072,3 +1114,25 @@ int get_timezone(char **tz) { *tz = z; return 0; } + +time_t mktime_or_timegm(struct tm *tm, bool utc) { + return utc ? timegm(tm) : mktime(tm); +} + +struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) { + return utc ? gmtime_r(t, tm) : localtime_r(t, tm); +} + +unsigned long usec_to_jiffies(usec_t u) { + static thread_local unsigned long hz = 0; + long r; + + if (hz == 0) { + r = sysconf(_SC_CLK_TCK); + + assert(r > 0); + hz = (unsigned long) r; + } + + return DIV_ROUND_UP(u , USEC_PER_SEC / hz); +} diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 1af01541fc..925bf18eb2 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -21,8 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <inttypes.h> +#include <stdio.h> +#include <time.h> typedef uint64_t usec_t; typedef uint64_t nsec_t; @@ -117,3 +118,8 @@ clockid_t clock_boottime_or_monotonic(void); "xstrftime: " #buf "[] must be big enough") int get_timezone(char **timezone); + +time_t mktime_or_timegm(struct tm *tm, bool utc); +struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); + +unsigned long usec_to_jiffies(usec_t usec); diff --git a/src/basic/umask-util.h b/src/basic/umask-util.h new file mode 100644 index 0000000000..8ed34658b4 --- /dev/null +++ b/src/basic/umask-util.h @@ -0,0 +1,48 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "macro.h" + +static inline void umaskp(mode_t *u) { + umask(*u); +} + +#define _cleanup_umask_ _cleanup_(umaskp) + +struct _umask_struct_ { + mode_t mask; + bool quit; +}; + +static inline void _reset_umask_(struct _umask_struct_ *s) { + umask(s->mask); +}; + +#define RUN_WITH_UMASK(mask) \ + for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ + !_saved_umask_.quit ; \ + _saved_umask_.quit = true) diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 8742ee757f..710421508c 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -22,12 +22,16 @@ #include <errno.h> #include <string.h> -#include "path-util.h" +#include "alloc-util.h" #include "bus-label.h" -#include "util.h" -#include "unit-name.h" #include "def.h" +#include "hexdecoct.h" +#include "path-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" +#include "unit-name.h" +#include "util.h" #define VALID_CHARS \ DIGITS LETTERS \ @@ -651,7 +655,7 @@ static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t * /blah/blah is converted to blah-blah.mount, anything else is left alone, * except that @suffix is appended if a valid unit suffix is not present. * - * If @allow_globs, globs characters are preserved. Otherwise they are escaped. + * If @allow_globs, globs characters are preserved. Otherwise, they are escaped. */ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, const char *suffix, char **ret) { char *s, *t; @@ -839,6 +843,170 @@ static const char* const unit_load_state_table[_UNIT_LOAD_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(unit_load_state, UnitLoadState); +static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { + [UNIT_ACTIVE] = "active", + [UNIT_RELOADING] = "reloading", + [UNIT_INACTIVE] = "inactive", + [UNIT_FAILED] = "failed", + [UNIT_ACTIVATING] = "activating", + [UNIT_DEACTIVATING] = "deactivating" +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); + +static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { + [AUTOMOUNT_DEAD] = "dead", + [AUTOMOUNT_WAITING] = "waiting", + [AUTOMOUNT_RUNNING] = "running", + [AUTOMOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); + +static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { + [BUSNAME_DEAD] = "dead", + [BUSNAME_MAKING] = "making", + [BUSNAME_REGISTERED] = "registered", + [BUSNAME_LISTENING] = "listening", + [BUSNAME_RUNNING] = "running", + [BUSNAME_SIGTERM] = "sigterm", + [BUSNAME_SIGKILL] = "sigkill", + [BUSNAME_FAILED] = "failed", +}; + +DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); + +static const char* const device_state_table[_DEVICE_STATE_MAX] = { + [DEVICE_DEAD] = "dead", + [DEVICE_TENTATIVE] = "tentative", + [DEVICE_PLUGGED] = "plugged", +}; + +DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); + +static const char* const mount_state_table[_MOUNT_STATE_MAX] = { + [MOUNT_DEAD] = "dead", + [MOUNT_MOUNTING] = "mounting", + [MOUNT_MOUNTING_DONE] = "mounting-done", + [MOUNT_MOUNTED] = "mounted", + [MOUNT_REMOUNTING] = "remounting", + [MOUNT_UNMOUNTING] = "unmounting", + [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm", + [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill", + [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", + [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", + [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", + [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", + [MOUNT_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); + +static const char* const path_state_table[_PATH_STATE_MAX] = { + [PATH_DEAD] = "dead", + [PATH_WAITING] = "waiting", + [PATH_RUNNING] = "running", + [PATH_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); + +static const char* const scope_state_table[_SCOPE_STATE_MAX] = { + [SCOPE_DEAD] = "dead", + [SCOPE_RUNNING] = "running", + [SCOPE_ABANDONED] = "abandoned", + [SCOPE_STOP_SIGTERM] = "stop-sigterm", + [SCOPE_STOP_SIGKILL] = "stop-sigkill", + [SCOPE_FAILED] = "failed", +}; + +DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState); + +static const char* const service_state_table[_SERVICE_STATE_MAX] = { + [SERVICE_DEAD] = "dead", + [SERVICE_START_PRE] = "start-pre", + [SERVICE_START] = "start", + [SERVICE_START_POST] = "start-post", + [SERVICE_RUNNING] = "running", + [SERVICE_EXITED] = "exited", + [SERVICE_RELOAD] = "reload", + [SERVICE_STOP] = "stop", + [SERVICE_STOP_SIGABRT] = "stop-sigabrt", + [SERVICE_STOP_SIGTERM] = "stop-sigterm", + [SERVICE_STOP_SIGKILL] = "stop-sigkill", + [SERVICE_STOP_POST] = "stop-post", + [SERVICE_FINAL_SIGTERM] = "final-sigterm", + [SERVICE_FINAL_SIGKILL] = "final-sigkill", + [SERVICE_FAILED] = "failed", + [SERVICE_AUTO_RESTART] = "auto-restart", +}; + +DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); + +static const char* const slice_state_table[_SLICE_STATE_MAX] = { + [SLICE_DEAD] = "dead", + [SLICE_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); + +static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { + [SNAPSHOT_DEAD] = "dead", + [SNAPSHOT_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); + +static const char* const socket_state_table[_SOCKET_STATE_MAX] = { + [SOCKET_DEAD] = "dead", + [SOCKET_START_PRE] = "start-pre", + [SOCKET_START_CHOWN] = "start-chown", + [SOCKET_START_POST] = "start-post", + [SOCKET_LISTENING] = "listening", + [SOCKET_RUNNING] = "running", + [SOCKET_STOP_PRE] = "stop-pre", + [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", + [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", + [SOCKET_STOP_POST] = "stop-post", + [SOCKET_FINAL_SIGTERM] = "final-sigterm", + [SOCKET_FINAL_SIGKILL] = "final-sigkill", + [SOCKET_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + +static const char* const swap_state_table[_SWAP_STATE_MAX] = { + [SWAP_DEAD] = "dead", + [SWAP_ACTIVATING] = "activating", + [SWAP_ACTIVATING_DONE] = "activating-done", + [SWAP_ACTIVE] = "active", + [SWAP_DEACTIVATING] = "deactivating", + [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", + [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", + [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", + [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", + [SWAP_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); + +static const char* const target_state_table[_TARGET_STATE_MAX] = { + [TARGET_DEAD] = "dead", + [TARGET_ACTIVE] = "active" +}; + +DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); + +static const char* const timer_state_table[_TIMER_STATE_MAX] = { + [TIMER_DEAD] = "dead", + [TIMER_WAITING] = "waiting", + [TIMER_RUNNING] = "running", + [TIMER_ELAPSED] = "elapsed", + [TIMER_FAILED] = "failed" +}; + +DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); + static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = { [UNIT_REQUIRES] = "Requires", [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable", diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index 28b3a555f3..65b55d9554 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -27,11 +27,7 @@ #define UNIT_NAME_MAX 256 -typedef enum UnitType UnitType; -typedef enum UnitLoadState UnitLoadState; -typedef enum UnitDependency UnitDependency; - -enum UnitType { +typedef enum UnitType { UNIT_SERVICE = 0, UNIT_SOCKET, UNIT_BUSNAME, @@ -47,9 +43,9 @@ enum UnitType { UNIT_SCOPE, _UNIT_TYPE_MAX, _UNIT_TYPE_INVALID = -1 -}; +} UnitType; -enum UnitLoadState { +typedef enum UnitLoadState { UNIT_STUB = 0, UNIT_LOADED, UNIT_NOT_FOUND, @@ -58,9 +54,176 @@ enum UnitLoadState { UNIT_MASKED, _UNIT_LOAD_STATE_MAX, _UNIT_LOAD_STATE_INVALID = -1 -}; - -enum UnitDependency { +} UnitLoadState; + +typedef enum UnitActiveState { + UNIT_ACTIVE, + UNIT_RELOADING, + UNIT_INACTIVE, + UNIT_FAILED, + UNIT_ACTIVATING, + UNIT_DEACTIVATING, + _UNIT_ACTIVE_STATE_MAX, + _UNIT_ACTIVE_STATE_INVALID = -1 +} UnitActiveState; + +typedef enum AutomountState { + AUTOMOUNT_DEAD, + AUTOMOUNT_WAITING, + AUTOMOUNT_RUNNING, + AUTOMOUNT_FAILED, + _AUTOMOUNT_STATE_MAX, + _AUTOMOUNT_STATE_INVALID = -1 +} AutomountState; + +typedef enum BusNameState { + BUSNAME_DEAD, + BUSNAME_MAKING, + BUSNAME_REGISTERED, + BUSNAME_LISTENING, + BUSNAME_RUNNING, + BUSNAME_SIGTERM, + BUSNAME_SIGKILL, + BUSNAME_FAILED, + _BUSNAME_STATE_MAX, + _BUSNAME_STATE_INVALID = -1 +} BusNameState; + +/* We simply watch devices, we cannot plug/unplug them. That + * simplifies the state engine greatly */ +typedef enum DeviceState { + DEVICE_DEAD, + DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ + DEVICE_PLUGGED, /* announced by udev */ + _DEVICE_STATE_MAX, + _DEVICE_STATE_INVALID = -1 +} DeviceState; + +typedef enum MountState { + MOUNT_DEAD, + MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */ + MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */ + MOUNT_MOUNTED, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, + MOUNT_MOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_FAILED, + _MOUNT_STATE_MAX, + _MOUNT_STATE_INVALID = -1 +} MountState; + +typedef enum PathState { + PATH_DEAD, + PATH_WAITING, + PATH_RUNNING, + PATH_FAILED, + _PATH_STATE_MAX, + _PATH_STATE_INVALID = -1 +} PathState; + +typedef enum ScopeState { + SCOPE_DEAD, + SCOPE_RUNNING, + SCOPE_ABANDONED, + SCOPE_STOP_SIGTERM, + SCOPE_STOP_SIGKILL, + SCOPE_FAILED, + _SCOPE_STATE_MAX, + _SCOPE_STATE_INVALID = -1 +} ScopeState; + +typedef enum ServiceState { + SERVICE_DEAD, + SERVICE_START_PRE, + SERVICE_START, + SERVICE_START_POST, + SERVICE_RUNNING, + SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ + SERVICE_RELOAD, + SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ + SERVICE_STOP_SIGABRT, /* Watchdog timeout */ + SERVICE_STOP_SIGTERM, + SERVICE_STOP_SIGKILL, + SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ + SERVICE_FINAL_SIGKILL, + SERVICE_FAILED, + SERVICE_AUTO_RESTART, + _SERVICE_STATE_MAX, + _SERVICE_STATE_INVALID = -1 +} ServiceState; + +typedef enum SliceState { + SLICE_DEAD, + SLICE_ACTIVE, + _SLICE_STATE_MAX, + _SLICE_STATE_INVALID = -1 +} SliceState; + +typedef enum SnapshotState { + SNAPSHOT_DEAD, + SNAPSHOT_ACTIVE, + _SNAPSHOT_STATE_MAX, + _SNAPSHOT_STATE_INVALID = -1 +} SnapshotState; + +typedef enum SocketState { + SOCKET_DEAD, + SOCKET_START_PRE, + SOCKET_START_CHOWN, + SOCKET_START_POST, + SOCKET_LISTENING, + SOCKET_RUNNING, + SOCKET_STOP_PRE, + SOCKET_STOP_PRE_SIGTERM, + SOCKET_STOP_PRE_SIGKILL, + SOCKET_STOP_POST, + SOCKET_FINAL_SIGTERM, + SOCKET_FINAL_SIGKILL, + SOCKET_FAILED, + _SOCKET_STATE_MAX, + _SOCKET_STATE_INVALID = -1 +} SocketState; + +typedef enum SwapState { + SWAP_DEAD, + SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */ + SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ + SWAP_ACTIVE, + SWAP_DEACTIVATING, + SWAP_ACTIVATING_SIGTERM, + SWAP_ACTIVATING_SIGKILL, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL, + SWAP_FAILED, + _SWAP_STATE_MAX, + _SWAP_STATE_INVALID = -1 +} SwapState; + + +typedef enum TargetState { + TARGET_DEAD, + TARGET_ACTIVE, + _TARGET_STATE_MAX, + _TARGET_STATE_INVALID = -1 +} TargetState; + +typedef enum TimerState { + TIMER_DEAD, + TIMER_WAITING, + TIMER_RUNNING, + TIMER_ELAPSED, + TIMER_FAILED, + _TIMER_STATE_MAX, + _TIMER_STATE_INVALID = -1 +} TimerState; + +typedef enum UnitDependency { /* Positive dependencies */ UNIT_REQUIRES, UNIT_REQUIRES_OVERRIDABLE, @@ -107,7 +270,7 @@ enum UnitDependency { _UNIT_DEPENDENCY_MAX, _UNIT_DEPENDENCY_INVALID = -1 -}; +} UnitDependency; typedef enum UnitNameFlags { UNIT_NAME_PLAIN = 1, /* Allow foo.service */ @@ -176,5 +339,47 @@ UnitType unit_type_from_string(const char *s) _pure_; const char *unit_load_state_to_string(UnitLoadState i) _const_; UnitLoadState unit_load_state_from_string(const char *s) _pure_; +const char *unit_active_state_to_string(UnitActiveState i) _const_; +UnitActiveState unit_active_state_from_string(const char *s) _pure_; + +const char* automount_state_to_string(AutomountState i) _const_; +AutomountState automount_state_from_string(const char *s) _pure_; + +const char* busname_state_to_string(BusNameState i) _const_; +BusNameState busname_state_from_string(const char *s) _pure_; + +const char* device_state_to_string(DeviceState i) _const_; +DeviceState device_state_from_string(const char *s) _pure_; + +const char* mount_state_to_string(MountState i) _const_; +MountState mount_state_from_string(const char *s) _pure_; + +const char* path_state_to_string(PathState i) _const_; +PathState path_state_from_string(const char *s) _pure_; + +const char* scope_state_to_string(ScopeState i) _const_; +ScopeState scope_state_from_string(const char *s) _pure_; + +const char* service_state_to_string(ServiceState i) _const_; +ServiceState service_state_from_string(const char *s) _pure_; + +const char* slice_state_to_string(SliceState i) _const_; +SliceState slice_state_from_string(const char *s) _pure_; + +const char* snapshot_state_to_string(SnapshotState i) _const_; +SnapshotState snapshot_state_from_string(const char *s) _pure_; + +const char* socket_state_to_string(SocketState i) _const_; +SocketState socket_state_from_string(const char *s) _pure_; + +const char* swap_state_to_string(SwapState i) _const_; +SwapState swap_state_from_string(const char *s) _pure_; + +const char* target_state_to_string(TargetState i) _const_; +TargetState target_state_from_string(const char *s) _pure_; + +const char *timer_state_to_string(TimerState i) _const_; +TimerState timer_state_from_string(const char *s) _pure_; + const char *unit_dependency_to_string(UnitDependency i) _const_; UnitDependency unit_dependency_from_string(const char *s) _pure_; diff --git a/src/basic/user-util.c b/src/basic/user-util.c new file mode 100644 index 0000000000..d6c936db37 --- /dev/null +++ b/src/basic/user-util.c @@ -0,0 +1,472 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <pwd.h> +#include <grp.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" + +bool uid_is_valid(uid_t uid) { + + /* Some libc APIs use UID_INVALID as special placeholder */ + if (uid == (uid_t) UINT32_C(0xFFFFFFFF)) + return false; + + /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ + if (uid == (uid_t) UINT32_C(0xFFFF)) + return false; + + return true; +} + +int parse_uid(const char *s, uid_t *ret) { + uint32_t uid = 0; + int r; + + assert(s); + + assert_cc(sizeof(uid_t) == sizeof(uint32_t)); + r = safe_atou32(s, &uid); + if (r < 0) + return r; + + if (!uid_is_valid(uid)) + return -ENXIO; /* we return ENXIO instead of EINVAL + * here, to make it easy to distuingish + * invalid numeric uids invalid + * strings. */ + + if (ret) + *ret = uid; + + return 0; +} + +char* getlogname_malloc(void) { + uid_t uid; + struct stat st; + + if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) + uid = st.st_uid; + else + uid = getuid(); + + return uid_to_name(uid); +} + +char *getusername_malloc(void) { + const char *e; + + e = getenv("USER"); + if (e) + return strdup(e); + + return uid_to_name(getuid()); +} + +int get_user_creds( + const char **username, + uid_t *uid, gid_t *gid, + const char **home, + const char **shell) { + + struct passwd *p; + uid_t u; + + assert(username); + assert(*username); + + /* We enforce some special rules for uid=0: in order to avoid + * NSS lookups for root we hardcode its data. */ + + if (streq(*username, "root") || streq(*username, "0")) { + *username = "root"; + + if (uid) + *uid = 0; + + if (gid) + *gid = 0; + + if (home) + *home = "/root"; + + if (shell) + *shell = "/bin/sh"; + + return 0; + } + + if (parse_uid(*username, &u) >= 0) { + errno = 0; + p = getpwuid(u); + + /* If there are multiple users with the same id, make + * sure to leave $USER to the configured value instead + * of the first occurrence in the database. However if + * the uid was configured by a numeric uid, then let's + * pick the real username from /etc/passwd. */ + if (p) + *username = p->pw_name; + } else { + errno = 0; + p = getpwnam(*username); + } + + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (uid) { + if (!uid_is_valid(p->pw_uid)) + return -EBADMSG; + + *uid = p->pw_uid; + } + + if (gid) { + if (!gid_is_valid(p->pw_gid)) + return -EBADMSG; + + *gid = p->pw_gid; + } + + if (home) + *home = p->pw_dir; + + if (shell) + *shell = p->pw_shell; + + return 0; +} + +int get_group_creds(const char **groupname, gid_t *gid) { + struct group *g; + gid_t id; + + assert(groupname); + + /* We enforce some special rules for gid=0: in order to avoid + * NSS lookups for root we hardcode its data. */ + + if (streq(*groupname, "root") || streq(*groupname, "0")) { + *groupname = "root"; + + if (gid) + *gid = 0; + + return 0; + } + + if (parse_gid(*groupname, &id) >= 0) { + errno = 0; + g = getgrgid(id); + + if (g) + *groupname = g->gr_name; + } else { + errno = 0; + g = getgrnam(*groupname); + } + + if (!g) + return errno > 0 ? -errno : -ESRCH; + + if (gid) { + if (!gid_is_valid(g->gr_gid)) + return -EBADMSG; + + *gid = g->gr_gid; + } + + return 0; +} + +char* uid_to_name(uid_t uid) { + char *ret; + int r; + + /* Shortcut things to avoid NSS lookups */ + if (uid == 0) + return strdup("root"); + + if (uid_is_valid(uid)) { + long bufsize; + + bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); + if (bufsize <= 0) + bufsize = 4096; + + for (;;) { + struct passwd pwbuf, *pw = NULL; + _cleanup_free_ char *buf = NULL; + + buf = malloc(bufsize); + if (!buf) + return NULL; + + r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw); + if (r == 0 && pw) + return strdup(pw->pw_name); + if (r != ERANGE) + break; + + bufsize *= 2; + } + } + + if (asprintf(&ret, UID_FMT, uid) < 0) + return NULL; + + return ret; +} + +char* gid_to_name(gid_t gid) { + char *ret; + int r; + + if (gid == 0) + return strdup("root"); + + if (gid_is_valid(gid)) { + long bufsize; + + bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); + if (bufsize <= 0) + bufsize = 4096; + + for (;;) { + struct group grbuf, *gr = NULL; + _cleanup_free_ char *buf = NULL; + + buf = malloc(bufsize); + if (!buf) + return NULL; + + r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr); + if (r == 0 && gr) + return strdup(gr->gr_name); + if (r != ERANGE) + break; + + bufsize *= 2; + } + } + + if (asprintf(&ret, GID_FMT, gid) < 0) + return NULL; + + return ret; +} + +int in_gid(gid_t gid) { + gid_t *gids; + int ngroups_max, r, i; + + if (getgid() == gid) + return 1; + + if (getegid() == gid) + return 1; + + if (!gid_is_valid(gid)) + return -EINVAL; + + ngroups_max = sysconf(_SC_NGROUPS_MAX); + assert(ngroups_max > 0); + + gids = alloca(sizeof(gid_t) * ngroups_max); + + r = getgroups(ngroups_max, gids); + if (r < 0) + return -errno; + + for (i = 0; i < r; i++) + if (gids[i] == gid) + return 1; + + return 0; +} + +int in_group(const char *name) { + int r; + gid_t gid; + + r = get_group_creds(&name, &gid); + if (r < 0) + return r; + + return in_gid(gid); +} + +int get_home_dir(char **_h) { + struct passwd *p; + const char *e; + char *h; + uid_t u; + + assert(_h); + + /* Take the user specified one */ + e = secure_getenv("HOME"); + if (e && path_is_absolute(e)) { + h = strdup(e); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + h = strdup("/root"); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_dir)) + return -EINVAL; + + h = strdup(p->pw_dir); + if (!h) + return -ENOMEM; + + *_h = h; + return 0; +} + +int get_shell(char **_s) { + struct passwd *p; + const char *e; + char *s; + uid_t u; + + assert(_s); + + /* Take the user specified one */ + e = getenv("SHELL"); + if (e) { + s = strdup(e); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Hardcode home directory for root to avoid NSS */ + u = getuid(); + if (u == 0) { + s = strdup("/bin/sh"); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; + } + + /* Check the database... */ + errno = 0; + p = getpwuid(u); + if (!p) + return errno > 0 ? -errno : -ESRCH; + + if (!path_is_absolute(p->pw_shell)) + return -EINVAL; + + s = strdup(p->pw_shell); + if (!s) + return -ENOMEM; + + *_s = s; + return 0; +} + +int reset_uid_gid(void) { + + if (setgroups(0, NULL) < 0) + return -errno; + + if (setresgid(0, 0, 0) < 0) + return -errno; + + if (setresuid(0, 0, 0) < 0) + return -errno; + + return 0; +} + +int take_etc_passwd_lock(const char *root) { + + struct flock flock = { + .l_type = F_WRLCK, + .l_whence = SEEK_SET, + .l_start = 0, + .l_len = 0, + }; + + const char *path; + int fd, r; + + /* This is roughly the same as lckpwdf(), but not as awful. We + * don't want to use alarm() and signals, hence we implement + * our own trivial version of this. + * + * Note that shadow-utils also takes per-database locks in + * addition to lckpwdf(). However, we don't given that they + * are redundant as they they invoke lckpwdf() first and keep + * it during everything they do. The per-database locks are + * awfully racy, and thus we just won't do them. */ + + if (root) + path = prefix_roota(root, "/etc/.pwd.lock"); + else + path = "/etc/.pwd.lock"; + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); + if (fd < 0) + return -errno; + + r = fcntl(fd, F_SETLKW, &flock); + if (r < 0) { + safe_close(fd); + return -errno; + } + + return fd; +} diff --git a/src/basic/user-util.h b/src/basic/user-util.h new file mode 100644 index 0000000000..11ff6674cf --- /dev/null +++ b/src/basic/user-util.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/types.h> +#include <stdbool.h> + +bool uid_is_valid(uid_t uid); + +static inline bool gid_is_valid(gid_t gid) { + return uid_is_valid((uid_t) gid); +} + +int parse_uid(const char *s, uid_t* ret_uid); + +static inline int parse_gid(const char *s, gid_t *ret_gid) { + return parse_uid(s, (uid_t*) ret_gid); +} + +char* getlogname_malloc(void); +char* getusername_malloc(void); + +int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); +int get_group_creds(const char **groupname, gid_t *gid); + +char* uid_to_name(uid_t uid); +char* gid_to_name(gid_t gid); + +int in_gid(gid_t gid); +int in_group(const char *name); + +int get_home_dir(char **ret); +int get_shell(char **_ret); + +int reset_uid_gid(void); + +int take_etc_passwd_lock(const char *root); + +#define UID_INVALID ((uid_t) -1) +#define GID_INVALID ((gid_t) -1) + +/* The following macros add 1 when converting things, since UID 0 is a + * valid UID, while the pointer NULL is special */ +#define PTR_TO_UID(p) ((uid_t) (((uintptr_t) (p))-1)) +#define UID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) + +#define PTR_TO_GID(p) ((gid_t) (((uintptr_t) (p))-1)) +#define GID_TO_PTR(u) ((void*) (((uintptr_t) (u))+1)) diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 800884ffee..7600d99903 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -49,6 +49,8 @@ #include <string.h> #include <stdbool.h> +#include "alloc-util.h" +#include "hexdecoct.h" #include "utf8.h" #include "util.h" diff --git a/src/basic/util.c b/src/basic/util.c index bc61ec0115..08bdcd28f2 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -23,15 +23,14 @@ #include <dirent.h> #include <errno.h> #include <fcntl.h> -#include <glob.h> #include <grp.h> #include <langinfo.h> #include <libintl.h> #include <limits.h> #include <linux/magic.h> +#include <linux/oom.h> #include <linux/sched.h> #include <locale.h> -#include <netinet/ip.h> #include <poll.h> #include <pwd.h> #include <sched.h> @@ -46,7 +45,6 @@ #include <sys/mount.h> #include <sys/personality.h> #include <sys/prctl.h> -#include <sys/resource.h> #include <sys/stat.h> #include <sys/statvfs.h> #include <sys/time.h> @@ -54,7 +52,6 @@ #include <sys/utsname.h> #include <sys/vfs.h> #include <sys/wait.h> -#include <sys/xattr.h> #include <syslog.h> #include <unistd.h> @@ -72,10 +69,14 @@ * otherwise conflicts with sys/mount.h. Yay, Linux is great! */ #include <linux/fs.h> +#include "alloc-util.h" +#include "build.h" #include "def.h" #include "device-nodes.h" #include "env-util.h" +#include "escape.h" #include "exit-status.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "gunicode.h" @@ -86,16 +87,23 @@ #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "hexdecoct.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "random-util.h" #include "signal-util.h" #include "sparse-endian.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" +#include "user-util.h" #include "utf8.h" #include "util.h" #include "virt.h" +#include "dirent-util.h" +#include "stat-util.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -117,2847 +125,6 @@ size_t page_size(void) { return pgsz; } -int strcmp_ptr(const char *a, const char *b) { - - /* Like strcmp(), but tries to make sense of NULL pointers */ - if (a && b) - return strcmp(a, b); - - if (!a && b) - return -1; - - if (a && !b) - return 1; - - return 0; -} - -bool streq_ptr(const char *a, const char *b) { - return strcmp_ptr(a, b) == 0; -} - -char* endswith(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (memcmp(s + sl - pl, postfix, pl) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -char* endswith_no_case(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (strcasecmp(s + sl - pl, postfix) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -char* first_word(const char *s, const char *word) { - size_t sl, wl; - const char *p; - - assert(s); - assert(word); - - /* Checks if the string starts with the specified word, either - * followed by NUL or by whitespace. Returns a pointer to the - * NUL or the first character after the whitespace. */ - - sl = strlen(s); - wl = strlen(word); - - if (sl < wl) - return NULL; - - if (wl == 0) - return (char*) s; - - if (memcmp(s, word, wl) != 0) - return NULL; - - p = s + wl; - if (*p == 0) - return (char*) p; - - if (!strchr(WHITESPACE, *p)) - return NULL; - - p += strspn(p, WHITESPACE); - return (char*) p; -} - -size_t cescape_char(char c, char *buf) { - char * buf_old = buf; - - switch (c) { - - case '\a': - *(buf++) = '\\'; - *(buf++) = 'a'; - break; - case '\b': - *(buf++) = '\\'; - *(buf++) = 'b'; - break; - case '\f': - *(buf++) = '\\'; - *(buf++) = 'f'; - break; - case '\n': - *(buf++) = '\\'; - *(buf++) = 'n'; - break; - case '\r': - *(buf++) = '\\'; - *(buf++) = 'r'; - break; - case '\t': - *(buf++) = '\\'; - *(buf++) = 't'; - break; - case '\v': - *(buf++) = '\\'; - *(buf++) = 'v'; - break; - case '\\': - *(buf++) = '\\'; - *(buf++) = '\\'; - break; - case '"': - *(buf++) = '\\'; - *(buf++) = '"'; - break; - case '\'': - *(buf++) = '\\'; - *(buf++) = '\''; - break; - - default: - /* For special chars we prefer octal over - * hexadecimal encoding, simply because glib's - * g_strescape() does the same */ - if ((c < ' ') || (c >= 127)) { - *(buf++) = '\\'; - *(buf++) = octchar((unsigned char) c >> 6); - *(buf++) = octchar((unsigned char) c >> 3); - *(buf++) = octchar((unsigned char) c); - } else - *(buf++) = c; - break; - } - - return buf - buf_old; -} - -int close_nointr(int fd) { - assert(fd >= 0); - - if (close(fd) >= 0) - return 0; - - /* - * Just ignore EINTR; a retry loop is the wrong thing to do on - * Linux. - * - * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html - * https://bugzilla.gnome.org/show_bug.cgi?id=682819 - * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR - * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain - */ - if (errno == EINTR) - return 0; - - return -errno; -} - -int safe_close(int fd) { - - /* - * Like close_nointr() but cannot fail. Guarantees errno is - * unchanged. Is a NOP with negative fds passed, and returns - * -1, so that it can be used in this syntax: - * - * fd = safe_close(fd); - */ - - if (fd >= 0) { - PROTECT_ERRNO; - - /* The kernel might return pretty much any error code - * via close(), but the fd will be closed anyway. The - * only condition we want to check for here is whether - * the fd was invalid at all... */ - - assert_se(close_nointr(fd) != -EBADF); - } - - return -1; -} - -void close_many(const int fds[], unsigned n_fd) { - unsigned i; - - assert(fds || n_fd <= 0); - - for (i = 0; i < n_fd; i++) - safe_close(fds[i]); -} - -int fclose_nointr(FILE *f) { - assert(f); - - /* Same as close_nointr(), but for fclose() */ - - if (fclose(f) == 0) - return 0; - - if (errno == EINTR) - return 0; - - return -errno; -} - -FILE* safe_fclose(FILE *f) { - - /* Same as safe_close(), but for fclose() */ - - if (f) { - PROTECT_ERRNO; - - assert_se(fclose_nointr(f) != EBADF); - } - - return NULL; -} - -DIR* safe_closedir(DIR *d) { - - if (d) { - PROTECT_ERRNO; - - assert_se(closedir(d) >= 0 || errno != EBADF); - } - - return NULL; -} - -int unlink_noerrno(const char *path) { - PROTECT_ERRNO; - int r; - - r = unlink(path); - if (r < 0) - return -errno; - - return 0; -} - -int parse_boolean(const char *v) { - assert(v); - - if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on")) - return 1; - else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off")) - return 0; - - return -EINVAL; -} - -int parse_pid(const char *s, pid_t* ret_pid) { - unsigned long ul = 0; - pid_t pid; - int r; - - assert(s); - assert(ret_pid); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - pid = (pid_t) ul; - - if ((unsigned long) pid != ul) - return -ERANGE; - - if (pid <= 0) - return -ERANGE; - - *ret_pid = pid; - return 0; -} - -bool uid_is_valid(uid_t uid) { - - /* Some libc APIs use UID_INVALID as special placeholder */ - if (uid == (uid_t) 0xFFFFFFFF) - return false; - - /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ - if (uid == (uid_t) 0xFFFF) - return false; - - return true; -} - -int parse_uid(const char *s, uid_t* ret_uid) { - unsigned long ul = 0; - uid_t uid; - int r; - - assert(s); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - uid = (uid_t) ul; - - if ((unsigned long) uid != ul) - return -ERANGE; - - if (!uid_is_valid(uid)) - return -ENXIO; /* we return ENXIO instead of EINVAL - * here, to make it easy to distuingish - * invalid numeric uids invalid - * strings. */ - - if (ret_uid) - *ret_uid = uid; - - return 0; -} - -int safe_atou(const char *s, unsigned *ret_u) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret_u); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (unsigned) l != l) - return -ERANGE; - - *ret_u = (unsigned) l; - return 0; -} - -int safe_atoi(const char *s, int *ret_i) { - char *x = NULL; - long l; - - assert(s); - assert(ret_i); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((long) (int) l != l) - return -ERANGE; - - *ret_i = (int) l; - return 0; -} - -int safe_atou8(const char *s, uint8_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (uint8_t) l != l) - return -ERANGE; - - *ret = (uint8_t) l; - return 0; -} - -int safe_atou16(const char *s, uint16_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (uint16_t) l != l) - return -ERANGE; - - *ret = (uint16_t) l; - return 0; -} - -int safe_atoi16(const char *s, int16_t *ret) { - char *x = NULL; - long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((long) (int16_t) l != l) - return -ERANGE; - - *ret = (int16_t) l; - return 0; -} - -int safe_atollu(const char *s, long long unsigned *ret_llu) { - char *x = NULL; - unsigned long long l; - - assert(s); - assert(ret_llu); - - errno = 0; - l = strtoull(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_llu = l; - return 0; -} - -int safe_atolli(const char *s, long long int *ret_lli) { - char *x = NULL; - long long l; - - assert(s); - assert(ret_lli); - - errno = 0; - l = strtoll(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_lli = l; - return 0; -} - -int safe_atod(const char *s, double *ret_d) { - char *x = NULL; - double d = 0; - locale_t loc; - - assert(s); - assert(ret_d); - - loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); - if (loc == (locale_t) 0) - return -errno; - - errno = 0; - d = strtod_l(s, &x, loc); - - if (!x || x == s || *x || errno) { - freelocale(loc); - return errno ? -errno : -EINVAL; - } - - freelocale(loc); - *ret_d = (double) d; - return 0; -} - -static size_t strcspn_escaped(const char *s, const char *reject) { - bool escaped = false; - int n; - - for (n=0; s[n]; n++) { - if (escaped) - escaped = false; - else if (s[n] == '\\') - escaped = true; - else if (strchr(reject, s[n])) - break; - } - - /* if s ends in \, return index of previous char */ - return n - escaped; -} - -/* Split a string into words. */ -const char* split(const char **state, size_t *l, const char *separator, bool quoted) { - const char *current; - - current = *state; - - if (!*current) { - assert(**state == '\0'); - return NULL; - } - - current += strspn(current, separator); - if (!*current) { - *state = current; - return NULL; - } - - if (quoted && strchr("\'\"", *current)) { - char quotechars[2] = {*current, '\0'}; - - *l = strcspn_escaped(current + 1, quotechars); - if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || - (current[*l + 2] && !strchr(separator, current[*l + 2]))) { - /* right quote missing or garbage at the end */ - *state = current; - return NULL; - } - *state = current++ + *l + 2; - } else if (quoted) { - *l = strcspn_escaped(current, separator); - if (current[*l] && !strchr(separator, current[*l])) { - /* unfinished escape */ - *state = current; - return NULL; - } - *state = current + *l; - } else { - *l = strcspn(current, separator); - *state = current + *l; - } - - return current; -} - -int fchmod_umask(int fd, mode_t m) { - mode_t u; - int r; - - u = umask(0777); - r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; - umask(u); - - return r; -} - -char *truncate_nl(char *s) { - assert(s); - - s[strcspn(s, NEWLINE)] = 0; - return s; -} - -char *strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - - if (!s) - return strndup(suffix, b); - - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - if (b > ((size_t) -1) - a) - return NULL; - - r = new(char, a+b+1); - if (!r) - return NULL; - - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; - - return r; -} - -char *strappend(const char *s, const char *suffix) { - return strnappend(s, suffix, suffix ? strlen(suffix) : 0); -} - -int readlinkat_malloc(int fd, const char *p, char **ret) { - size_t l = 100; - int r; - - assert(p); - assert(ret); - - for (;;) { - char *c; - ssize_t n; - - c = new(char, l); - if (!c) - return -ENOMEM; - - n = readlinkat(fd, p, c, l-1); - if (n < 0) { - r = -errno; - free(c); - return r; - } - - if ((size_t) n < l-1) { - c[n] = 0; - *ret = c; - return 0; - } - - free(c); - l *= 2; - } -} - -int readlink_malloc(const char *p, char **ret) { - return readlinkat_malloc(AT_FDCWD, p, ret); -} - -int readlink_value(const char *p, char **ret) { - _cleanup_free_ char *link = NULL; - char *value; - int r; - - r = readlink_malloc(p, &link); - if (r < 0) - return r; - - value = basename(link); - if (!value) - return -ENOENT; - - value = strdup(value); - if (!value) - return -ENOMEM; - - *ret = value; - - return 0; -} - -int readlink_and_make_absolute(const char *p, char **r) { - _cleanup_free_ char *target = NULL; - char *k; - int j; - - assert(p); - assert(r); - - j = readlink_malloc(p, &target); - if (j < 0) - return j; - - k = file_in_same_dir(p, target); - if (!k) - return -ENOMEM; - - *r = k; - return 0; -} - -int readlink_and_canonicalize(const char *p, char **r) { - char *t, *s; - int j; - - assert(p); - assert(r); - - j = readlink_and_make_absolute(p, &t); - if (j < 0) - return j; - - s = canonicalize_file_name(t); - if (s) { - free(t); - *r = s; - } else - *r = t; - - path_kill_slashes(*r); - - return 0; -} - -char *strstrip(char *s) { - char *e; - - /* Drops trailing whitespace. Modifies the string in - * place. Returns pointer to first non-space character */ - - s += strspn(s, WHITESPACE); - - for (e = strchr(s, 0); e > s; e --) - if (!strchr(WHITESPACE, e[-1])) - break; - - *e = 0; - - return s; -} - -char *delete_chars(char *s, const char *bad) { - char *f, *t; - - /* Drops all whitespace, regardless where in the string */ - - for (f = s, t = s; *f; f++) { - if (strchr(bad, *f)) - continue; - - *(t++) = *f; - } - - *t = 0; - - return s; -} - -char *file_in_same_dir(const char *path, const char *filename) { - char *e, *ret; - size_t k; - - assert(path); - assert(filename); - - /* This removes the last component of path and appends - * filename, unless the latter is absolute anyway or the - * former isn't */ - - if (path_is_absolute(filename)) - return strdup(filename); - - e = strrchr(path, '/'); - if (!e) - return strdup(filename); - - k = strlen(filename); - ret = new(char, (e + 1 - path) + k + 1); - if (!ret) - return NULL; - - memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1); - return ret; -} - -int rmdir_parents(const char *path, const char *stop) { - size_t l; - int r = 0; - - assert(path); - assert(stop); - - l = strlen(path); - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - while (l > 0) { - char *t; - - /* Skip last component */ - while (l > 0 && path[l-1] != '/') - l--; - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - if (l <= 0) - break; - - if (!(t = strndup(path, l))) - return -ENOMEM; - - if (path_startswith(stop, t)) { - free(t); - return 0; - } - - r = rmdir(t); - free(t); - - if (r < 0) - if (errno != ENOENT) - return -errno; - } - - return 0; -} - -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; - - return table[x & 15]; -} - -int unhexchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - return -EINVAL; -} - -char *hexmem(const void *p, size_t l) { - char *r, *z; - const uint8_t *x; - - z = r = malloc(l * 2 + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + l; x++) { - *(z++) = hexchar(*x >> 4); - *(z++) = hexchar(*x & 15); - } - - *z = 0; - return r; -} - -int unhexmem(const char *p, size_t l, void **mem, size_t *len) { - _cleanup_free_ uint8_t *r = NULL; - uint8_t *z; - const char *x; - - assert(mem); - assert(len); - assert(p); - - z = r = malloc((l + 1) / 2 + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + l; x += 2) { - int a, b; - - a = unhexchar(x[0]); - if (a < 0) - return a; - else if (x+1 < p + l) { - b = unhexchar(x[1]); - if (b < 0) - return b; - } else - b = 0; - - *(z++) = (uint8_t) a << 4 | (uint8_t) b; - } - - *z = 0; - - *mem = r; - r = NULL; - *len = (l + 1) / 2; - - return 0; -} - -/* https://tools.ietf.org/html/rfc4648#section-6 - * Notice that base32hex differs from base32 in the alphabet it uses. - * The distinction is that the base32hex representation preserves the - * order of the underlying data when compared as bytestrings, this is - * useful when representing NSEC3 hashes, as one can then verify the - * order of hashes directly from their representation. */ -char base32hexchar(int x) { - static const char table[32] = "0123456789" - "ABCDEFGHIJKLMNOPQRSTUV"; - - return table[x & 31]; -} - -int unbase32hexchar(char c) { - unsigned offset; - - if (c >= '0' && c <= '9') - return c - '0'; - - offset = '9' - '0' + 1; - - if (c >= 'A' && c <= 'V') - return c - 'A' + offset; - - return -EINVAL; -} - -char *base32hexmem(const void *p, size_t l, bool padding) { - char *r, *z; - const uint8_t *x; - size_t len; - - if (padding) - /* five input bytes makes eight output bytes, padding is added so we must round up */ - len = 8 * (l + 4) / 5; - else { - /* same, but round down as there is no padding */ - len = 8 * l / 5; - - switch (l % 5) { - case 4: - len += 7; - break; - case 3: - len += 5; - break; - case 2: - len += 4; - break; - case 1: - len += 2; - break; - } - } - - z = r = malloc(len + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { - /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ - x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ - *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ - *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */ - *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */ - } - - switch (l % 5) { - case 4: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ - *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ - *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */ - if (padding) - *(z++) = '='; - - break; - - case 3: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ - *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - - case 2: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ - *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ - *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - - case 1: - *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ - *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */ - if (padding) { - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - *(z++) = '='; - } - - break; - } - - *z = 0; - return r; -} - -int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) { - _cleanup_free_ uint8_t *r = NULL; - int a, b, c, d, e, f, g, h; - uint8_t *z; - const char *x; - size_t len; - unsigned pad = 0; - - assert(p); - - /* padding ensures any base32hex input has input divisible by 8 */ - if (padding && l % 8 != 0) - return -EINVAL; - - if (padding) { - /* strip the padding */ - while (l > 0 && p[l - 1] == '=' && pad < 7) { - pad ++; - l --; - } - } - - /* a group of eight input bytes needs five output bytes, in case of - padding we need to add some extra bytes */ - len = (l / 8) * 5; - - switch (l % 8) { - case 7: - len += 4; - break; - case 5: - len += 3; - break; - case 4: - len += 2; - break; - case 2: - len += 1; - break; - case 0: - break; - default: - return -EINVAL; - } - - z = r = malloc(len + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + (l / 8) * 8; x += 8) { - /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW - e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - f = unbase32hexchar(x[5]); - if (f < 0) - return -EINVAL; - - g = unbase32hexchar(x[6]); - if (g < 0) - return -EINVAL; - - h = unbase32hexchar(x[7]); - if (h < 0) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ - *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */ - } - - switch (l % 8) { - case 7: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - f = unbase32hexchar(x[5]); - if (f < 0) - return -EINVAL; - - g = unbase32hexchar(x[6]); - if (g < 0) - return -EINVAL; - - /* g == 000VV000 */ - if (g & 7) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ - - break; - case 5: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - e = unbase32hexchar(x[4]); - if (e < 0) - return -EINVAL; - - /* e == 000SSSS0 */ - if (e & 1) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ - - break; - case 4: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase32hexchar(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase32hexchar(x[3]); - if (d < 0) - return -EINVAL; - - /* d == 000W0000 */ - if (d & 15) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ - - break; - case 2: - a = unbase32hexchar(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase32hexchar(x[1]); - if (b < 0) - return -EINVAL; - - /* b == 000YYY00 */ - if (b & 3) - return -EINVAL; - - *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ - - break; - case 0: - break; - default: - return -EINVAL; - } - - *z = 0; - - *mem = r; - r = NULL; - *_len = len; - - return 0; -} - -/* https://tools.ietf.org/html/rfc4648#section-4 */ -char base64char(int x) { - static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; - return table[x & 63]; -} - -int unbase64char(char c) { - unsigned offset; - - if (c >= 'A' && c <= 'Z') - return c - 'A'; - - offset = 'Z' - 'A' + 1; - - if (c >= 'a' && c <= 'z') - return c - 'a' + offset; - - offset += 'z' - 'a' + 1; - - if (c >= '0' && c <= '9') - return c - '0' + offset; - - offset += '9' - '0' + 1; - - if (c == '+') - return offset; - - offset ++; - - if (c == '/') - return offset; - - return -EINVAL; -} - -char *base64mem(const void *p, size_t l) { - char *r, *z; - const uint8_t *x; - - /* three input bytes makes four output bytes, padding is added so we must round up */ - z = r = malloc(4 * (l + 2) / 3 + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { - /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ - *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ - *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ - } - - switch (l % 3) { - case 2: - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ - *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ - *(z++) = '='; - - break; - case 1: - *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ - *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ - *(z++) = '='; - *(z++) = '='; - - break; - } - - *z = 0; - return r; -} - -int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { - _cleanup_free_ uint8_t *r = NULL; - int a, b, c, d; - uint8_t *z; - const char *x; - size_t len; - - assert(p); - - /* padding ensures any base63 input has input divisible by 4 */ - if (l % 4 != 0) - return -EINVAL; - - /* strip the padding */ - if (l > 0 && p[l - 1] == '=') - l --; - if (l > 0 && p[l - 1] == '=') - l --; - - /* a group of four input bytes needs three output bytes, in case of - padding we need to add two or three extra bytes */ - len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); - - z = r = malloc(len + 1); - if (!r) - return -ENOMEM; - - for (x = p; x < p + (l / 4) * 4; x += 4) { - /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase64char(x[2]); - if (c < 0) - return -EINVAL; - - d = unbase64char(x[3]); - if (d < 0) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ - } - - switch (l % 4) { - case 3: - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - c = unbase64char(x[2]); - if (c < 0) - return -EINVAL; - - /* c == 00ZZZZ00 */ - if (c & 3) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ - *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ - - break; - case 2: - a = unbase64char(x[0]); - if (a < 0) - return -EINVAL; - - b = unbase64char(x[1]); - if (b < 0) - return -EINVAL; - - /* b == 00YY0000 */ - if (b & 15) - return -EINVAL; - - *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ - - break; - case 0: - - break; - default: - return -EINVAL; - } - - *z = 0; - - *mem = r; - r = NULL; - *_len = len; - - return 0; -} - -char octchar(int x) { - return '0' + (x & 7); -} - -int unoctchar(char c) { - - if (c >= '0' && c <= '7') - return c - '0'; - - return -EINVAL; -} - -char decchar(int x) { - return '0' + (x % 10); -} - -int undecchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - return -EINVAL; -} - -char *cescape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Does C style string escaping. May be reversed with - * cunescape(). */ - - r = new(char, strlen(s)*4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) - t += cescape_char(*f, t); - - *t = 0; - - return r; -} - -static int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { - int r = 1; - - assert(p); - assert(*p); - assert(ret); - - /* Unescapes C style. Returns the unescaped character in ret, - * unless we encountered a \u sequence in which case the full - * unicode character is returned in ret_unicode, instead. */ - - if (length != (size_t) -1 && length < 1) - return -EINVAL; - - switch (p[0]) { - - case 'a': - *ret = '\a'; - break; - case 'b': - *ret = '\b'; - break; - case 'f': - *ret = '\f'; - break; - case 'n': - *ret = '\n'; - break; - case 'r': - *ret = '\r'; - break; - case 't': - *ret = '\t'; - break; - case 'v': - *ret = '\v'; - break; - case '\\': - *ret = '\\'; - break; - case '"': - *ret = '"'; - break; - case '\'': - *ret = '\''; - break; - - case 's': - /* This is an extension of the XDG syntax files */ - *ret = ' '; - break; - - case 'x': { - /* hexadecimal encoding */ - int a, b; - - if (length != (size_t) -1 && length < 3) - return -EINVAL; - - a = unhexchar(p[1]); - if (a < 0) - return -EINVAL; - - b = unhexchar(p[2]); - if (b < 0) - return -EINVAL; - - /* Don't allow NUL bytes */ - if (a == 0 && b == 0) - return -EINVAL; - - *ret = (char) ((a << 4U) | b); - r = 3; - break; - } - - case 'u': { - /* C++11 style 16bit unicode */ - - int a[4]; - unsigned i; - uint32_t c; - - if (length != (size_t) -1 && length < 5) - return -EINVAL; - - for (i = 0; i < 4; i++) { - a[i] = unhexchar(p[1 + i]); - if (a[i] < 0) - return a[i]; - } - - c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; - - /* Don't allow 0 chars */ - if (c == 0) - return -EINVAL; - - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - - r = 5; - break; - } - - case 'U': { - /* C++11 style 32bit unicode */ - - int a[8]; - unsigned i; - uint32_t c; - - if (length != (size_t) -1 && length < 9) - return -EINVAL; - - for (i = 0; i < 8; i++) { - a[i] = unhexchar(p[1 + i]); - if (a[i] < 0) - return a[i]; - } - - c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | - ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; - - /* Don't allow 0 chars */ - if (c == 0) - return -EINVAL; - - /* Don't allow invalid code points */ - if (!unichar_is_valid(c)) - return -EINVAL; - - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - - r = 9; - break; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - /* octal encoding */ - int a, b, c; - uint32_t m; - - if (length != (size_t) -1 && length < 3) - return -EINVAL; - - a = unoctchar(p[0]); - if (a < 0) - return -EINVAL; - - b = unoctchar(p[1]); - if (b < 0) - return -EINVAL; - - c = unoctchar(p[2]); - if (c < 0) - return -EINVAL; - - /* don't allow NUL bytes */ - if (a == 0 && b == 0 && c == 0) - return -EINVAL; - - /* Don't allow bytes above 255 */ - m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; - if (m > 255) - return -EINVAL; - - *ret = m; - r = 3; - break; - } - - default: - return -EINVAL; - } - - return r; -} - -int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) { - char *r, *t; - const char *f; - size_t pl; - - assert(s); - assert(ret); - - /* Undoes C style string escaping, and optionally prefixes it. */ - - pl = prefix ? strlen(prefix) : 0; - - r = new(char, pl+length+1); - if (!r) - return -ENOMEM; - - if (prefix) - memcpy(r, prefix, pl); - - for (f = s, t = r + pl; f < s + length; f++) { - size_t remaining; - uint32_t u; - char c; - int k; - - remaining = s + length - f; - assert(remaining > 0); - - if (*f != '\\') { - /* A literal literal, copy verbatim */ - *(t++) = *f; - continue; - } - - if (remaining == 1) { - if (flags & UNESCAPE_RELAX) { - /* A trailing backslash, copy verbatim */ - *(t++) = *f; - continue; - } - - free(r); - return -EINVAL; - } - - k = cunescape_one(f + 1, remaining - 1, &c, &u); - if (k < 0) { - if (flags & UNESCAPE_RELAX) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - continue; - } - - free(r); - return k; - } - - if (c != 0) - /* Non-Unicode? Let's encode this directly */ - *(t++) = c; - else - /* Unicode? Then let's encode this in UTF-8 */ - t += utf8_encode_unichar(t, u); - - f += k; - } - - *t = 0; - - *ret = r; - return t - r; -} - -int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { - return cunescape_length_with_prefix(s, length, NULL, flags, ret); -} - -int cunescape(const char *s, UnescapeFlags flags, char **ret) { - return cunescape_length(s, strlen(s), flags, ret); -} - -char *xescape(const char *s, const char *bad) { - char *r, *t; - const char *f; - - /* Escapes all chars in bad, in addition to \ and all special - * chars, in \xFF style escaping. May be reversed with - * cunescape(). */ - - r = new(char, strlen(s) * 4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) { - - if ((*f < ' ') || (*f >= 127) || - (*f == '\\') || strchr(bad, *f)) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *ascii_strlower(char *t) { - char *p; - - assert(t); - - for (p = t; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; - - return t; -} - -_pure_ static bool hidden_file_allow_backup(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".dpkg-tmp") || - endswith(filename, ".dpkg-dist") || - endswith(filename, ".dpkg-bak") || - endswith(filename, ".dpkg-backup") || - endswith(filename, ".dpkg-remove") || - endswith(filename, ".swp"); -} - -bool hidden_file(const char *filename) { - assert(filename); - - if (endswith(filename, "~")) - return true; - - return hidden_file_allow_backup(filename); -} - -int fd_nonblock(int fd, bool nonblock) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) - return -errno; - - if (nonblock) - nflags = flags | O_NONBLOCK; - else - nflags = flags & ~O_NONBLOCK; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFL, nflags) < 0) - return -errno; - - return 0; -} - -int fd_cloexec(int fd, bool cloexec) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFD, 0); - if (flags < 0) - return -errno; - - if (cloexec) - nflags = flags | FD_CLOEXEC; - else - nflags = flags & ~FD_CLOEXEC; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFD, nflags) < 0) - return -errno; - - return 0; -} - -_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { - unsigned i; - - assert(n_fdset == 0 || fdset); - - for (i = 0; i < n_fdset; i++) - if (fdset[i] == fd) - return true; - - return false; -} - -int close_all_fds(const int except[], unsigned n_except) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r = 0; - - assert(n_except == 0 || except); - - d = opendir("/proc/self/fd"); - if (!d) { - int fd; - struct rlimit rl; - - /* When /proc isn't available (for example in chroots) - * the fallback is brute forcing through the fd - * table */ - - assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - for (fd = 3; fd < (int) rl.rlim_max; fd ++) { - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) - if (errno != EBADF && r == 0) - r = -errno; - } - - return r; - } - - while ((de = readdir(d))) { - int fd = -1; - - if (hidden_file(de->d_name)) - continue; - - if (safe_atoi(de->d_name, &fd) < 0) - /* Let's better ignore this, just in case */ - continue; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) { - /* Valgrind has its own FD and doesn't want to have it closed */ - if (errno != EBADF && r == 0) - r = -errno; - } - } - - return r; -} - -bool chars_intersect(const char *a, const char *b) { - const char *p; - - /* Returns true if any of the chars in a are in b. */ - for (p = a; *p; p++) - if (strchr(b, *p)) - return true; - - return false; -} - -bool fstype_is_network(const char *fstype) { - static const char table[] = - "afs\0" - "cifs\0" - "smbfs\0" - "sshfs\0" - "ncpfs\0" - "ncp\0" - "nfs\0" - "nfs4\0" - "gfs\0" - "gfs2\0" - "glusterfs\0"; - - const char *x; - - x = startswith(fstype, "fuse."); - if (x) - fstype = x; - - return nulstr_contains(table, fstype); -} - -int flush_fd(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN, - }; - - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; - - r = poll(&pollfd, 1, 0); - if (r < 0) { - if (errno == EINTR) - continue; - - return -errno; - - } else if (r == 0) - return 0; - - l = read(fd, buf, sizeof(buf)); - if (l < 0) { - - if (errno == EINTR) - continue; - - if (errno == EAGAIN) - return 0; - - return -errno; - } else if (l == 0) - return 0; - } -} - -void safe_close_pair(int p[]) { - assert(p); - - if (p[0] == p[1]) { - /* Special case pairs which use the same fd in both - * directions... */ - p[0] = p[1] = safe_close(p[0]); - return; - } - - p[0] = safe_close(p[0]); - p[1] = safe_close(p[1]); -} - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p = buf; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - /* If called with nbytes == 0, let's call read() at least - * once, to validate the operation */ - - if (nbytes > (size_t) SSIZE_MAX) - return -EINVAL; - - do { - ssize_t k; - - k = read(fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; - - if (errno == EAGAIN && do_poll) { - - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via read() */ - - (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); - continue; - } - - return n > 0 ? n : -errno; - } - - if (k == 0) - return n; - - assert((size_t) k <= nbytes); - - p += k; - nbytes -= k; - n += k; - } while (nbytes > 0); - - return n; -} - -int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { - ssize_t n; - - n = loop_read(fd, buf, nbytes, do_poll); - if (n < 0) - return (int) n; - if ((size_t) n != nbytes) - return -EIO; - - return 0; -} - -int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { - const uint8_t *p = buf; - - assert(fd >= 0); - assert(buf); - - if (nbytes > (size_t) SSIZE_MAX) - return -EINVAL; - - do { - ssize_t k; - - k = write(fd, p, nbytes); - if (k < 0) { - if (errno == EINTR) - continue; - - if (errno == EAGAIN && do_poll) { - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via write() */ - - (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); - continue; - } - - return -errno; - } - - if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */ - return -EIO; - - assert((size_t) k <= nbytes); - - p += k; - nbytes -= k; - } while (nbytes > 0); - - return 0; -} - -int parse_size(const char *t, uint64_t base, uint64_t *size) { - - /* Soo, sometimes we want to parse IEC binary suffixes, and - * sometimes SI decimal suffixes. This function can parse - * both. Which one is the right way depends on the - * context. Wikipedia suggests that SI is customary for - * hardware metrics and network speeds, while IEC is - * customary for most data sizes used by software and volatile - * (RAM) memory. Hence be careful which one you pick! - * - * In either case we use just K, M, G as suffix, and not Ki, - * Mi, Gi or so (as IEC would suggest). That's because that's - * frickin' ugly. But this means you really need to make sure - * to document which base you are parsing when you use this - * call. */ - - struct table { - const char *suffix; - unsigned long long factor; - }; - - static const struct table iec[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, - { "B", 1ULL }, - { "", 1ULL }, - }; - - static const struct table si[] = { - { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, - { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, - { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, - { "G", 1000ULL*1000ULL*1000ULL }, - { "M", 1000ULL*1000ULL }, - { "K", 1000ULL }, - { "B", 1ULL }, - { "", 1ULL }, - }; - - const struct table *table; - const char *p; - unsigned long long r = 0; - unsigned n_entries, start_pos = 0; - - assert(t); - assert(base == 1000 || base == 1024); - assert(size); - - if (base == 1000) { - table = si; - n_entries = ELEMENTSOF(si); - } else { - table = iec; - n_entries = ELEMENTSOF(iec); - } - - p = t; - do { - unsigned long long l, tmp; - double frac = 0; - char *e; - unsigned i; - - p += strspn(p, WHITESPACE); - if (*p == '-') - return -ERANGE; - - errno = 0; - l = strtoull(p, &e, 10); - if (errno > 0) - return -errno; - if (e == p) - return -EINVAL; - - if (*e == '.') { - e++; - - /* strtoull() itself would accept space/+/- */ - if (*e >= '0' && *e <= '9') { - unsigned long long l2; - char *e2; - - l2 = strtoull(e, &e2, 10); - if (errno > 0) - return -errno; - - /* Ignore failure. E.g. 10.M is valid */ - frac = l2; - for (; e < e2; e++) - frac /= 10; - } - } - - e += strspn(e, WHITESPACE); - - for (i = start_pos; i < n_entries; i++) - if (startswith(e, table[i].suffix)) - break; - - if (i >= n_entries) - return -EINVAL; - - if (l + (frac > 0) > ULLONG_MAX / table[i].factor) - return -ERANGE; - - tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); - if (tmp > ULLONG_MAX - r) - return -ERANGE; - - r += tmp; - if ((unsigned long long) (uint64_t) r != r) - return -ERANGE; - - p = e + strlen(table[i].suffix); - - start_pos = i + 1; - - } while (*p); - - *size = r; - - return 0; -} - -bool is_device_path(const char *path) { - - /* Returns true on paths that refer to a device, either in - * sysfs or in /dev */ - - return - path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); -} - -int dir_is_empty(const char *path) { - _cleanup_closedir_ DIR *d; - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - - if (!de) - return 1; - - if (!hidden_file(de->d_name)) - return 0; - } -} - -char* dirname_malloc(const char *path) { - char *d, *dir, *dir2; - - d = strdup(path); - if (!d) - return NULL; - dir = dirname(d); - assert(dir); - - if (dir != d) { - dir2 = strdup(dir); - free(d); - return dir2; - } - - return dir; -} - -void rename_process(const char name[8]) { - assert(name); - - /* This is a like a poor man's setproctitle(). It changes the - * comm field, argv[0], and also the glibc's internally used - * name of the process. For the first one a limit of 16 chars - * applies, to the second one usually one of 10 (i.e. length - * of "/sbin/init"), to the third one one of 7 (i.e. length of - * "systemd"). If you pass a longer string it will be - * truncated */ - - prctl(PR_SET_NAME, name); - - if (program_invocation_name) - strncpy(program_invocation_name, name, strlen(program_invocation_name)); - - if (saved_argc > 0) { - int i; - - if (saved_argv[0]) - strncpy(saved_argv[0], name, strlen(saved_argv[0])); - - for (i = 1; i < saved_argc; i++) { - if (!saved_argv[i]) - break; - - memzero(saved_argv[i], strlen(saved_argv[i])); - } - } -} - -char *lookup_uid(uid_t uid) { - long bufsize; - char *name; - _cleanup_free_ char *buf = NULL; - struct passwd pwbuf, *pw = NULL; - - /* Shortcut things to avoid NSS lookups */ - if (uid == 0) - return strdup("root"); - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize <= 0) - bufsize = 4096; - - buf = malloc(bufsize); - if (!buf) - return NULL; - - if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) - return strdup(pw->pw_name); - - if (asprintf(&name, UID_FMT, uid) < 0) - return NULL; - - return name; -} - -char* getlogname_malloc(void) { - uid_t uid; - struct stat st; - - if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) - uid = st.st_uid; - else - uid = getuid(); - - return lookup_uid(uid); -} - -char *getusername_malloc(void) { - const char *e; - - e = getenv("USER"); - if (e) - return strdup(e); - - return lookup_uid(getuid()); -} - -bool is_temporary_fs(const struct statfs *s) { - assert(s); - - return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) || - F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC); -} - -int fd_is_temporary_fs(int fd) { - struct statfs s; - - if (fstatfs(fd, &s) < 0) - return -errno; - - return is_temporary_fs(&s); -} - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { - assert(path); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != MODE_INVALID) - if (chmod(path, mode) < 0) - return -errno; - - if (uid != UID_INVALID || gid != GID_INVALID) - if (chown(path, uid, gid) < 0) - return -errno; - - return 0; -} - -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { - assert(fd >= 0); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != MODE_INVALID) - if (fchmod(fd, mode) < 0) - return -errno; - - if (uid != UID_INVALID || gid != GID_INVALID) - if (fchown(fd, uid, gid) < 0) - return -errno; - - return 0; -} - -cpu_set_t* cpu_set_malloc(unsigned *ncpus) { - cpu_set_t *r; - unsigned n = 1024; - - /* Allocates the cpuset in the right size */ - - for (;;) { - if (!(r = CPU_ALLOC(n))) - return NULL; - - if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) { - CPU_ZERO_S(CPU_ALLOC_SIZE(n), r); - - if (ncpus) - *ncpus = n; - - return r; - } - - CPU_FREE(r); - - if (errno != EINVAL) - return NULL; - - n *= 2; - } -} - -int parse_cpu_set( - const char *rvalue, - cpu_set_t **cpu_set, - const char *unit, - const char *filename, - unsigned line, - const char *lvalue) { - - const char *whole_rvalue = rvalue; - _cleanup_cpu_free_ cpu_set_t *c = NULL; - unsigned ncpus = 0; - - assert(filename); - assert(lvalue); - assert(rvalue); - - for (;;) { - _cleanup_free_ char *word = NULL; - unsigned cpu; - int r; - - r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Invalid value for %s: %s", lvalue, whole_rvalue); - return r; - } - if (r == 0) - break; - - r = safe_atou(word, &cpu); - - if (!c) - if (!(c = cpu_set_malloc(&ncpus))) - return log_oom(); - - if (r < 0 || cpu >= ncpus) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse CPU affinity '%s'", rvalue); - return -EBADMSG; - } - - CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c); - } - if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); - - /* On success, sets *cpu_set and returns ncpus for the system. */ - if (c) { - *cpu_set = c; - c = NULL; - } - return (int) ncpus; -} - -int files_same(const char *filea, const char *fileb) { - struct stat a, b; - - if (stat(filea, &a) < 0) - return -errno; - - if (stat(fileb, &b) < 0) - return -errno; - - return a.st_dev == b.st_dev && - a.st_ino == b.st_ino; -} - -int running_in_chroot(void) { - int ret; - - ret = files_same("/proc/1/root", "/"); - if (ret < 0) - return ret; - - return ret == 0; -} - -static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *r; - - assert(s); - assert(percent <= 100); - assert(new_length >= 3); - - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - r = new0(char, new_length+1); - if (!r) - return NULL; - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; - - memcpy(r, s, x); - r[x] = '.'; - r[x+1] = '.'; - r[x+2] = '.'; - memcpy(r + x + 3, - s + old_length - (new_length - x - 3), - new_length - x - 3); - - return r; -} - -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *e; - const char *i, *j; - unsigned k, len, len2; - - assert(s); - assert(percent <= 100); - assert(new_length >= 3); - - /* if no multibyte characters use ascii_ellipsize_mem for speed */ - if (ascii_is_valid(s)) - return ascii_ellipsize_mem(s, old_length, new_length, percent); - - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; - - k = 0; - for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { - int c; - - c = utf8_encoded_to_unichar(i); - if (c < 0) - return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - - if (k > x) /* last character was wide and went over quota */ - x ++; - - for (j = s + old_length; k < new_length && j > i; ) { - int c; - - j = utf8_prev_char(j); - c = utf8_encoded_to_unichar(j); - if (c < 0) - return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - assert(i <= j); - - /* we don't actually need to ellipsize */ - if (i == j) - return memdup(s, old_length + 1); - - /* make space for ellipsis */ - j = utf8_next_char(j); - - len = i - s; - len2 = s + old_length - j; - e = new(char, len + 3 + len2 + 1); - if (!e) - return NULL; - - /* - printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", - old_length, new_length, x, len, len2, k); - */ - - memcpy(e, s, len); - e[len] = 0xe2; /* tri-dot ellipsis: … */ - e[len + 1] = 0x80; - e[len + 2] = 0xa6; - - memcpy(e + len + 3, j, len2 + 1); - - return e; -} - -char *ellipsize(const char *s, size_t length, unsigned percent) { - return ellipsize_mem(s, strlen(s), length, percent); -} - -int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { - _cleanup_close_ int fd; - int r; - - assert(path); - - if (parents) - mkdir_parents(path, 0755); - - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); - if (fd < 0) - return -errno; - - if (mode > 0) { - r = fchmod(fd, mode); - if (r < 0) - return -errno; - } - - if (uid != UID_INVALID || gid != GID_INVALID) { - r = fchown(fd, uid, gid); - if (r < 0) - return -errno; - } - - if (stamp != USEC_INFINITY) { - struct timespec ts[2]; - - timespec_store(&ts[0], stamp); - ts[1] = ts[0]; - r = futimens(fd, ts); - } else - r = futimens(fd, NULL); - if (r < 0) - return -errno; - - return 0; -} - -int touch(const char *path) { - return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0); -} - -static char *unquote(const char *s, const char* quotes) { - size_t l; - assert(s); - - /* This is rather stupid, simply removes the heading and - * trailing quotes if there is one. Doesn't care about - * escaping or anything. - * - * DON'T USE THIS FOR NEW CODE ANYMORE!*/ - - l = strlen(s); - if (l < 2) - return strdup(s); - - if (strchr(quotes, s[0]) && s[l-1] == s[0]) - return strndup(s+1, l-2); - - return strdup(s); -} - -noreturn void freeze(void) { - - /* Make sure nobody waits for us on a socket anymore */ - close_all_fds(NULL, 0); - - sync(); - - for (;;) - pause(); -} - -bool null_or_empty(struct stat *st) { - assert(st); - - if (S_ISREG(st->st_mode) && st->st_size <= 0) - return true; - - if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - return true; - - return false; -} - -int null_or_empty_path(const char *fn) { - struct stat st; - - assert(fn); - - if (stat(fn, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -int null_or_empty_fd(int fd) { - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -DIR *xopendirat(int fd, const char *name, int flags) { - int nfd; - DIR *d; - - assert(!(flags & O_CREAT)); - - nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); - if (nfd < 0) - return NULL; - - d = fdopendir(nfd); - if (!d) { - safe_close(nfd); - return NULL; - } - - return d; -} - -static char *tag_to_udev_node(const char *tagvalue, const char *by) { - _cleanup_free_ char *t = NULL, *u = NULL; - size_t enc_len; - - u = unquote(tagvalue, QUOTES); - if (!u) - return NULL; - - enc_len = strlen(u) * 4 + 1; - t = new(char, enc_len); - if (!t) - return NULL; - - if (encode_devnode_name(u, t, enc_len) < 0) - return NULL; - - return strjoin("/dev/disk/by-", by, "/", t, NULL); -} - -char *fstab_node_to_udev_node(const char *p) { - assert(p); - - if (startswith(p, "LABEL=")) - return tag_to_udev_node(p+6, "label"); - - if (startswith(p, "UUID=")) - return tag_to_udev_node(p+5, "uuid"); - - if (startswith(p, "PARTUUID=")) - return tag_to_udev_node(p+9, "partuuid"); - - if (startswith(p, "PARTLABEL=")) - return tag_to_udev_node(p+10, "partlabel"); - - return strdup(p); -} - -bool dirent_is_file(const struct dirent *de) { - assert(de); - - if (hidden_file(de->d_name)) - return false; - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - return true; -} - -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { - assert(de); - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - if (hidden_file_allow_backup(de->d_name)) - return false; - - return endswith(de->d_name, suffix); -} - static int do_execute(char **directories, usec_t timeout, char *argv[]) { _cleanup_hashmap_free_free_ Hashmap *pids = NULL; _cleanup_set_free_free_ Set *seen = NULL; @@ -3098,189 +265,10 @@ void execute_directories(const char* const* directories, usec_t timeout, char *a wait_for_terminate_and_warn(name, executor_pid, true); } -bool nulstr_contains(const char*nulstr, const char *needle) { - const char *i; - - if (!nulstr) - return false; - - NULSTR_FOREACH(i, nulstr) - if (streq(i, needle)) - return true; - - return false; -} - bool plymouth_running(void) { return access("/run/plymouth/pid", F_OK) >= 0; } -char* strshorten(char *s, size_t l) { - assert(s); - - if (l < strlen(s)) - s[l] = 0; - - return s; -} - -int pipe_eof(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN|POLLHUP, - }; - - int r; - - r = poll(&pollfd, 1, 0); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents & POLLHUP; -} - -int fd_wait_for_event(int fd, int event, usec_t t) { - - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; - - struct timespec ts; - int r; - - r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents; -} - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { - FILE *f; - char *t; - int r, fd; - - assert(path); - assert(_f); - assert(_temp_path); - - r = tempfn_xxxxxx(path, NULL, &t); - if (r < 0) - return r; - - fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - free(t); - return -errno; - } - - f = fdopen(fd, "we"); - if (!f) { - unlink_noerrno(t); - free(t); - safe_close(fd); - return -errno; - } - - *_f = f; - *_temp_path = t; - - return 0; -} - -int symlink_atomic(const char *from, const char *to) { - _cleanup_free_ char *t = NULL; - int r; - - assert(from); - assert(to); - - r = tempfn_random(to, NULL, &t); - if (r < 0) - return r; - - if (symlink(from, t) < 0) - return -errno; - - if (rename(t, to) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -int symlink_idempotent(const char *from, const char *to) { - _cleanup_free_ char *p = NULL; - int r; - - assert(from); - assert(to); - - if (symlink(from, to) < 0) { - if (errno != EEXIST) - return -errno; - - r = readlink_malloc(to, &p); - if (r < 0) - return r; - - if (!streq(p, from)) - return -EINVAL; - } - - return 0; -} - -int mknod_atomic(const char *path, mode_t mode, dev_t dev) { - _cleanup_free_ char *t = NULL; - int r; - - assert(path); - - r = tempfn_random(path, NULL, &t); - if (r < 0) - return r; - - if (mknod(t, mode, dev) < 0) - return -errno; - - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -int mkfifo_atomic(const char *path, mode_t mode) { - _cleanup_free_ char *t = NULL; - int r; - - assert(path); - - r = tempfn_random(path, NULL, &t); - if (r < 0) - return r; - - if (mkfifo(t, mode) < 0) - return -errno; - - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - bool display_is_local(const char *display) { assert(display); @@ -3315,368 +303,6 @@ int socket_from_display(const char *display, char **path) { return 0; } -int get_user_creds( - const char **username, - uid_t *uid, gid_t *gid, - const char **home, - const char **shell) { - - struct passwd *p; - uid_t u; - - assert(username); - assert(*username); - - /* We enforce some special rules for uid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*username, "root") || streq(*username, "0")) { - *username = "root"; - - if (uid) - *uid = 0; - - if (gid) - *gid = 0; - - if (home) - *home = "/root"; - - if (shell) - *shell = "/bin/sh"; - - return 0; - } - - if (parse_uid(*username, &u) >= 0) { - errno = 0; - p = getpwuid(u); - - /* If there are multiple users with the same id, make - * sure to leave $USER to the configured value instead - * of the first occurrence in the database. However if - * the uid was configured by a numeric uid, then let's - * pick the real username from /etc/passwd. */ - if (p) - *username = p->pw_name; - } else { - errno = 0; - p = getpwnam(*username); - } - - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (uid) - *uid = p->pw_uid; - - if (gid) - *gid = p->pw_gid; - - if (home) - *home = p->pw_dir; - - if (shell) - *shell = p->pw_shell; - - return 0; -} - -char* uid_to_name(uid_t uid) { - struct passwd *p; - char *r; - - if (uid == 0) - return strdup("root"); - - p = getpwuid(uid); - if (p) - return strdup(p->pw_name); - - if (asprintf(&r, UID_FMT, uid) < 0) - return NULL; - - return r; -} - -char* gid_to_name(gid_t gid) { - struct group *p; - char *r; - - if (gid == 0) - return strdup("root"); - - p = getgrgid(gid); - if (p) - return strdup(p->gr_name); - - if (asprintf(&r, GID_FMT, gid) < 0) - return NULL; - - return r; -} - -int get_group_creds(const char **groupname, gid_t *gid) { - struct group *g; - gid_t id; - - assert(groupname); - - /* We enforce some special rules for gid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*groupname, "root") || streq(*groupname, "0")) { - *groupname = "root"; - - if (gid) - *gid = 0; - - return 0; - } - - if (parse_gid(*groupname, &id) >= 0) { - errno = 0; - g = getgrgid(id); - - if (g) - *groupname = g->gr_name; - } else { - errno = 0; - g = getgrnam(*groupname); - } - - if (!g) - return errno > 0 ? -errno : -ESRCH; - - if (gid) - *gid = g->gr_gid; - - return 0; -} - -int in_gid(gid_t gid) { - gid_t *gids; - int ngroups_max, r, i; - - if (getgid() == gid) - return 1; - - if (getegid() == gid) - return 1; - - ngroups_max = sysconf(_SC_NGROUPS_MAX); - assert(ngroups_max > 0); - - gids = alloca(sizeof(gid_t) * ngroups_max); - - r = getgroups(ngroups_max, gids); - if (r < 0) - return -errno; - - for (i = 0; i < r; i++) - if (gids[i] == gid) - return 1; - - return 0; -} - -int in_group(const char *name) { - int r; - gid_t gid; - - r = get_group_creds(&name, &gid); - if (r < 0) - return r; - - return in_gid(gid); -} - -int glob_exists(const char *path) { - _cleanup_globfree_ glob_t g = {}; - int k; - - assert(path); - - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - return 0; - else if (k == GLOB_NOSPACE) - return -ENOMEM; - else if (k == 0) - return !strv_isempty(g.gl_pathv); - else - return errno ? -errno : -EIO; -} - -int glob_extend(char ***strv, const char *path) { - _cleanup_globfree_ glob_t g = {}; - int k; - char **p; - - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - return -ENOENT; - else if (k == GLOB_NOSPACE) - return -ENOMEM; - else if (k != 0 || strv_isempty(g.gl_pathv)) - return errno ? -errno : -EIO; - - STRV_FOREACH(p, g.gl_pathv) { - k = strv_extend(strv, *p); - if (k < 0) - break; - } - - return k; -} - -int dirent_ensure_type(DIR *d, struct dirent *de) { - struct stat st; - - assert(d); - assert(de); - - if (de->d_type != DT_UNKNOWN) - return 0; - - if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) - return -errno; - - de->d_type = - S_ISREG(st.st_mode) ? DT_REG : - S_ISDIR(st.st_mode) ? DT_DIR : - S_ISLNK(st.st_mode) ? DT_LNK : - S_ISFIFO(st.st_mode) ? DT_FIFO : - S_ISSOCK(st.st_mode) ? DT_SOCK : - S_ISCHR(st.st_mode) ? DT_CHR : - S_ISBLK(st.st_mode) ? DT_BLK : - DT_UNKNOWN; - - return 0; -} - -int get_files_in_directory(const char *path, char ***list) { - _cleanup_closedir_ DIR *d = NULL; - size_t bufsize = 0, n = 0; - _cleanup_strv_free_ char **l = NULL; - - assert(path); - - /* Returns all files in a directory in *list, and the number - * of files as return value. If list is NULL returns only the - * number. */ - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - if (!de) - break; - - dirent_ensure_type(d, de); - - if (!dirent_is_file(de)) - continue; - - if (list) { - /* one extra slot is needed for the terminating NULL */ - if (!GREEDY_REALLOC(l, bufsize, n + 2)) - return -ENOMEM; - - l[n] = strdup(de->d_name); - if (!l[n]) - return -ENOMEM; - - l[++n] = NULL; - } else - n++; - } - - if (list) { - *list = l; - l = NULL; /* avoid freeing */ - } - - return n; -} - -char *strjoin(const char *x, ...) { - va_list ap; - size_t l; - char *r, *p; - - va_start(ap, x); - - if (x) { - l = strlen(x); - - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - } else - l = 0; - - va_end(ap); - - r = new(char, l+1); - if (!r) - return NULL; - - if (x) { - p = stpcpy(r, x); - - va_start(ap, x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - - va_end(ap); - } else - r[0] = 0; - - return r; -} - -bool is_main_thread(void) { - static thread_local int cached = 0; - - if (_unlikely_(cached == 0)) - cached = getpid() == gettid() ? 1 : -1; - - return cached > 0; -} - int block_get_whole_disk(dev_t d, dev_t *ret) { char *p, *s; int r; @@ -3737,104 +363,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret) { return -ENOENT; } -static const char *const ioprio_class_table[] = { - [IOPRIO_CLASS_NONE] = "none", - [IOPRIO_CLASS_RT] = "realtime", - [IOPRIO_CLASS_BE] = "best-effort", - [IOPRIO_CLASS_IDLE] = "idle" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); - -static const char *const sigchld_code_table[] = { - [CLD_EXITED] = "exited", - [CLD_KILLED] = "killed", - [CLD_DUMPED] = "dumped", - [CLD_TRAPPED] = "trapped", - [CLD_STOPPED] = "stopped", - [CLD_CONTINUED] = "continued", -}; - -DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); - -static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { - [LOG_FAC(LOG_KERN)] = "kern", - [LOG_FAC(LOG_USER)] = "user", - [LOG_FAC(LOG_MAIL)] = "mail", - [LOG_FAC(LOG_DAEMON)] = "daemon", - [LOG_FAC(LOG_AUTH)] = "auth", - [LOG_FAC(LOG_SYSLOG)] = "syslog", - [LOG_FAC(LOG_LPR)] = "lpr", - [LOG_FAC(LOG_NEWS)] = "news", - [LOG_FAC(LOG_UUCP)] = "uucp", - [LOG_FAC(LOG_CRON)] = "cron", - [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", - [LOG_FAC(LOG_FTP)] = "ftp", - [LOG_FAC(LOG_LOCAL0)] = "local0", - [LOG_FAC(LOG_LOCAL1)] = "local1", - [LOG_FAC(LOG_LOCAL2)] = "local2", - [LOG_FAC(LOG_LOCAL3)] = "local3", - [LOG_FAC(LOG_LOCAL4)] = "local4", - [LOG_FAC(LOG_LOCAL5)] = "local5", - [LOG_FAC(LOG_LOCAL6)] = "local6", - [LOG_FAC(LOG_LOCAL7)] = "local7" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); - -static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", - [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); - -static const char* const sched_policy_table[] = { - [SCHED_OTHER] = "other", - [SCHED_BATCH] = "batch", - [SCHED_IDLE] = "idle", - [SCHED_FIFO] = "fifo", - [SCHED_RR] = "rr" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); - -static const char* const rlimit_table[_RLIMIT_MAX] = { - [RLIMIT_CPU] = "LimitCPU", - [RLIMIT_FSIZE] = "LimitFSIZE", - [RLIMIT_DATA] = "LimitDATA", - [RLIMIT_STACK] = "LimitSTACK", - [RLIMIT_CORE] = "LimitCORE", - [RLIMIT_RSS] = "LimitRSS", - [RLIMIT_NOFILE] = "LimitNOFILE", - [RLIMIT_AS] = "LimitAS", - [RLIMIT_NPROC] = "LimitNPROC", - [RLIMIT_MEMLOCK] = "LimitMEMLOCK", - [RLIMIT_LOCKS] = "LimitLOCKS", - [RLIMIT_SIGPENDING] = "LimitSIGPENDING", - [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", - [RLIMIT_NICE] = "LimitNICE", - [RLIMIT_RTPRIO] = "LimitRTPRIO", - [RLIMIT_RTTIME] = "LimitRTTIME" -}; - -DEFINE_STRING_TABLE_LOOKUP(rlimit, int); - -static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", - [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); - bool kexec_loaded(void) { bool loaded = false; char *s; @@ -3865,93 +393,6 @@ int prot_from_flags(int flags) { } } -char *format_bytes(char *buf, size_t l, uint64_t t) { - unsigned i; - - static const struct { - const char *suffix; - uint64_t factor; - } table[] = { - { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, - { "M", UINT64_C(1024)*UINT64_C(1024) }, - { "K", UINT64_C(1024) }, - }; - - if (t == (uint64_t) -1) - return NULL; - - for (i = 0; i < ELEMENTSOF(table); i++) { - - if (t >= table[i].factor) { - snprintf(buf, l, - "%" PRIu64 ".%" PRIu64 "%s", - t / table[i].factor, - ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), - table[i].suffix); - - goto finish; - } - } - - snprintf(buf, l, "%" PRIu64 "B", t); - -finish: - buf[l-1] = 0; - return buf; - -} - -void* memdup(const void *p, size_t l) { - void *r; - - assert(p); - - r = malloc(l); - if (!r) - return NULL; - - memcpy(r, p, l); - return r; -} - -int fd_inc_sndbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) - return 0; - - /* If we have the privileges we will ignore the kernel limit. */ - - value = (int) n; - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) - return -errno; - - return 1; -} - -int fd_inc_rcvbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) - return 0; - - /* If we have the privileges we will ignore the kernel limit. */ - - value = (int) n; - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) - return -errno; - return 1; -} - int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { bool stdout_is_tty, stderr_is_tty; pid_t parent_pid, agent_pid; @@ -4054,82 +495,6 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa _exit(EXIT_FAILURE); } -int setrlimit_closest(int resource, const struct rlimit *rlim) { - struct rlimit highest, fixed; - - assert(rlim); - - if (setrlimit(resource, rlim) >= 0) - return 0; - - if (errno != EPERM) - return -errno; - - /* So we failed to set the desired setrlimit, then let's try - * to get as close as we can */ - assert_se(getrlimit(resource, &highest) == 0); - - fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); - fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); - - if (setrlimit(resource, &fixed) < 0) - return -errno; - - return 0; -} - -bool http_etag_is_valid(const char *etag) { - if (isempty(etag)) - return false; - - if (!endswith(etag, "\"")) - return false; - - if (!startswith(etag, "\"") && !startswith(etag, "W/\"")) - return false; - - return true; -} - -bool http_url_is_valid(const char *url) { - const char *p; - - if (isempty(url)) - return false; - - p = startswith(url, "http://"); - if (!p) - p = startswith(url, "https://"); - if (!p) - return false; - - if (isempty(p)) - return false; - - return ascii_is_valid(p); -} - -bool documentation_url_is_valid(const char *url) { - const char *p; - - if (isempty(url)) - return false; - - if (http_url_is_valid(url)) - return true; - - p = startswith(url, "file:/"); - if (!p) - p = startswith(url, "info:"); - if (!p) - p = startswith(url, "man:"); - - if (isempty(p)) - return false; - - return ascii_is_valid(p); -} - bool in_initrd(void) { static int saved = -1; struct statfs s; @@ -4154,181 +519,6 @@ bool in_initrd(void) { return saved; } -int get_home_dir(char **_h) { - struct passwd *p; - const char *e; - char *h; - uid_t u; - - assert(_h); - - /* Take the user specified one */ - e = secure_getenv("HOME"); - if (e && path_is_absolute(e)) { - h = strdup(e); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - h = strdup("/root"); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_dir)) - return -EINVAL; - - h = strdup(p->pw_dir); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; -} - -int get_shell(char **_s) { - struct passwd *p; - const char *e; - char *s; - uid_t u; - - assert(_s); - - /* Take the user specified one */ - e = getenv("SHELL"); - if (e) { - s = strdup(e); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - s = strdup("/bin/sh"); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_shell)) - return -EINVAL; - - s = strdup(p->pw_shell); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; -} - -bool filename_is_valid(const char *p) { - - if (isempty(p)) - return false; - - if (strchr(p, '/')) - return false; - - if (streq(p, ".")) - return false; - - if (streq(p, "..")) - return false; - - if (strlen(p) > FILENAME_MAX) - return false; - - return true; -} - -bool string_is_safe(const char *p) { - const char *t; - - if (!p) - return false; - - for (t = p; *t; t++) { - if (*t > 0 && *t < ' ') - return false; - - if (strchr("\\\"\'\x7f", *t)) - return false; - } - - return true; -} - -/** - * Check if a string contains control characters. If 'ok' is non-NULL - * it may be a string containing additional CCs to be considered OK. - */ -bool string_has_cc(const char *p, const char *ok) { - const char *t; - - assert(p); - - for (t = p; *t; t++) { - if (ok && strchr(ok, *t)) - continue; - - if (*t > 0 && *t < ' ') - return true; - - if (*t == 127) - return true; - } - - return false; -} - -bool path_is_safe(const char *p) { - - if (isempty(p)) - return false; - - if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) - return false; - - if (strlen(p)+1 > PATH_MAX) - return false; - - /* The following two checks are not really dangerous, but hey, they still are confusing */ - if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) - return false; - - if (strstr(p, "//")) - return false; - - return true; -} - /* hey glibc, APIs with callbacks without a user pointer are so useless */ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), void *arg) { @@ -4352,216 +542,6 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, return NULL; } -void init_gettext(void) { - setlocale(LC_ALL, ""); - textdomain(GETTEXT_PACKAGE); -} - -bool is_locale_utf8(void) { - const char *set; - static int cached_answer = -1; - - if (cached_answer >= 0) - goto out; - - if (!setlocale(LC_ALL, "")) { - cached_answer = true; - goto out; - } - - set = nl_langinfo(CODESET); - if (!set) { - cached_answer = true; - goto out; - } - - if (streq(set, "UTF-8")) { - cached_answer = true; - goto out; - } - - /* For LC_CTYPE=="C" return true, because CTYPE is effectly - * unset and everything can do to UTF-8 nowadays. */ - set = setlocale(LC_CTYPE, NULL); - if (!set) { - cached_answer = true; - goto out; - } - - /* Check result, but ignore the result if C was set - * explicitly. */ - cached_answer = - STR_IN_SET(set, "C", "POSIX") && - !getenv("LC_ALL") && - !getenv("LC_CTYPE") && - !getenv("LANG"); - -out: - return (bool) cached_answer; -} - -const char *draw_special_char(DrawSpecialChar ch) { - static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { - - /* UTF-8 */ { - [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */ - [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ - [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ - [DRAW_TREE_SPACE] = " ", /* */ - [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ - [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */ - [DRAW_ARROW] = "\342\206\222", /* → */ - [DRAW_DASH] = "\342\200\223", /* – */ - }, - - /* ASCII fallback */ { - [DRAW_TREE_VERTICAL] = "| ", - [DRAW_TREE_BRANCH] = "|-", - [DRAW_TREE_RIGHT] = "`-", - [DRAW_TREE_SPACE] = " ", - [DRAW_TRIANGULAR_BULLET] = ">", - [DRAW_BLACK_CIRCLE] = "*", - [DRAW_ARROW] = "->", - [DRAW_DASH] = "-", - } - }; - - return draw_table[!is_locale_utf8()][ch]; -} - -char *strreplace(const char *text, const char *old_string, const char *new_string) { - const char *f; - char *t, *r; - size_t l, old_len, new_len; - - assert(text); - assert(old_string); - assert(new_string); - - old_len = strlen(old_string); - new_len = strlen(new_string); - - l = strlen(text); - r = new(char, l+1); - if (!r) - return NULL; - - f = text; - t = r; - while (*f) { - char *a; - size_t d, nl; - - if (!startswith(f, old_string)) { - *(t++) = *(f++); - continue; - } - - d = t - r; - nl = l - old_len + new_len; - a = realloc(r, nl + 1); - if (!a) - goto oom; - - l = nl; - r = a; - t = r + d; - - t = stpcpy(t, new_string); - f += old_len; - } - - *t = 0; - return r; - -oom: - free(r); - return NULL; -} - -char *strip_tab_ansi(char **ibuf, size_t *_isz) { - const char *i, *begin = NULL; - enum { - STATE_OTHER, - STATE_ESCAPE, - STATE_BRACKET - } state = STATE_OTHER; - char *obuf = NULL; - size_t osz = 0, isz; - FILE *f; - - assert(ibuf); - assert(*ibuf); - - /* Strips ANSI color and replaces TABs by 8 spaces */ - - isz = _isz ? *_isz : strlen(*ibuf); - - f = open_memstream(&obuf, &osz); - if (!f) - return NULL; - - for (i = *ibuf; i < *ibuf + isz + 1; i++) { - - switch (state) { - - case STATE_OTHER: - if (i >= *ibuf + isz) /* EOT */ - break; - else if (*i == '\x1B') - state = STATE_ESCAPE; - else if (*i == '\t') - fputs(" ", f); - else - fputc(*i, f); - break; - - case STATE_ESCAPE: - if (i >= *ibuf + isz) { /* EOT */ - fputc('\x1B', f); - break; - } else if (*i == '[') { - state = STATE_BRACKET; - begin = i + 1; - } else { - fputc('\x1B', f); - fputc(*i, f); - state = STATE_OTHER; - } - - break; - - case STATE_BRACKET: - - if (i >= *ibuf + isz || /* EOT */ - (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { - fputc('\x1B', f); - fputc('[', f); - state = STATE_OTHER; - i = begin-1; - } else if (*i == 'm') - state = STATE_OTHER; - break; - } - } - - if (ferror(f)) { - fclose(f); - free(obuf); - return NULL; - } - - fclose(f); - - free(*ibuf); - *ibuf = obuf; - - if (_isz) - *_isz = osz; - - return obuf; -} - int on_ac_power(void) { bool found_offline = false, found_online = false; _cleanup_closedir_ DIR *d = NULL; @@ -4638,204 +618,6 @@ int on_ac_power(void) { return found_online || !found_offline; } -static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) { - char **i; - - assert(path); - assert(mode); - assert(_f); - - if (!path_strv_resolve_uniq(search, root)) - return -ENOMEM; - - STRV_FOREACH(i, search) { - _cleanup_free_ char *p = NULL; - FILE *f; - - if (root) - p = strjoin(root, *i, "/", path, NULL); - else - p = strjoin(*i, "/", path, NULL); - if (!p) - return -ENOMEM; - - f = fopen(p, mode); - if (f) { - *_f = f; - return 0; - } - - if (errno != ENOENT) - return -errno; - } - - return -ENOENT; -} - -int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) { - _cleanup_strv_free_ char **copy = NULL; - - assert(path); - assert(mode); - assert(_f); - - if (path_is_absolute(path)) { - FILE *f; - - f = fopen(path, mode); - if (f) { - *_f = f; - return 0; - } - - return -errno; - } - - copy = strv_copy((char**) search); - if (!copy) - return -ENOMEM; - - return search_and_fopen_internal(path, mode, root, copy, _f); -} - -int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) { - _cleanup_strv_free_ char **s = NULL; - - if (path_is_absolute(path)) { - FILE *f; - - f = fopen(path, mode); - if (f) { - *_f = f; - return 0; - } - - return -errno; - } - - s = strv_split_nulstr(search); - if (!s) - return -ENOMEM; - - return search_and_fopen_internal(path, mode, root, s, _f); -} - -char *strextend(char **x, ...) { - va_list ap; - size_t f, l; - char *r, *p; - - assert(x); - - l = f = *x ? strlen(*x) : 0; - - va_start(ap, x); - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - va_end(ap); - - r = realloc(*x, l+1); - if (!r) - return NULL; - - p = r + f; - - va_start(ap, x); - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - va_end(ap); - - *p = 0; - *x = r; - - return r + l; -} - -char *strrep(const char *s, unsigned n) { - size_t l; - char *r, *p; - unsigned i; - - assert(s); - - l = strlen(s); - p = r = malloc(l * n + 1); - if (!r) - return NULL; - - for (i = 0; i < n; i++) - p = stpcpy(p, s); - - *p = 0; - return r; -} - -void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { - size_t a, newalloc; - void *q; - - assert(p); - assert(allocated); - - if (*allocated >= need) - return *p; - - newalloc = MAX(need * 2, 64u / size); - a = newalloc * size; - - /* check for overflows */ - if (a < size * need) - return NULL; - - q = realloc(*p, a); - if (!q) - return NULL; - - *p = q; - *allocated = newalloc; - return q; -} - -void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { - size_t prev; - uint8_t *q; - - assert(p); - assert(allocated); - - prev = *allocated; - - q = greedy_realloc(p, allocated, need, size); - if (!q) - return NULL; - - if (*allocated > prev) - memzero(q + prev * size, (*allocated - prev) * size); - - return q; -} - bool id128_is_valid(const char *s) { size_t i, l; @@ -4877,151 +659,6 @@ bool id128_is_valid(const char *s) { return true; } -int split_pair(const char *s, const char *sep, char **l, char **r) { - char *x, *a, *b; - - assert(s); - assert(sep); - assert(l); - assert(r); - - if (isempty(sep)) - return -EINVAL; - - x = strstr(s, sep); - if (!x) - return -EINVAL; - - a = strndup(s, x - s); - if (!a) - return -ENOMEM; - - b = strdup(x + strlen(sep)); - if (!b) { - free(a); - return -ENOMEM; - } - - *l = a; - *r = b; - - return 0; -} - -int shall_restore_state(void) { - _cleanup_free_ char *value = NULL; - int r; - - r = get_proc_cmdline_key("systemd.restore_state=", &value); - if (r < 0) - return r; - if (r == 0) - return true; - - return parse_boolean(value) != 0; -} - -int proc_cmdline(char **ret) { - assert(ret); - - if (detect_container() > 0) - return get_process_cmdline(1, 0, false, ret); - else - return read_one_line_file("/proc/cmdline", ret); -} - -int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { - _cleanup_free_ char *line = NULL; - const char *p; - int r; - - assert(parse_item); - - r = proc_cmdline(&line); - if (r < 0) - return r; - - p = line; - for (;;) { - _cleanup_free_ char *word = NULL; - char *value = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); - if (r < 0) - return r; - if (r == 0) - break; - - /* Filter out arguments that are intended only for the - * initrd */ - if (!in_initrd() && startswith(word, "rd.")) - continue; - - value = strchr(word, '='); - if (value) - *(value++) = 0; - - r = parse_item(word, value); - if (r < 0) - return r; - } - - return 0; -} - -int get_proc_cmdline_key(const char *key, char **value) { - _cleanup_free_ char *line = NULL, *ret = NULL; - bool found = false; - const char *p; - int r; - - assert(key); - - r = proc_cmdline(&line); - if (r < 0) - return r; - - p = line; - for (;;) { - _cleanup_free_ char *word = NULL; - const char *e; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); - if (r < 0) - return r; - if (r == 0) - break; - - /* Filter out arguments that are intended only for the - * initrd */ - if (!in_initrd() && startswith(word, "rd.")) - continue; - - if (value) { - e = startswith(word, key); - if (!e) - continue; - - r = free_and_strdup(&ret, e); - if (r < 0) - return r; - - found = true; - } else { - if (streq(word, key)) - found = true; - } - } - - if (value) { - *value = ret; - ret = NULL; - } - - return found; - -} - int container_get_leader(const char *machine, pid_t *pid) { _cleanup_free_ char *s = NULL, *class = NULL; const char *p; @@ -5171,203 +808,6 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int return reset_uid_gid(); } -int getpeercred(int fd, struct ucred *ucred) { - socklen_t n = sizeof(struct ucred); - struct ucred u; - int r; - - assert(fd >= 0); - assert(ucred); - - r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); - if (r < 0) - return -errno; - - if (n != sizeof(struct ucred)) - return -EIO; - - /* Check if the data is actually useful and not suppressed due - * to namespacing issues */ - if (u.pid <= 0) - return -ENODATA; - if (u.uid == UID_INVALID) - return -ENODATA; - if (u.gid == GID_INVALID) - return -ENODATA; - - *ucred = u; - return 0; -} - -int getpeersec(int fd, char **ret) { - socklen_t n = 64; - char *s; - int r; - - assert(fd >= 0); - assert(ret); - - s = new0(char, n); - if (!s) - return -ENOMEM; - - r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); - if (r < 0) { - free(s); - - if (errno != ERANGE) - return -errno; - - s = new0(char, n); - if (!s) - return -ENOMEM; - - r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); - if (r < 0) { - free(s); - return -errno; - } - } - - if (isempty(s)) { - free(s); - return -EOPNOTSUPP; - } - - *ret = s; - return 0; -} - -/* This is much like like mkostemp() but is subject to umask(). */ -int mkostemp_safe(char *pattern, int flags) { - _cleanup_umask_ mode_t u; - int fd; - - assert(pattern); - - u = umask(077); - - fd = mkostemp(pattern, flags); - if (fd < 0) - return -errno; - - return fd; -} - -int open_tmpfile(const char *path, int flags) { - char *p; - int fd; - - assert(path); - -#ifdef O_TMPFILE - /* Try O_TMPFILE first, if it is supported */ - fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); - if (fd >= 0) - return fd; -#endif - - /* Fall back to unguessable name + unlinking */ - p = strjoina(path, "/systemd-tmp-XXXXXX"); - - fd = mkostemp_safe(p, flags); - if (fd < 0) - return fd; - - unlink(p); - return fd; -} - -int fd_warn_permissions(const char *path, int fd) { - struct stat st; - - if (fstat(fd, &st) < 0) - return -errno; - - if (st.st_mode & 0111) - log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); - - if (st.st_mode & 0002) - log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); - - if (getpid() == 1 && (st.st_mode & 0044) != 0044) - log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); - - return 0; -} - -unsigned long personality_from_string(const char *p) { - - /* Parse a personality specifier. We introduce our own - * identifiers that indicate specific ABIs, rather than just - * hints regarding the register size, since we want to keep - * things open for multiple locally supported ABIs for the - * same register size. We try to reuse the ABI identifiers - * used by libseccomp. */ - -#if defined(__x86_64__) - - if (streq(p, "x86")) - return PER_LINUX32; - - if (streq(p, "x86-64")) - return PER_LINUX; - -#elif defined(__i386__) - - if (streq(p, "x86")) - return PER_LINUX; - -#elif defined(__s390x__) - - if (streq(p, "s390")) - return PER_LINUX32; - - if (streq(p, "s390x")) - return PER_LINUX; - -#elif defined(__s390__) - - if (streq(p, "s390")) - return PER_LINUX; -#endif - - return PERSONALITY_INVALID; -} - -const char* personality_to_string(unsigned long p) { - -#if defined(__x86_64__) - - if (p == PER_LINUX32) - return "x86"; - - if (p == PER_LINUX) - return "x86-64"; - -#elif defined(__i386__) - - if (p == PER_LINUX) - return "x86"; - -#elif defined(__s390x__) - - if (p == PER_LINUX) - return "s390x"; - - if (p == PER_LINUX32) - return "s390"; - -#elif defined(__s390__) - - if (p == PER_LINUX) - return "s390"; - -#endif - - return NULL; -} - uint64_t physical_memory(void) { long mem; @@ -5380,1575 +820,21 @@ uint64_t physical_memory(void) { return (uint64_t) mem * (uint64_t) page_size(); } -void hexdump(FILE *f, const void *p, size_t s) { - const uint8_t *b = p; - unsigned n = 0; - - assert(s == 0 || b); - - while (s > 0) { - size_t i; - - fprintf(f, "%04x ", n); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputs(" ", f); - else - fprintf(f, "%02x ", b[i]); - - if (i == 7) - fputc(' ', f); - } - - fputc(' ', f); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputc(' ', f); - else - fputc(isprint(b[i]) ? (char) b[i] : '.', f); - } - - fputc('\n', f); - - if (s < 16) - break; - - n += 16; - b += 16; - s -= 16; - } -} - int update_reboot_param_file(const char *param) { int r = 0; if (param) { - r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); if (r < 0) - log_error("Failed to write reboot param to " - REBOOT_PARAM_FILE": %s", strerror(-r)); - } else - unlink(REBOOT_PARAM_FILE); - - return r; -} - -int umount_recursive(const char *prefix, int flags) { - bool again; - int n = 0, r; - - /* Try to umount everything recursively below a - * directory. Also, take care of stacked mounts, and keep - * unmounting them until they are gone. */ - - do { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - - again = false; - r = 0; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%*s " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options 2 */ - "%*[^\n]", /* some rubbish at the end */ - &path); - if (k != 1) { - if (k == EOF) - break; - - continue; - } - - r = cunescape(path, UNESCAPE_RELAX, &p); - if (r < 0) - return r; - - if (!path_startswith(p, prefix)) - continue; - - if (umount2(p, flags) < 0) { - r = -errno; - continue; - } - - again = true; - n++; - - break; - } - - } while (again); - - return r ? r : n; -} - -static int get_mount_flags(const char *path, unsigned long *flags) { - struct statvfs buf; - - if (statvfs(path, &buf) < 0) - return -errno; - *flags = buf.f_flag; - return 0; -} - -int bind_remount_recursive(const char *prefix, bool ro) { - _cleanup_set_free_free_ Set *done = NULL; - _cleanup_free_ char *cleaned = NULL; - int r; - - /* Recursively remount a directory (and all its submounts) - * read-only or read-write. If the directory is already - * mounted, we reuse the mount and simply mark it - * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write - * operation). If it isn't we first make it one. Afterwards we - * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all - * submounts we can access, too. When mounts are stacked on - * the same mount point we only care for each individual - * "top-level" mount on each point, as we cannot - * influence/access the underlying mounts anyway. We do not - * have any effect on future submounts that might get - * propagated, they migt be writable. This includes future - * submounts that have been triggered via autofs. */ - - cleaned = strdup(prefix); - if (!cleaned) - return -ENOMEM; - - path_kill_slashes(cleaned); - - done = set_new(&string_hash_ops); - if (!done) - return -ENOMEM; - - for (;;) { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - _cleanup_set_free_free_ Set *todo = NULL; - bool top_autofs = false; - char *x; - unsigned long orig_flags; - - todo = set_new(&string_hash_ops); - if (!todo) - return -ENOMEM; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options (superblock) */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%ms " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options (bind mount) */ - "%*[^\n]", /* some rubbish at the end */ - &path, - &type); - if (k != 2) { - if (k == EOF) - break; - - continue; - } - - r = cunescape(path, UNESCAPE_RELAX, &p); - if (r < 0) - return r; - - /* Let's ignore autofs mounts. If they aren't - * triggered yet, we want to avoid triggering - * them, as we don't make any guarantees for - * future submounts anyway. If they are - * already triggered, then we will find - * another entry for this. */ - if (streq(type, "autofs")) { - top_autofs = top_autofs || path_equal(cleaned, p); - continue; - } - - if (path_startswith(p, cleaned) && - !set_contains(done, p)) { - - r = set_consume(todo, p); - p = NULL; - - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - } - - /* If we have no submounts to process anymore and if - * the root is either already done, or an autofs, we - * are done */ - if (set_isempty(todo) && - (top_autofs || set_contains(done, cleaned))) - return 0; - - if (!set_contains(done, cleaned) && - !set_contains(todo, cleaned)) { - /* The prefix directory itself is not yet a - * mount, make it one. */ - if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0) - return -errno; - - orig_flags = 0; - (void) get_mount_flags(cleaned, &orig_flags); - orig_flags &= ~MS_RDONLY; - - if (mount(NULL, prefix, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) - return -errno; - - x = strdup(cleaned); - if (!x) - return -ENOMEM; - - r = set_consume(done, x); - if (r < 0) - return r; - } - - while ((x = set_steal_first(todo))) { - - r = set_consume(done, x); - if (r == -EEXIST || r == 0) - continue; - if (r < 0) - return r; - - /* Try to reuse the original flag set, but - * don't care for errors, in case of - * obstructed mounts */ - orig_flags = 0; - (void) get_mount_flags(x, &orig_flags); - orig_flags &= ~MS_RDONLY; - - if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { - - /* Deal with mount points that are - * obstructed by a later mount */ - - if (errno != ENOENT) - return -errno; - } - - } - } -} - -int fflush_and_check(FILE *f) { - assert(f); - - errno = 0; - fflush(f); - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; -} - -int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { - const char *fn; - char *t; - - assert(p); - assert(ret); - - /* - * Turns this: - * /foo/bar/waldo - * - * Into this: - * /foo/bar/.#<extra>waldoXXXXXX - */ - - fn = basename(p); - if (!filename_is_valid(fn)) - return -EINVAL; - - if (extra == NULL) - extra = ""; - - t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); - if (!t) - return -ENOMEM; - - strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); - - *ret = path_kill_slashes(t); - return 0; -} - -int tempfn_random(const char *p, const char *extra, char **ret) { - const char *fn; - char *t, *x; - uint64_t u; - unsigned i; - - assert(p); - assert(ret); - - /* - * Turns this: - * /foo/bar/waldo - * - * Into this: - * /foo/bar/.#<extra>waldobaa2a261115984a9 - */ - - fn = basename(p); - if (!filename_is_valid(fn)) - return -EINVAL; - - if (!extra) - extra = ""; - - t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); - if (!t) - return -ENOMEM; - - x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn); - - u = random_u64(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(u & 0xF); - u >>= 4; - } - - *x = 0; - - *ret = path_kill_slashes(t); - return 0; -} - -int tempfn_random_child(const char *p, const char *extra, char **ret) { - char *t, *x; - uint64_t u; - unsigned i; - - assert(p); - assert(ret); - - /* Turns this: - * /foo/bar/waldo - * Into this: - * /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0 - */ - - if (!extra) - extra = ""; - - t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1); - if (!t) - return -ENOMEM; - - x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); - - u = random_u64(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(u & 0xF); - u >>= 4; - } - - *x = 0; - - *ret = path_kill_slashes(t); - return 0; -} - -int take_password_lock(const char *root) { - - struct flock flock = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; - - const char *path; - int fd, r; - - /* This is roughly the same as lckpwdf(), but not as awful. We - * don't want to use alarm() and signals, hence we implement - * our own trivial version of this. - * - * Note that shadow-utils also takes per-database locks in - * addition to lckpwdf(). However, we don't given that they - * are redundant as they they invoke lckpwdf() first and keep - * it during everything they do. The per-database locks are - * awfully racy, and thus we just won't do them. */ - - if (root) - path = strjoina(root, "/etc/.pwd.lock"); - else - path = "/etc/.pwd.lock"; - - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); - if (fd < 0) - return -errno; - - r = fcntl(fd, F_SETLKW, &flock); - if (r < 0) { - safe_close(fd); - return -errno; - } - - return fd; -} - -int is_symlink(const char *path) { - struct stat info; - - if (lstat(path, &info) < 0) - return -errno; - - return !!S_ISLNK(info.st_mode); -} - -int is_dir(const char* path, bool follow) { - struct stat st; - int r; - - if (follow) - r = stat(path, &st); - else - r = lstat(path, &st); - if (r < 0) - return -errno; - - return !!S_ISDIR(st.st_mode); -} - -int is_device_node(const char *path) { - struct stat info; - - if (lstat(path, &info) < 0) - return -errno; - - return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); -} - -int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { - _cleanup_free_ char *s = NULL; - size_t allocated = 0, sz = 0; - int r; - - enum { - START, - VALUE, - VALUE_ESCAPE, - SINGLE_QUOTE, - SINGLE_QUOTE_ESCAPE, - DOUBLE_QUOTE, - DOUBLE_QUOTE_ESCAPE, - SEPARATOR, - } state = START; - - assert(p); - assert(ret); - - if (!separators) - separators = WHITESPACE; - - /* Bail early if called after last value or with no input */ - if (!*p) - goto finish_force_terminate; - - /* Parses the first word of a string, and returns it in - * *ret. Removes all quotes in the process. When parsing fails - * (because of an uneven number of quotes or similar), leaves - * the pointer *p at the first invalid character. */ - - for (;;) { - char c = **p; - - switch (state) { - - case START: - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - - if (c == 0) - goto finish_force_terminate; - else if (strchr(separators, c)) { - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; - goto finish_force_next; - } - break; - } - - /* We found a non-blank character, so we will always - * want to return a string (even if it is empty), - * allocate it here. */ - if (!GREEDY_REALLOC(s, allocated, sz+1)) - return -ENOMEM; - - state = VALUE; - /* fallthrough */ - - case VALUE: - if (c == 0) - goto finish_force_terminate; - else if (c == '\'' && (flags & EXTRACT_QUOTES)) - state = SINGLE_QUOTE; - else if (c == '\\') - state = VALUE_ESCAPE; - else if (c == '\"' && (flags & EXTRACT_QUOTES)) - state = DOUBLE_QUOTE; - else if (strchr(separators, c)) { - if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) { - (*p) ++; - goto finish_force_next; - } - state = SEPARATOR; - } else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case SINGLE_QUOTE: - if (c == 0) { - if (flags & EXTRACT_RELAX) - goto finish_force_terminate; - return -EINVAL; - } else if (c == '\'') - state = VALUE; - else if (c == '\\') - state = SINGLE_QUOTE_ESCAPE; - else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case DOUBLE_QUOTE: - if (c == 0) - return -EINVAL; - else if (c == '\"') - state = VALUE; - else if (c == '\\') - state = DOUBLE_QUOTE_ESCAPE; - else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case SINGLE_QUOTE_ESCAPE: - case DOUBLE_QUOTE_ESCAPE: - case VALUE_ESCAPE: - if (!GREEDY_REALLOC(s, allocated, sz+7)) - return -ENOMEM; - - if (c == 0) { - if ((flags & EXTRACT_CUNESCAPE_RELAX) && - (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) { - /* If we find an unquoted trailing backslash and we're in - * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the - * output. - * - * Unbalanced quotes will only be allowed in EXTRACT_RELAX - * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. - */ - s[sz++] = '\\'; - goto finish_force_terminate; - } - if (flags & EXTRACT_RELAX) - goto finish_force_terminate; - return -EINVAL; - } - - if (flags & EXTRACT_CUNESCAPE) { - uint32_t u; - - r = cunescape_one(*p, (size_t) -1, &c, &u); - if (r < 0) { - if (flags & EXTRACT_CUNESCAPE_RELAX) { - s[sz++] = '\\'; - s[sz++] = c; - goto end_escape; - } - return -EINVAL; - } - - (*p) += r - 1; - - if (c != 0) - s[sz++] = c; /* normal explicit char */ - else - sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ - } else - s[sz++] = c; - -end_escape: - state = (state == SINGLE_QUOTE_ESCAPE) ? SINGLE_QUOTE : - (state == DOUBLE_QUOTE_ESCAPE) ? DOUBLE_QUOTE : - VALUE; - break; - - case SEPARATOR: - if (c == 0) - goto finish_force_terminate; - if (!strchr(separators, c)) - goto finish; - break; - } - - (*p) ++; - } - -finish_force_terminate: - *p = NULL; -finish: - if (!s) { - *p = NULL; - *ret = NULL; - return 0; - } - -finish_force_next: - s[sz] = 0; - *ret = s; - s = NULL; - - return 1; -} - -int extract_first_word_and_warn( - const char **p, - char **ret, - const char *separators, - ExtractFlags flags, - const char *unit, - const char *filename, - unsigned line, - const char *rvalue) { - /* Try to unquote it, if it fails, warn about it and try again but this - * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim - * in invalid escape sequences. */ - const char *save; - int r; - - save = *p; - r = extract_first_word(p, ret, separators, flags); - if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) { - /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ - *p = save; - r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unbalanced quoting in command line, ignoring: \"%s\"", rvalue); - else - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, - "Invalid escape sequences in command line: \"%s\"", rvalue); - } - return r; -} - -int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) { - va_list ap; - char **l; - int n = 0, i, c, r; - - /* Parses a number of words from a string, stripping any - * quotes if necessary. */ - - assert(p); - - /* Count how many words are expected */ - va_start(ap, flags); - for (;;) { - if (!va_arg(ap, char **)) - break; - n++; - } - va_end(ap); - - if (n <= 0) - return 0; - - /* Read all words into a temporary array */ - l = newa0(char*, n); - for (c = 0; c < n; c++) { - - r = extract_first_word(p, &l[c], separators, flags); - if (r < 0) { - int j; - - for (j = 0; j < c; j++) - free(l[j]); - - return r; - } - - if (r == 0) - break; - } - - /* If we managed to parse all words, return them in the passed - * in parameters */ - va_start(ap, flags); - for (i = 0; i < n; i++) { - char **v; - - v = va_arg(ap, char **); - assert(v); - - *v = l[i]; - } - va_end(ap); - - return c; -} - -int free_and_strdup(char **p, const char *s) { - char *t; - - assert(p); - - /* Replaces a string pointer with an strdup()ed new string, - * possibly freeing the old one. */ - - if (streq_ptr(*p, s)) - return 0; - - if (s) { - t = strdup(s); - if (!t) - return -ENOMEM; - } else - t = NULL; - - free(*p); - *p = t; - - return 1; -} - -int ptsname_malloc(int fd, char **ret) { - size_t l = 100; - - assert(fd >= 0); - assert(ret); - - for (;;) { - char *c; - - c = new(char, l); - if (!c) - return -ENOMEM; - - if (ptsname_r(fd, c, l) == 0) { - *ret = c; - return 0; - } - if (errno != ERANGE) { - free(c); - return -errno; - } - - free(c); - l *= 2; - } -} - -int openpt_in_namespace(pid_t pid, int flags) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1; - _cleanup_close_pair_ int pair[2] = { -1, -1 }; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - siginfo_t si; - pid_t child; - int r; - - assert(pid > 0); - - r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd); - if (r < 0) - return r; - - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0) - return -errno; - - child = fork(); - if (child < 0) - return -errno; - - if (child == 0) { - int master; - - pair[0] = safe_close(pair[0]); - - r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd); - if (r < 0) - _exit(EXIT_FAILURE); - - master = posix_openpt(flags); - if (master < 0) - _exit(EXIT_FAILURE); - - if (unlockpt(master) < 0) - _exit(EXIT_FAILURE); - - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &master, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) - _exit(EXIT_FAILURE); - - _exit(EXIT_SUCCESS); - } - - pair[1] = safe_close(pair[1]); - - r = wait_for_terminate(child, &si); - if (r < 0) - return r; - if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) - return -EIO; - - if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0) - return -errno; - - CMSG_FOREACH(cmsg, &mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - int *fds; - unsigned n_fds; - - fds = (int*) CMSG_DATA(cmsg); - n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - - if (n_fds != 1) { - close_many(fds, n_fds); - return -EIO; - } - - return fds[0]; - } - - return -EIO; -} - -ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) { - _cleanup_close_ int fd = -1; - ssize_t l; - - /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ - - fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOATIME|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); - if (fd < 0) - return -errno; - - l = fgetxattr(fd, attribute, value, size); - if (l < 0) - return -errno; - - return l; -} - -static int parse_crtime(le64_t le, usec_t *usec) { - uint64_t u; - - assert(usec); - - u = le64toh(le); - if (u == 0 || u == (uint64_t) -1) - return -EIO; - - *usec = (usec_t) u; - return 0; -} - -int fd_getcrtime(int fd, usec_t *usec) { - le64_t le; - ssize_t n; - - assert(fd >= 0); - assert(usec); - - /* Until Linux gets a real concept of birthtime/creation time, - * let's fake one with xattrs */ - - n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le)); - if (n < 0) - return -errno; - if (n != sizeof(le)) - return -EIO; - - return parse_crtime(le, usec); -} - -int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) { - le64_t le; - ssize_t n; - - n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags); - if (n < 0) - return -errno; - if (n != sizeof(le)) - return -EIO; - - return parse_crtime(le, usec); -} - -int path_getcrtime(const char *p, usec_t *usec) { - le64_t le; - ssize_t n; - - assert(p); - assert(usec); - - n = getxattr(p, "user.crtime_usec", &le, sizeof(le)); - if (n < 0) - return -errno; - if (n != sizeof(le)) - return -EIO; - - return parse_crtime(le, usec); -} - -int fd_setcrtime(int fd, usec_t usec) { - le64_t le; - - assert(fd >= 0); - - if (usec <= 0) - usec = now(CLOCK_REALTIME); - - le = htole64((uint64_t) usec); - if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0) - return -errno; - - return 0; -} - -int same_fd(int a, int b) { - struct stat sta, stb; - pid_t pid; - int r, fa, fb; - - assert(a >= 0); - assert(b >= 0); - - /* Compares two file descriptors. Note that semantics are - * quite different depending on whether we have kcmp() or we - * don't. If we have kcmp() this will only return true for - * dup()ed file descriptors, but not otherwise. If we don't - * have kcmp() this will also return true for two fds of the same - * file, created by separate open() calls. Since we use this - * call mostly for filtering out duplicates in the fd store - * this difference hopefully doesn't matter too much. */ - - if (a == b) - return true; - - /* Try to use kcmp() if we have it. */ - pid = getpid(); - r = kcmp(pid, pid, KCMP_FILE, a, b); - if (r == 0) - return true; - if (r > 0) - return false; - if (errno != ENOSYS) - return -errno; - - /* We don't have kcmp(), use fstat() instead. */ - if (fstat(a, &sta) < 0) - return -errno; - - if (fstat(b, &stb) < 0) - return -errno; - - if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) - return false; - - /* We consider all device fds different, since two device fds - * might refer to quite different device contexts even though - * they share the same inode and backing dev_t. */ - - if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) - return false; - - if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) - return false; - - /* The fds refer to the same inode on disk, let's also check - * if they have the same fd flags. This is useful to - * distinguish the read and write side of a pipe created with - * pipe(). */ - fa = fcntl(a, F_GETFL); - if (fa < 0) - return -errno; - - fb = fcntl(b, F_GETFL); - if (fb < 0) - return -errno; - - return fa == fb; -} - -int chattr_fd(int fd, unsigned value, unsigned mask) { - unsigned old_attr, new_attr; - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - /* Explicitly check whether this is a regular file or - * directory. If it is anything else (such as a device node or - * fifo), then the ioctl will not hit the file systems but - * possibly drivers, where the ioctl might have different - * effects. Notably, DRM is using the same ioctl() number. */ - - if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) - return -ENOTTY; - - if (mask == 0) - return 0; - - if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) - return -errno; - - new_attr = (old_attr & ~mask) | (value & mask); - if (new_attr == old_attr) - return 0; - - if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) - return -errno; - - return 1; -} - -int chattr_path(const char *p, unsigned value, unsigned mask) { - _cleanup_close_ int fd = -1; - - assert(p); - - if (mask == 0) - return 0; - - fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd < 0) - return -errno; - - return chattr_fd(fd, value, mask); -} - -int read_attr_fd(int fd, unsigned *ret) { - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) - return -ENOTTY; - - if (ioctl(fd, FS_IOC_GETFLAGS, ret) < 0) - return -errno; - - return 0; -} - -int read_attr_path(const char *p, unsigned *ret) { - _cleanup_close_ int fd = -1; - - assert(p); - assert(ret); - - fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd < 0) - return -errno; - - return read_attr_fd(fd, ret); -} - -static size_t nul_length(const uint8_t *p, size_t sz) { - size_t n = 0; - - while (sz > 0) { - if (*p != 0) - break; - - n++; - p++; - sz--; - } - - return n; -} - -ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { - const uint8_t *q, *w, *e; - ssize_t l; - - q = w = p; - e = q + sz; - while (q < e) { - size_t n; - - n = nul_length(q, e - q); - - /* If there are more than the specified run length of - * NUL bytes, or if this is the beginning or the end - * of the buffer, then seek instead of write */ - if ((n > run_length) || - (n > 0 && q == p) || - (n > 0 && q + n >= e)) { - if (q > w) { - l = write(fd, w, q - w); - if (l < 0) - return -errno; - if (l != q -w) - return -EIO; - } - - if (lseek(fd, n, SEEK_CUR) == (off_t) -1) - return -errno; - - q += n; - w = q; - } else if (n > 0) - q += n; - else - q ++; - } - - if (q > w) { - l = write(fd, w, q - w); - if (l < 0) - return -errno; - if (l != q - w) - return -EIO; - } - - return q - (const uint8_t*) p; -} - -void sigkill_wait(pid_t *pid) { - if (!pid) - return; - if (*pid <= 1) - return; - - if (kill(*pid, SIGKILL) > 0) - (void) wait_for_terminate(*pid, NULL); -} - -int syslog_parse_priority(const char **p, int *priority, bool with_facility) { - int a = 0, b = 0, c = 0; - int k; - - assert(p); - assert(*p); - assert(priority); - - if ((*p)[0] != '<') - return 0; - - if (!strchr(*p, '>')) - return 0; - - if ((*p)[2] == '>') { - c = undecchar((*p)[1]); - k = 3; - } else if ((*p)[3] == '>') { - b = undecchar((*p)[1]); - c = undecchar((*p)[2]); - k = 4; - } else if ((*p)[4] == '>') { - a = undecchar((*p)[1]); - b = undecchar((*p)[2]); - c = undecchar((*p)[3]); - k = 5; + return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m"); } else - return 0; - - if (a < 0 || b < 0 || c < 0 || - (!with_facility && (a || b || c > 7))) - return 0; - - if (with_facility) - *priority = a*100 + b*10 + c; - else - *priority = (*priority & LOG_FACMASK) | c; - - *p += k; - return 1; -} - -ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { - size_t i; - - if (!key) - return -1; - - for (i = 0; i < len; ++i) - if (streq_ptr(table[i], key)) - return (ssize_t) i; - - return -1; -} - -void cmsg_close_all(struct msghdr *mh) { - struct cmsghdr *cmsg; - - assert(mh); - - CMSG_FOREACH(cmsg, mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) - close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); -} - -int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { - struct stat buf; - int ret; - - ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE); - if (ret >= 0) - return 0; - - /* renameat2() exists since Linux 3.15, btrfs added support for it later. - * If it is not implemented, fallback to another method. */ - if (!IN_SET(errno, EINVAL, ENOSYS)) - return -errno; - - /* The link()/unlink() fallback does not work on directories. But - * renameat() without RENAME_NOREPLACE gives the same semantics on - * directories, except when newpath is an *empty* directory. This is - * good enough. */ - ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW); - if (ret >= 0 && S_ISDIR(buf.st_mode)) { - ret = renameat(olddirfd, oldpath, newdirfd, newpath); - return ret >= 0 ? 0 : -errno; - } - - /* If it is not a directory, use the link()/unlink() fallback. */ - ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0); - if (ret < 0) - return -errno; - - ret = unlinkat(olddirfd, oldpath, 0); - if (ret < 0) { - /* backup errno before the following unlinkat() alters it */ - ret = errno; - (void) unlinkat(newdirfd, newpath, 0); - errno = ret; - return -errno; - } - - return 0; -} - -static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { - assert(bad); - - for (; *s; s++) { - if (*s == '\\' || strchr(bad, *s)) - *(t++) = '\\'; - - *(t++) = *s; - } - - return t; -} - -char *shell_escape(const char *s, const char *bad) { - char *r, *t; - - r = new(char, strlen(s)*2+1); - if (!r) - return NULL; - - t = strcpy_backslash_escaped(r, s, bad); - *t = 0; - - return r; -} - -char *shell_maybe_quote(const char *s) { - const char *p; - char *r, *t; - - assert(s); - - /* Encloses a string in double quotes if necessary to make it - * OK as shell string. */ - - for (p = s; *p; p++) - if (*p <= ' ' || - *p >= 127 || - strchr(SHELL_NEED_QUOTES, *p)) - break; - - if (!*p) - return strdup(s); - - r = new(char, 1+strlen(s)*2+1+1); - if (!r) - return NULL; - - t = r; - *(t++) = '"'; - t = mempcpy(t, s, p - s); - - t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); - - *(t++)= '"'; - *t = 0; - - return r; -} - -int parse_mode(const char *s, mode_t *ret) { - char *x; - long l; + (void) unlink(REBOOT_PARAM_FILE); - assert(s); - assert(ret); - - errno = 0; - l = strtol(s, &x, 8); - if (errno != 0) - return -errno; - - if (!x || x == s || *x) - return -EINVAL; - if (l < 0 || l > 07777) - return -ERANGE; - - *ret = (mode_t) l; return 0; } -int mount_move_root(const char *path) { - assert(path); - - if (chdir(path) < 0) - return -errno; - - if (mount(path, "/", NULL, MS_MOVE, NULL) < 0) - return -errno; - - if (chroot(".") < 0) - return -errno; - - if (chdir("/") < 0) - return -errno; - +int version(void) { + puts(PACKAGE_STRING "\n" + SYSTEMD_FEATURES); return 0; } - -int reset_uid_gid(void) { - - if (setgroups(0, NULL) < 0) - return -errno; - - if (setresgid(0, 0, 0) < 0) - return -errno; - - if (setresuid(0, 0, 0) < 0) - return -errno; - - return 0; -} - -int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { - char *v; - size_t l; - ssize_t n; - - assert(path); - assert(name); - assert(value); - - for (l = 100; ; l = (size_t) n + 1) { - v = new0(char, l); - if (!v) - return -ENOMEM; - - if (allow_symlink) - n = lgetxattr(path, name, v, l); - else - n = getxattr(path, name, v, l); - - if (n >= 0 && (size_t) n < l) { - *value = v; - return n; - } - - free(v); - - if (n < 0 && errno != ERANGE) - return -errno; - - if (allow_symlink) - n = lgetxattr(path, name, NULL, 0); - else - n = getxattr(path, name, NULL, 0); - if (n < 0) - return -errno; - } -} - -int fgetxattr_malloc(int fd, const char *name, char **value) { - char *v; - size_t l; - ssize_t n; - - assert(fd >= 0); - assert(name); - assert(value); - - for (l = 100; ; l = (size_t) n + 1) { - v = new0(char, l); - if (!v) - return -ENOMEM; - - n = fgetxattr(fd, name, v, l); - - if (n >= 0 && (size_t) n < l) { - *value = v; - return n; - } - - free(v); - - if (n < 0 && errno != ERANGE) - return -errno; - - n = fgetxattr(fd, name, NULL, 0); - if (n < 0) - return -errno; - } -} - -int send_one_fd(int transport_fd, int fd) { - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - ssize_t k; - - assert(transport_fd >= 0); - assert(fd >= 0); - - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = CMSG_SPACE(sizeof(int)); - k = sendmsg(transport_fd, &mh, MSG_NOSIGNAL); - if (k < 0) - return -errno; - - return 0; -} - -int receive_one_fd(int transport_fd) { - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - ssize_t k; - - assert(transport_fd >= 0); - - /* - * Receive a single FD via @transport_fd. We don't care for the - * transport-type, but the caller must assure that no other CMSG types - * than SCM_RIGHTS is enabled. We also retrieve a single FD at most, so - * for packet-based transports, the caller must ensure to send only a - * single FD per packet. - * This is best used in combination with send_one_fd(). - */ - - k = recvmsg(transport_fd, &mh, MSG_NOSIGNAL | MSG_CMSG_CLOEXEC); - if (k < 0) - return -errno; - - cmsg = CMSG_FIRSTHDR(&mh); - if (!cmsg || CMSG_NXTHDR(&mh, cmsg) || - cmsg->cmsg_level != SOL_SOCKET || - cmsg->cmsg_type != SCM_RIGHTS || - cmsg->cmsg_len != CMSG_LEN(sizeof(int)) || - *(const int *)CMSG_DATA(cmsg) < 0) { - cmsg_close_all(&mh); - return -EIO; - } - - return *(const int *)CMSG_DATA(cmsg); -} diff --git a/src/basic/util.h b/src/basic/util.h index 56d9f037bf..d9d2f72b75 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -22,13 +22,10 @@ ***/ #include <alloca.h> -#include <dirent.h> #include <fcntl.h> #include <inttypes.h> #include <limits.h> #include <locale.h> -#include <mntent.h> -#include <sched.h> #include <stdarg.h> #include <stdbool.h> #include <stddef.h> @@ -47,49 +44,9 @@ #include "missing.h" #include "time-util.h" -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;" -#define GLOB_CHARS "*?[" - -/* What characters are special in the shell? */ -/* must be escaped outside and inside double-quotes */ -#define SHELL_NEED_ESCAPE "\"\\`$" -/* can be escaped or double-quoted */ -#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;" - -#define FORMAT_BYTES_MAX 8 - size_t page_size(void) _pure_; #define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) -#define streq(a,b) (strcmp((a),(b)) == 0) -#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) -#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) -#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) - -bool streq_ptr(const char *a, const char *b) _pure_; -int strcmp_ptr(const char *a, const char *b) _pure_; - -#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) - -#define new0(t, n) ((t*) calloc((n), sizeof(t))) - -#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) - -#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) - -#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) - -#define malloc0(n) (calloc(1, (n))) - -static inline void *mfree(void *memory) { - free(memory); - return NULL; -} - static inline const char* yes_no(bool b) { return b ? "yes" : "no"; } @@ -102,351 +59,13 @@ static inline const char* one_zero(bool b) { return b ? "1" : "0"; } -static inline const char* strempty(const char *s) { - return s ? s : ""; -} - -static inline const char* strnull(const char *s) { - return s ? s : "(null)"; -} - -static inline const char *strna(const char *s) { - return s ? s : "n/a"; -} - -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - -static inline char *startswith(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -static inline char *startswith_no_case(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncasecmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -char *endswith(const char *s, const char *postfix) _pure_; -char *endswith_no_case(const char *s, const char *postfix) _pure_; - -char *first_word(const char *s, const char *word) _pure_; - -int close_nointr(int fd); -int safe_close(int fd); -void safe_close_pair(int p[]); - -void close_many(const int fds[], unsigned n_fd); - -int fclose_nointr(FILE *f); -FILE* safe_fclose(FILE *f); -DIR* safe_closedir(DIR *f); - -int parse_size(const char *t, uint64_t base, uint64_t *size); - -int parse_boolean(const char *v) _pure_; -int parse_pid(const char *s, pid_t* ret_pid); -int parse_uid(const char *s, uid_t* ret_uid); -#define parse_gid(s, ret_gid) parse_uid(s, ret_gid) - -bool uid_is_valid(uid_t uid); - -static inline bool gid_is_valid(gid_t gid) { - return uid_is_valid((uid_t) gid); -} - -int safe_atou(const char *s, unsigned *ret_u); -int safe_atoi(const char *s, int *ret_i); - -int safe_atollu(const char *s, unsigned long long *ret_u); -int safe_atolli(const char *s, long long int *ret_i); - -int safe_atod(const char *s, double *ret_d); - -int safe_atou8(const char *s, uint8_t *ret); - -#if LONG_MAX == INT_MAX -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(int)); - return safe_atoi(s, (int*) ret_u); -} -#else -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_u); -} -#endif - -static inline int safe_atou32(const char *s, uint32_t *ret_u) { - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} - -static inline int safe_atoi32(const char *s, int32_t *ret_i) { - assert_cc(sizeof(int32_t) == sizeof(int)); - return safe_atoi(s, (int*) ret_i); -} - -static inline int safe_atou64(const char *s, uint64_t *ret_u) { - assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} - -static inline int safe_atoi64(const char *s, int64_t *ret_i) { - assert_cc(sizeof(int64_t) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_i); -} - -int safe_atou16(const char *s, uint16_t *ret); -int safe_atoi16(const char *s, int16_t *ret); - -const char* split(const char **state, size_t *l, const char *separator, bool quoted); - -#define FOREACH_WORD(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, false, state) - -#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - _FOREACH_WORD(word, length, s, separator, false, state) - -#define FOREACH_WORD_QUOTED(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, true, state) - -#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ - for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) - -char *strappend(const char *s, const char *suffix); -char *strnappend(const char *s, const char *suffix, size_t length); - -int readlinkat_malloc(int fd, const char *p, char **ret); -int readlink_malloc(const char *p, char **r); -int readlink_value(const char *p, char **ret); -int readlink_and_make_absolute(const char *p, char **r); -int readlink_and_canonicalize(const char *p, char **r); - -char *strstrip(char *s); -char *delete_chars(char *s, const char *bad); -char *truncate_nl(char *s); - -char *file_in_same_dir(const char *path, const char *filename); - -int rmdir_parents(const char *path, const char *stop); - -char hexchar(int x) _const_; -int unhexchar(char c) _const_; -char octchar(int x) _const_; -int unoctchar(char c) _const_; -char decchar(int x) _const_; -int undecchar(char c) _const_; -char base32hexchar(int x) _const_; -int unbase32hexchar(char c) _const_; -char base64char(int x) _const_; -int unbase64char(char c) _const_; - -char *cescape(const char *s); -size_t cescape_char(char c, char *buf); - -typedef enum UnescapeFlags { - UNESCAPE_RELAX = 1, -} UnescapeFlags; - -int cunescape(const char *s, UnescapeFlags flags, char **ret); -int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); -int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); - -char *xescape(const char *s, const char *bad); - -char *ascii_strlower(char *path); - -bool dirent_is_file(const struct dirent *de) _pure_; -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; - -bool hidden_file(const char *filename) _pure_; - -bool chars_intersect(const char *a, const char *b) _pure_; - -/* For basic lookup tables with strictly enumerated entries */ -#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - scope const char *name##_to_string(type i) { \ - if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ - return NULL; \ - return name##_table[i]; \ - } - -ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); - -#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - scope type name##_from_string(const char *s) { \ - return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ - } - -#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ - _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) - -/* For string conversions where numbers are also acceptable */ -#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ - int name##_to_string_alloc(type i, char **str) { \ - char *s; \ - if (i < 0 || i > max) \ - return -ERANGE; \ - if (i < (type) ELEMENTSOF(name##_table)) { \ - s = strdup(name##_table[i]); \ - if (!s) \ - return -ENOMEM; \ - } else { \ - if (asprintf(&s, "%i", i) < 0) \ - return -ENOMEM; \ - } \ - *str = s; \ - return 0; \ - } \ - type name##_from_string(const char *s) { \ - type i; \ - unsigned u = 0; \ - if (!s) \ - return (type) -1; \ - for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ - if (streq_ptr(name##_table[i], s)) \ - return i; \ - if (safe_atou(s, &u) >= 0 && u <= max) \ - return (type) u; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -int fd_nonblock(int fd, bool nonblock); -int fd_cloexec(int fd, bool cloexec); - -int close_all_fds(const int except[], unsigned n_except); - -bool fstype_is_network(const char *fstype); - -int flush_fd(int fd); - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path); - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); -int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); -int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); - -bool is_device_path(const char *path); - -int dir_is_empty(const char *path); -char* dirname_malloc(const char *path); - -char* lookup_uid(uid_t uid); -char* getlogname_malloc(void); -char* getusername_malloc(void); - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid); - -bool is_temporary_fs(const struct statfs *s) _pure_; -int fd_is_temporary_fs(int fd); - -int pipe_eof(int fd); - -DEFINE_TRIVIAL_CLEANUP_FUNC(cpu_set_t*, CPU_FREE); -#define _cleanup_cpu_free_ _cleanup_(CPU_FREEp) - -cpu_set_t* cpu_set_malloc(unsigned *ncpus); -int parse_cpu_set(const char *rvalue, cpu_set_t **cpu_set, const char *unit, const char *filename, unsigned line, const char *lvalue); - -#define xsprintf(buf, fmt, ...) \ - assert_message_se((size_t) snprintf(buf, ELEMENTSOF(buf), fmt, __VA_ARGS__) < ELEMENTSOF(buf), \ - "xsprintf: " #buf "[] must be big enough") - -int files_same(const char *filea, const char *fileb); - -int running_in_chroot(void); - -char *ellipsize(const char *s, size_t length, unsigned percent); - /* bytes columns */ -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent); - -int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); -int touch(const char *path); - -noreturn void freeze(void); - -bool null_or_empty(struct stat *st) _pure_; -int null_or_empty_path(const char *fn); -int null_or_empty_fd(int fd); - -DIR *xopendirat(int dirfd, const char *name, int flags); - -char *fstab_node_to_udev_node(const char *p); - void execute_directories(const char* const* directories, usec_t timeout, char *argv[]); -bool nulstr_contains(const char*nulstr, const char *needle); - bool plymouth_running(void); -char* strshorten(char *s, size_t l); - -int symlink_idempotent(const char *from, const char *to); - -int symlink_atomic(const char *from, const char *to); -int mknod_atomic(const char *path, mode_t mode, dev_t dev); -int mkfifo_atomic(const char *path, mode_t mode); - -int fchmod_umask(int fd, mode_t mode); - bool display_is_local(const char *display) _pure_; int socket_from_display(const char *display, char **path); -int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); -int get_group_creds(const char **groupname, gid_t *gid); - -int in_gid(gid_t gid); -int in_group(const char *name); - -char* uid_to_name(uid_t uid); -char* gid_to_name(gid_t gid); - -int glob_exists(const char *path); -int glob_extend(char ***strv, const char *path); - -int dirent_ensure_type(DIR *d, struct dirent *de); - -int get_files_in_directory(const char *path, char ***list); - -char *strjoin(const char *x, ...) _sentinel_; - -bool is_main_thread(void); - -static inline bool _pure_ in_charset(const char *s, const char* charset) { - assert(s); - assert(charset); - return s[strspn(s, charset)] == '\0'; -} - int block_get_whole_disk(dev_t d, dev_t *ret); #define NULSTR_FOREACH(i, l) \ @@ -455,27 +74,6 @@ int block_get_whole_disk(dev_t d, dev_t *ret); #define NULSTR_FOREACH_PAIR(i, j, l) \ for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) -int ioprio_class_to_string_alloc(int i, char **s); -int ioprio_class_from_string(const char *s); - -const char *sigchld_code_to_string(int i) _const_; -int sigchld_code_from_string(const char *s) _pure_; - -int log_facility_unshifted_to_string_alloc(int i, char **s); -int log_facility_unshifted_from_string(const char *s); - -int log_level_to_string_alloc(int i, char **s); -int log_level_from_string(const char *s); - -int sched_policy_to_string_alloc(int i, char **s); -int sched_policy_from_string(const char *s); - -const char *rlimit_to_string(int i) _const_; -int rlimit_from_string(const char *s) _pure_; - -int ip_tos_to_string_alloc(int i, char **s); -int ip_tos_from_string(const char *s); - extern int saved_argc; extern char **saved_argv; @@ -483,182 +81,36 @@ bool kexec_loaded(void); int prot_from_flags(int flags) _const_; -char *format_bytes(char *buf, size_t l, uint64_t t); - -int fd_wait_for_event(int fd, int event, usec_t timeout); - -void* memdup(const void *p, size_t l) _alloc_(2); - -int fd_inc_sndbuf(int fd, size_t n); -int fd_inc_rcvbuf(int fd, size_t n); - int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); -int setrlimit_closest(int resource, const struct rlimit *rlim); - -bool http_url_is_valid(const char *url) _pure_; -bool documentation_url_is_valid(const char *url) _pure_; - -bool http_etag_is_valid(const char *etag); - bool in_initrd(void); -int get_home_dir(char **ret); -int get_shell(char **_ret); - -static inline void freep(void *p) { - free(*(void**) p); -} - -static inline void closep(int *fd) { - safe_close(*fd); -} - -static inline void umaskp(mode_t *u) { - umask(*u); -} - -static inline void close_pairp(int (*p)[2]) { - safe_close_pair(*p); -} - -static inline void fclosep(FILE **f) { - safe_fclose(*f); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); - -#define _cleanup_free_ _cleanup_(freep) -#define _cleanup_close_ _cleanup_(closep) -#define _cleanup_umask_ _cleanup_(umaskp) -#define _cleanup_globfree_ _cleanup_(globfree) -#define _cleanup_fclose_ _cleanup_(fclosep) -#define _cleanup_pclose_ _cleanup_(pclosep) -#define _cleanup_closedir_ _cleanup_(closedirp) -#define _cleanup_endmntent_ _cleanup_(endmntentp) -#define _cleanup_close_pair_ _cleanup_(close_pairp) - -_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return malloc(a * b); -} - -_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return realloc(p, a * b); -} - -_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return memdup(p, a * b); -} - -bool filename_is_valid(const char *p) _pure_; -bool path_is_safe(const char *p) _pure_; -bool string_is_safe(const char *p) _pure_; -bool string_has_cc(const char *p, const char *ok) _pure_; - -/** - * Check if a string contains any glob patterns. - */ -_pure_ static inline bool string_is_glob(const char *p) { - return !!strpbrk(p, GLOB_CHARS); -} - void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *, void *), void *arg); -#define _(String) gettext (String) -#define N_(String) String -void init_gettext(void); -bool is_locale_utf8(void); - -typedef enum DrawSpecialChar { - DRAW_TREE_VERTICAL, - DRAW_TREE_BRANCH, - DRAW_TREE_RIGHT, - DRAW_TREE_SPACE, - DRAW_TRIANGULAR_BULLET, - DRAW_BLACK_CIRCLE, - DRAW_ARROW, - DRAW_DASH, - _DRAW_SPECIAL_CHAR_MAX -} DrawSpecialChar; - -const char *draw_special_char(DrawSpecialChar ch); - -char *strreplace(const char *text, const char *old_string, const char *new_string); +/** + * Normal qsort requires base to be nonnull. Here were require + * that only if nmemb > 0. + */ +static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { + if (nmemb <= 1) + return; -char *strip_tab_ansi(char **p, size_t *l); + assert(base); + qsort(base, nmemb, size, compar); +} int on_ac_power(void); -int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); -int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); - -#define FOREACH_LINE(line, f, on_error) \ - for (;;) \ - if (!fgets(line, sizeof(line), f)) { \ - if (ferror(f)) { \ - on_error; \ - } \ - break; \ - } else - -#define FOREACH_DIRENT(de, d, on_error) \ - for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ - if (!de) { \ - if (errno > 0) { \ - on_error; \ - } \ - break; \ - } else if (hidden_file((de)->d_name)) \ - continue; \ - else - -#define FOREACH_DIRENT_ALL(de, d, on_error) \ - for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ - if (!de) { \ - if (errno > 0) { \ - on_error; \ - } \ - break; \ - } else +#define memzero(x,l) (memset((x), 0, (l))) +#define zero(x) (memzero(&(x), sizeof(x))) static inline void *mempset(void *s, int c, size_t n) { memset(s, c, n); return (uint8_t*)s + n; } -char *hexmem(const void *p, size_t l); -int unhexmem(const char *p, size_t l, void **mem, size_t *len); - -char *base32hexmem(const void *p, size_t l, bool padding); -int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); - -char *base64mem(const void *p, size_t l); -int unbase64mem(const char *p, size_t l, void **mem, size_t *len); - -char *strextend(char **x, ...) _sentinel_; -char *strrep(const char *s, unsigned n); - -void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); -void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); -#define GREEDY_REALLOC(array, allocated, need) \ - greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) - -#define GREEDY_REALLOC0(array, allocated, need) \ - greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) - static inline void _reset_errno_(int *saved_errno) { errno = *saved_errno; } @@ -674,20 +126,6 @@ static inline int negative_errno(void) { return -errno; } -struct _umask_struct_ { - mode_t mask; - bool quit; -}; - -static inline void _reset_umask_(struct _umask_struct_ *s) { - umask(s->mask); -}; - -#define RUN_WITH_UMASK(mask) \ - for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ - !_saved_umask_.quit ; \ - _saved_umask_.quit = true) - static inline unsigned u64log2(uint64_t n) { #if __SIZEOF_LONG_LONG__ == 8 return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; @@ -725,222 +163,15 @@ static inline unsigned log2u_round_up(unsigned x) { return log2u(x - 1) + 1; } -static inline bool logind_running(void) { - return access("/run/systemd/seats/", F_OK) >= 0; -} - -#define DECIMAL_STR_WIDTH(x) \ - ({ \ - typeof(x) _x_ = (x); \ - unsigned ans = 1; \ - while (_x_ /= 10) \ - ans++; \ - ans; \ - }) - -int unlink_noerrno(const char *path); - -#define alloca0(n) \ - ({ \ - char *_new_; \ - size_t _len_ = n; \ - _new_ = alloca(_len_); \ - (void *) memset(_new_, 0, _len_); \ - }) - -/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ -#define alloca_align(size, align) \ - ({ \ - void *_ptr_; \ - size_t _mask_ = (align) - 1; \ - _ptr_ = alloca((size) + _mask_); \ - (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ - }) - -#define alloca0_align(size, align) \ - ({ \ - void *_new_; \ - size_t _size_ = (size); \ - _new_ = alloca_align(_size_, (align)); \ - (void*)memset(_new_, 0, _size_); \ - }) - -#define strjoina(a, ...) \ - ({ \ - const char *_appendees_[] = { a, __VA_ARGS__ }; \ - char *_d_, *_p_; \ - int _len_ = 0; \ - unsigned _i_; \ - for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ - _len_ += strlen(_appendees_[_i_]); \ - _p_ = _d_ = alloca(_len_ + 1); \ - for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ - _p_ = stpcpy(_p_, _appendees_[_i_]); \ - *_p_ = 0; \ - _d_; \ - }) - bool id128_is_valid(const char *s) _pure_; -int split_pair(const char *s, const char *sep, char **l, char **r); - -int shall_restore_state(void); - -/** - * Normal qsort requires base to be nonnull. Here were require - * that only if nmemb > 0. - */ -static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { - if (nmemb <= 1) - return; - - assert(base); - qsort(base, nmemb, size, compar); -} - -/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ -static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { - - if (needlelen <= 0) - return (void*) haystack; - - if (haystacklen < needlelen) - return NULL; - - assert(haystack); - assert(needle); - - return memmem(haystack, haystacklen, needle, needlelen); -} - -int proc_cmdline(char **ret); -int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value)); -int get_proc_cmdline_key(const char *parameter, char **value); - int container_get_leader(const char *machine, pid_t *pid); int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); -int getpeercred(int fd, struct ucred *ucred); -int getpeersec(int fd, char **ret); - -int writev_safe(int fd, const struct iovec *w, int j); - -int mkostemp_safe(char *pattern, int flags); -int open_tmpfile(const char *path, int flags); - -int fd_warn_permissions(const char *path, int fd); - -#ifndef PERSONALITY_INVALID -/* personality(7) documents that 0xffffffffUL is used for querying the - * current personality, hence let's use that here as error - * indicator. */ -#define PERSONALITY_INVALID 0xffffffffLU -#endif - -unsigned long personality_from_string(const char *p); -const char *personality_to_string(unsigned long); - uint64_t physical_memory(void); -void hexdump(FILE *f, const void *p, size_t s); - -union file_handle_union { - struct file_handle handle; - char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; -}; -#define FILE_HANDLE_INIT { .handle.handle_bytes = MAX_HANDLE_SZ } - int update_reboot_param_file(const char *param); -int umount_recursive(const char *target, int flags); - -int bind_remount_recursive(const char *prefix, bool ro); - -int fflush_and_check(FILE *f); - -int tempfn_xxxxxx(const char *p, const char *extra, char **ret); -int tempfn_random(const char *p, const char *extra, char **ret); -int tempfn_random_child(const char *p, const char *extra, char **ret); - -int take_password_lock(const char *root); - -int is_symlink(const char *path); -int is_dir(const char *path, bool follow); -int is_device_node(const char *path); - -typedef enum ExtractFlags { - EXTRACT_RELAX = 1, - EXTRACT_CUNESCAPE = 2, - EXTRACT_CUNESCAPE_RELAX = 4, - EXTRACT_QUOTES = 8, - EXTRACT_DONT_COALESCE_SEPARATORS = 16, -} ExtractFlags; - -int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); -int extract_first_word_and_warn(const char **p, char **ret, const char *separators, ExtractFlags flags, const char *unit, const char *filename, unsigned line, const char *rvalue); -int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) _sentinel_; - -int free_and_strdup(char **p, const char *s); - -#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) - -#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ - for ((e) = &buffer.ev; \ - (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \ - (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len)) - -union inotify_event_buffer { - struct inotify_event ev; - uint8_t raw[INOTIFY_EVENT_MAX]; -}; - -#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) - -int ptsname_malloc(int fd, char **ret); - -int openpt_in_namespace(pid_t pid, int flags); - -ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags); - -int fd_setcrtime(int fd, usec_t usec); -int fd_getcrtime(int fd, usec_t *usec); -int path_getcrtime(const char *p, usec_t *usec); -int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags); - -int same_fd(int a, int b); - -int chattr_fd(int fd, unsigned value, unsigned mask); -int chattr_path(const char *p, unsigned value, unsigned mask); - -int read_attr_fd(int fd, unsigned *ret); -int read_attr_path(const char *p, unsigned *ret); - -#define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) - -ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); - -void sigkill_wait(pid_t *pid); -#define _cleanup_sigkill_wait_ _cleanup_(sigkill_wait) - -int syslog_parse_priority(const char **p, int *priority, bool with_facility); - -void cmsg_close_all(struct msghdr *mh); - -int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); - -char *shell_escape(const char *s, const char *bad); -char *shell_maybe_quote(const char *s); - -int parse_mode(const char *s, mode_t *ret); - -int mount_move_root(const char *path); - -int reset_uid_gid(void); - -int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); -int fgetxattr_malloc(int fd, const char *name, char **value); - -int send_one_fd(int transport_fd, int fd); -int receive_one_fd(int transport_fd); +int version(void); diff --git a/src/basic/verbs.c b/src/basic/verbs.c index c7beccc2dc..d63062d39e 100644 --- a/src/basic/verbs.c +++ b/src/basic/verbs.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "string-util.h" #include "util.h" #include "verbs.h" diff --git a/src/basic/virt.c b/src/basic/virt.c index 1fc6c1baba..ff006e96c6 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -19,18 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> +#include <string.h> #include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "fileio.h" #include "process-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" #include "virt.h" -#include "fileio.h" static int detect_vm_cpuid(void) { - /* Both CPUID and DMI are x86 specific interfaces... */ + /* CPUID is an x86 specific interface. */ #if defined(__i386__) || defined(__x86_64__) static const struct { @@ -140,11 +144,10 @@ static int detect_vm_device_tree(void) { } static int detect_vm_dmi(void) { - - /* Both CPUID and DMI are x86 specific interfaces... */ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) static const char *const dmi_vendors[] = { + "/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */ "/sys/class/dmi/id/sys_vendor", "/sys/class/dmi/id/board_vendor", "/sys/class/dmi/id/bios_vendor" @@ -154,6 +157,7 @@ static int detect_vm_dmi(void) { const char *vendor; int id; } dmi_vendor_table[] = { + { "KVM", VIRTUALIZATION_KVM }, { "QEMU", VIRTUALIZATION_QEMU }, /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ { "VMware", VIRTUALIZATION_VMWARE }, @@ -240,7 +244,7 @@ static int detect_vm_zvm(void) { _cleanup_free_ char *t = NULL; int r; - r = get_status_field("/proc/sysinfo", "VM00 Control Program:", &t); + r = get_proc_field("/proc/sysinfo", "VM00 Control Program", WHITESPACE, &t); if (r == -ENOENT) return VIRTUALIZATION_NONE; if (r < 0) @@ -263,12 +267,7 @@ int detect_vm(void) { if (cached_found >= 0) return cached_found; - /* Try xen capabilities file first, if not found try - * high-level hypervisor sysfs file: - * - * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ - - r = detect_vm_xen(); + r = detect_vm_cpuid(); if (r < 0) return r; if (r != VIRTUALIZATION_NONE) @@ -280,7 +279,14 @@ int detect_vm(void) { if (r != VIRTUALIZATION_NONE) goto finish; - r = detect_vm_cpuid(); + /* x86 xen will most likely be detected by cpuid. If not (most likely + * because we're not an x86 guest), then we should try the xen capabilities + * file next. If that's not found, then we check for the high-level + * hypervisor sysfs file: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=77271 */ + + r = detect_vm_xen(); if (r < 0) return r; if (r != VIRTUALIZATION_NONE) @@ -323,6 +329,7 @@ int detect_container(void) { { "lxc-libvirt", VIRTUALIZATION_LXC_LIBVIRT }, { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN }, { "docker", VIRTUALIZATION_DOCKER }, + { "rkt", VIRTUALIZATION_RKT }, }; static thread_local int cached_found = _VIRTUALIZATION_INVALID; @@ -410,6 +417,16 @@ int detect_virtualization(void) { return detect_vm(); } +int running_in_chroot(void) { + int ret; + + ret = files_same("/proc/1/root", "/"); + if (ret < 0) + return ret; + + return ret == 0; +} + static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { [VIRTUALIZATION_NONE] = "none", [VIRTUALIZATION_KVM] = "kvm", @@ -429,6 +446,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { [VIRTUALIZATION_LXC] = "lxc", [VIRTUALIZATION_OPENVZ] = "openvz", [VIRTUALIZATION_DOCKER] = "docker", + [VIRTUALIZATION_RKT] = "rkt", [VIRTUALIZATION_CONTAINER_OTHER] = "container-other", }; diff --git a/src/basic/virt.h b/src/basic/virt.h index 449e069901..aca961867c 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -48,6 +48,7 @@ enum { VIRTUALIZATION_LXC, VIRTUALIZATION_OPENVZ, VIRTUALIZATION_DOCKER, + VIRTUALIZATION_RKT, VIRTUALIZATION_CONTAINER_OTHER, VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER, @@ -67,5 +68,7 @@ int detect_vm(void); int detect_container(void); int detect_virtualization(void); +int running_in_chroot(void); + const char *virtualization_to_string(int v) _const_; int virtualization_from_string(const char *s) _pure_; diff --git a/src/basic/web-util.c b/src/basic/web-util.c new file mode 100644 index 0000000000..68ec04021b --- /dev/null +++ b/src/basic/web-util.c @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +#include "string-util.h" +#include "utf8.h" +#include "web-util.h" + +bool http_etag_is_valid(const char *etag) { + if (isempty(etag)) + return false; + + if (!endswith(etag, "\"")) + return false; + + if (!startswith(etag, "\"") && !startswith(etag, "W/\"")) + return false; + + return true; +} + +bool http_url_is_valid(const char *url) { + const char *p; + + if (isempty(url)) + return false; + + p = startswith(url, "http://"); + if (!p) + p = startswith(url, "https://"); + if (!p) + return false; + + if (isempty(p)) + return false; + + return ascii_is_valid(p); +} + +bool documentation_url_is_valid(const char *url) { + const char *p; + + if (isempty(url)) + return false; + + if (http_url_is_valid(url)) + return true; + + p = startswith(url, "file:/"); + if (!p) + p = startswith(url, "info:"); + if (!p) + p = startswith(url, "man:"); + + if (isempty(p)) + return false; + + return ascii_is_valid(p); +} diff --git a/src/basic/web-util.h b/src/basic/web-util.h new file mode 100644 index 0000000000..40c1509eb8 --- /dev/null +++ b/src/basic/web-util.h @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> + +#include "macro.h" + +bool http_url_is_valid(const char *url) _pure_; + +bool documentation_url_is_valid(const char *url) _pure_; + +bool http_etag_is_valid(const char *etag); diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c new file mode 100644 index 0000000000..6abdaedc3e --- /dev/null +++ b/src/basic/xattr-util.c @@ -0,0 +1,195 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <sys/xattr.h> + +#include "alloc-util.h" +#include "fd-util.h" +#include "sparse-endian.h" +#include "stdio-util.h" +#include "util.h" +#include "xattr-util.h" + +int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { + char *v; + size_t l; + ssize_t n; + + assert(path); + assert(name); + assert(value); + + for (l = 100; ; l = (size_t) n + 1) { + v = new0(char, l); + if (!v) + return -ENOMEM; + + if (allow_symlink) + n = lgetxattr(path, name, v, l); + else + n = getxattr(path, name, v, l); + + if (n >= 0 && (size_t) n < l) { + *value = v; + return n; + } + + free(v); + + if (n < 0 && errno != ERANGE) + return -errno; + + if (allow_symlink) + n = lgetxattr(path, name, NULL, 0); + else + n = getxattr(path, name, NULL, 0); + if (n < 0) + return -errno; + } +} + +int fgetxattr_malloc(int fd, const char *name, char **value) { + char *v; + size_t l; + ssize_t n; + + assert(fd >= 0); + assert(name); + assert(value); + + for (l = 100; ; l = (size_t) n + 1) { + v = new0(char, l); + if (!v) + return -ENOMEM; + + n = fgetxattr(fd, name, v, l); + + if (n >= 0 && (size_t) n < l) { + *value = v; + return n; + } + + free(v); + + if (n < 0 && errno != ERANGE) + return -errno; + + n = fgetxattr(fd, name, NULL, 0); + if (n < 0) + return -errno; + } +} + +ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags) { + char fn[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; + _cleanup_close_ int fd = -1; + ssize_t l; + + /* The kernel doesn't have a fgetxattrat() command, hence let's emulate one */ + + fd = openat(dirfd, filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_PATH|(flags & AT_SYMLINK_NOFOLLOW ? O_NOFOLLOW : 0)); + if (fd < 0) + return -errno; + + xsprintf(fn, "/proc/self/fd/%i", fd); + + l = getxattr(fn, attribute, value, size); + if (l < 0) + return -errno; + + return l; +} + +static int parse_crtime(le64_t le, usec_t *usec) { + uint64_t u; + + assert(usec); + + u = le64toh(le); + if (u == 0 || u == (uint64_t) -1) + return -EIO; + + *usec = (usec_t) u; + return 0; +} + +int fd_getcrtime(int fd, usec_t *usec) { + le64_t le; + ssize_t n; + + assert(fd >= 0); + assert(usec); + + /* Until Linux gets a real concept of birthtime/creation time, + * let's fake one with xattrs */ + + n = fgetxattr(fd, "user.crtime_usec", &le, sizeof(le)); + if (n < 0) + return -errno; + if (n != sizeof(le)) + return -EIO; + + return parse_crtime(le, usec); +} + +int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags) { + le64_t le; + ssize_t n; + + n = fgetxattrat_fake(dirfd, name, "user.crtime_usec", &le, sizeof(le), flags); + if (n < 0) + return -errno; + if (n != sizeof(le)) + return -EIO; + + return parse_crtime(le, usec); +} + +int path_getcrtime(const char *p, usec_t *usec) { + le64_t le; + ssize_t n; + + assert(p); + assert(usec); + + n = getxattr(p, "user.crtime_usec", &le, sizeof(le)); + if (n < 0) + return -errno; + if (n != sizeof(le)) + return -EIO; + + return parse_crtime(le, usec); +} + +int fd_setcrtime(int fd, usec_t usec) { + le64_t le; + + assert(fd >= 0); + + if (usec <= 0) + usec = now(CLOCK_REALTIME); + + le = htole64((uint64_t) usec); + if (fsetxattr(fd, "user.crtime_usec", &le, sizeof(le), 0) < 0) + return -errno; + + return 0; +} diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h new file mode 100644 index 0000000000..cf4cb12a25 --- /dev/null +++ b/src/basic/xattr-util.h @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdbool.h> +#include <sys/types.h> + +#include "time-util.h" + +int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink); +int fgetxattr_malloc(int fd, const char *name, char **value); + +ssize_t fgetxattrat_fake(int dirfd, const char *filename, const char *attribute, void *value, size_t size, int flags); + +int fd_setcrtime(int fd, usec_t usec); + +int fd_getcrtime(int fd, usec_t *usec); +int path_getcrtime(const char *p, usec_t *usec); +int fd_getcrtime_at(int dirfd, const char *name, usec_t *usec, int flags); diff --git a/src/basic/xml.c b/src/basic/xml.c index 15c629b188..8126bce212 100644 --- a/src/basic/xml.c +++ b/src/basic/xml.c @@ -21,6 +21,7 @@ #include <string.h> +#include "string-util.h" #include "util.h" #include "xml.h" diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index 1e216f52bd..42ad0adb02 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -19,20 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stdbool.h> #include <errno.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> #include <getopt.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "alloc-util.h" +#include "conf-files.h" +#include "def.h" +#include "fd-util.h" +#include "fileio.h" #include "log.h" +#include "string-util.h" #include "strv.h" #include "util.h" -#include "conf-files.h" -#include "fileio.h" -#include "build.h" static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt"); @@ -91,8 +94,7 @@ static int apply_file(const char *path, bool ignore_enoent) { if (feof(f)) break; - log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); } p = strstrip(l); @@ -143,9 +145,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case '?': return -EINVAL; diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index ac1711b318..4cf42d17f3 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -20,28 +20,32 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <getopt.h> -#include <stdlib.h> #include <assert.h> -#include <sys/statfs.h> -#include <sys/stat.h> -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <sys/mman.h> -#include <dirent.h> +#include <blkid/blkid.h> #include <ctype.h> -#include <limits.h> +#include <dirent.h> +#include <errno.h> #include <ftw.h> +#include <getopt.h> +#include <limits.h> #include <stdbool.h> -#include <blkid/blkid.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <unistd.h> +#include "alloc-util.h" +#include "blkid-util.h" #include "efivars.h" -#include "build.h" -#include "util.h" +#include "fd-util.h" +#include "fileio.h" +#include "locale-util.h" #include "rm-rf.h" -#include "blkid-util.h" +#include "string-util.h" +#include "util.h" static int verify_esp(const char *p, uint32_t *part, uint64_t *pstart, uint64_t *psize, sd_id128_t *uuid) { struct statfs sfs; @@ -967,8 +971,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - printf(VERSION "\n"); - return 0; + return version(); case ARG_PATH: arg_path = optarg; diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index 83ad90c222..852febb225 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -33,30 +33,37 @@ ***/ -#include <sys/resource.h> -#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <limits.h> #include <signal.h> +#include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> +#include <sys/resource.h> #include <time.h> -#include <getopt.h> -#include <limits.h> -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include "systemd/sd-journal.h" +#include <unistd.h> -#include "util.h" +#include "sd-journal.h" + +#include "alloc-util.h" +#include "bootchart.h" +#include "conf-parser.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" +#include "list.h" #include "macro.h" -#include "conf-parser.h" -#include "strxcpyx.h" +#include "parse-util.h" #include "path-util.h" #include "store.h" +#include "string-util.h" +#include "strxcpyx.h" #include "svg.h" -#include "bootchart.h" -#include "list.h" +#include "util.h" static int exiting = 0; diff --git a/src/bootchart/store.c b/src/bootchart/store.c index caa97b97fc..c1b1e77e44 100644 --- a/src/bootchart/store.c +++ b/src/bootchart/store.c @@ -22,22 +22,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <stdlib.h> +#include <dirent.h> +#include <fcntl.h> #include <limits.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <dirent.h> -#include <fcntl.h> #include <time.h> +#include <unistd.h> -#include "util.h" -#include "time-util.h" -#include "strxcpyx.h" -#include "store.h" +#include "alloc-util.h" #include "bootchart.h" #include "cgroup-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "fileio.h" +#include "parse-util.h" +#include "store.h" +#include "string-util.h" +#include "strxcpyx.h" +#include "time-util.h" +#include "util.h" /* * Alloc a static 4k buffer for stdio - primarily used to increase diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c index c66f12e3a6..05330c0577 100644 --- a/src/bootchart/svg.c +++ b/src/bootchart/svg.c @@ -30,6 +30,8 @@ #include <sys/utsname.h> #include <fcntl.h> +#include "alloc-util.h" +#include "architecture.h" #include "util.h" #include "fileio.h" #include "macro.h" @@ -38,6 +40,7 @@ #include "bootchart.h" #include "list.h" #include "utf8.h" +#include "fd-util.h" #define time_to_graph(t) ((t) * arg_scale_x) #define ps_to_graph(n) ((n) * arg_scale_y) @@ -147,7 +150,7 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start, _cleanup_free_ char *model = NULL; _cleanup_free_ char *buf = NULL; char date[256] = "Unknown"; - char *cpu; + const char *cpu; char *c; time_t t; int r; @@ -188,20 +191,11 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start, assert_se(r > 0); /* CPU type */ - r = read_full_file("/proc/cpuinfo", &buf, NULL); + r = get_proc_field("/proc/cpuinfo", PROC_CPUINFO_MODEL, "\n", &buf); if (r < 0) - return log_error_errno(r, "Unable to read cpuinfo: %m"); - - cpu = strstr(buf, "model name"); - if (!cpu) { - log_error("Unable to read module name from cpuinfo.\n"); - return -ENOENT; - } - - cpu += 13; - c = strchr(cpu, '\n'); - if (c) - *c = '\0'; + cpu = "Unknown"; + else + cpu = buf; fprintf(of, "<text class=\"t1\" x=\"0\" y=\"30\">Bootchart for %s - %s</text>\n", uts.nodename, date); diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c index 3cc3b33ae7..6a7134644f 100644 --- a/src/bus-proxyd/bus-proxyd.c +++ b/src/bus-proxyd/bus-proxyd.c @@ -22,26 +22,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <unistd.h> -#include <string.h> #include <errno.h> -#include <sys/prctl.h> -#include <stddef.h> #include <getopt.h> #include <pthread.h> +#include <stddef.h> +#include <string.h> +#include <sys/prctl.h> +#include <sys/socket.h> +#include <unistd.h> -#include "log.h" -#include "util.h" #include "sd-daemon.h" + +#include "alloc-util.h" #include "bus-internal.h" -#include "build.h" -#include "strv.h" -#include "def.h" -#include "capability.h" #include "bus-xml-policy.h" -#include "proxy.h" +#include "capability-util.h" +#include "def.h" +#include "fd-util.h" #include "formats-util.h" +#include "log.h" +#include "proxy.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" static char *arg_address = NULL; static char **arg_configuration = NULL; @@ -85,11 +89,11 @@ static void *run_client(void *userdata) { int r; r = proxy_new(&p, c->fd, c->fd, arg_address); + c->fd = -1; + if (r < 0) goto exit; - c->fd = -1; - /* set comm to "p$PIDu$UID" and suffix with '*' if truncated */ r = snprintf(comm, sizeof(comm), "p" PID_FMT "u" UID_FMT, p->local_creds.pid, p->local_creds.uid); if (r >= (ssize_t)sizeof(comm)) @@ -116,13 +120,12 @@ static int loop_clients(int accept_fd, uid_t bus_uid) { int r; r = pthread_attr_init(&attr); - if (r < 0) { - return log_error_errno(errno, "Cannot initialize pthread attributes: %m"); - } + if (r != 0) + return log_error_errno(r, "Cannot initialize pthread attributes: %m"); r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - if (r < 0) { - r = log_error_errno(errno, "Cannot mark pthread attributes as detached: %m"); + if (r != 0) { + r = log_error_errno(r, "Cannot mark pthread attributes as detached: %m"); goto finish; } @@ -156,8 +159,8 @@ static int loop_clients(int accept_fd, uid_t bus_uid) { c->bus_uid = bus_uid; r = pthread_create(&tid, &attr, run_client, c); - if (r < 0) { - log_error("Cannot spawn thread: %m"); + if (r != 0) { + log_warning_errno(r, "Cannot spawn thread, ignoring: %m"); client_context_free(c); continue; } @@ -215,9 +218,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_ADDRESS: r = free_and_strdup(&arg_address, optarg); diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c index 9a3b451c56..f0834e9525 100644 --- a/src/bus-proxyd/bus-xml-policy.c +++ b/src/bus-proxyd/bus-xml-policy.c @@ -19,15 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "xml.h" -#include "fileio.h" -#include "strv.h" -#include "set.h" -#include "conf-files.h" +#include "sd-login.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-xml-policy.h" -#include "sd-login.h" +#include "conf-files.h" +#include "fileio.h" #include "formats-util.h" +#include "locale-util.h" +#include "set.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "xml.h" static void policy_item_free(PolicyItem *i) { assert(i); @@ -1186,14 +1192,14 @@ int shared_policy_new(SharedPolicy **out) { return log_oom(); r = pthread_mutex_init(&sp->lock, NULL); - if (r < 0) { - log_error_errno(r, "Cannot initialize shared policy mutex: %m"); + if (r != 0) { + r = log_error_errno(r, "Cannot initialize shared policy mutex: %m"); goto exit_free; } r = pthread_rwlock_init(&sp->rwlock, NULL); - if (r < 0) { - log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); + if (r != 0) { + r = log_error_errno(r, "Cannot initialize shared policy rwlock: %m"); goto exit_mutex; } diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c index fa4aee691a..2e8bd83efd 100644 --- a/src/bus-proxyd/driver.c +++ b/src/bus-proxyd/driver.c @@ -21,21 +21,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> #include <stddef.h> +#include <string.h> -#include "util.h" #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" -#include "strv.h" -#include "set.h" #include "driver.h" +#include "env-util.h" #include "proxy.h" +#include "set.h" +#include "strv.h" #include "synthesize.h" -#include "env-util.h" +#include "util.h" static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c index 88800f5e7f..db399b24f2 100644 --- a/src/bus-proxyd/proxy.c +++ b/src/bus-proxyd/proxy.c @@ -22,27 +22,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <sys/types.h> -#include <string.h> #include <errno.h> #include <poll.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> -#include "log.h" -#include "util.h" -#include "sd-daemon.h" #include "sd-bus.h" +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" -#include "strv.h" -#include "bus-control.h" -#include "set.h" #include "bus-xml-policy.h" #include "driver.h" +#include "fd-util.h" +#include "formats-util.h" +#include "log.h" #include "proxy.h" +#include "set.h" +#include "strv.h" #include "synthesize.h" -#include "formats-util.h" +#include "user-util.h" +#include "util.h" static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) { _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; @@ -100,18 +104,24 @@ static int proxy_create_destination(Proxy *p, const char *destination, const cha return 0; } -static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fds) { - _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; +static int proxy_create_local(Proxy *p, bool negotiate_fds) { sd_id128_t server_id; + sd_bus *b; int r; r = sd_bus_new(&b); if (r < 0) return log_error_errno(r, "Failed to allocate bus: %m"); - r = sd_bus_set_fd(b, in_fd, out_fd); - if (r < 0) + r = sd_bus_set_fd(b, p->local_in, p->local_out); + if (r < 0) { + sd_bus_unref(b); return log_error_errno(r, "Failed to set fds: %m"); + } + + /* The fds are now owned by the bus, and we indicate that by + * storing the bus object in the proxy object. */ + p->local_bus = b; r = sd_bus_get_bus_id(p->destination_bus, &server_id); if (r < 0) @@ -139,8 +149,6 @@ static int proxy_create_local(Proxy *p, int in_fd, int out_fd, bool negotiate_fd if (r < 0) return log_error_errno(r, "Failed to start bus client: %m"); - p->local_bus = b; - b = NULL; return 0; } @@ -224,9 +232,17 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { bool is_unix; int r; + /* This takes possession/destroys the file descriptors passed + * in even on failure. The caller should hence forget about + * the fds in all cases after calling this function and not + * close them. */ + p = new0(Proxy, 1); - if (!p) + if (!p) { + safe_close(in_fd); + safe_close(out_fd); return log_oom(); + } p->local_in = in_fd; p->local_out = out_fd; @@ -247,7 +263,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { if (r < 0) return r; - r = proxy_create_local(p, in_fd, out_fd, is_unix); + r = proxy_create_local(p, is_unix); if (r < 0) return r; @@ -257,6 +273,7 @@ int proxy_new(Proxy **out, int in_fd, int out_fd, const char *destination) { *out = p; p = NULL; + return 0; } @@ -273,7 +290,14 @@ Proxy *proxy_free(Proxy *p) { free(activation); } - sd_bus_flush_close_unref(p->local_bus); + if (p->local_bus) + sd_bus_flush_close_unref(p->local_bus); + else { + safe_close(p->local_in); + if (p->local_out != p->local_in) + safe_close(p->local_out); + } + sd_bus_flush_close_unref(p->destination_bus); set_free_free(p->owned_names); free(p); diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h index 6aac650ac9..7b2e5d422f 100644 --- a/src/bus-proxyd/proxy.h +++ b/src/bus-proxyd/proxy.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "bus-xml-policy.h" typedef struct Proxy Proxy; diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c index f275f6705f..6e47884209 100644 --- a/src/bus-proxyd/stdio-bridge.c +++ b/src/bus-proxyd/stdio-bridge.c @@ -21,23 +21,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <string.h> #include <errno.h> -#include <stddef.h> #include <getopt.h> +#include <stddef.h> +#include <string.h> +#include <unistd.h> -#include "log.h" -#include "util.h" #include "sd-daemon.h" #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-util.h" -#include "build.h" -#include "strv.h" #include "def.h" -#include "proxy.h" #include "formats-util.h" +#include "log.h" +#include "proxy.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" static char *arg_address = NULL; static char *arg_command_line_buffer = NULL; @@ -86,9 +88,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_ADDRESS: { char *a; diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c index 15d99103f6..7f1f9dc28d 100644 --- a/src/bus-proxyd/synthesize.c +++ b/src/bus-proxyd/synthesize.c @@ -23,13 +23,14 @@ #include <stddef.h> -#include "util.h" #include "sd-bus.h" + #include "bus-internal.h" +#include "bus-match.h" #include "bus-message.h" #include "bus-util.h" -#include "bus-match.h" #include "synthesize.h" +#include "util.h" int synthetic_driver_send(sd_bus *b, sd_bus_message *m) { int r; diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h index b596daddf2..ddfe2fd266 100644 --- a/src/bus-proxyd/synthesize.h +++ b/src/bus-proxyd/synthesize.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "proxy.h" int synthetic_driver_send(sd_bus *b, sd_bus_message *m); diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c index d19d0e1b60..1f465edd91 100644 --- a/src/bus-proxyd/test-bus-xml-policy.c +++ b/src/bus-proxyd/test-bus-xml-policy.c @@ -19,15 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> #include <stddef.h> +#include <unistd.h> -#include "log.h" -#include "util.h" #include "sd-bus.h" -#include "strv.h" + +#include "alloc-util.h" #include "bus-xml-policy.h" +#include "log.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static int test_policy_load(Policy *p, const char *name) { _cleanup_free_ char *path = NULL; diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index ec4215f741..4e9a76a100 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -19,25 +19,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <unistd.h> #include <errno.h> #include <getopt.h> +#include <stdio.h> #include <string.h> +#include <unistd.h> + +#include "sd-bus.h" +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" #include "cgroup-show.h" #include "cgroup-util.h" +#include "fileio.h" #include "log.h" -#include "path-util.h" -#include "util.h" -#include "pager.h" -#include "build.h" #include "output-mode.h" -#include "fileio.h" -#include "sd-bus.h" -#include "bus-util.h" -#include "bus-error.h" +#include "pager.h" +#include "path-util.h" #include "unit-name.h" +#include "util.h" static bool arg_no_pager = false; static bool arg_kernel_threads = false; @@ -89,9 +90,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; @@ -147,7 +146,7 @@ static int get_cgroup_root(char **ret) { if (!path) return log_oom(); - r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus); + r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus); if (r < 0) return log_error_errno(r, "Failed to create bus connection: %m"); diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index 612bc8fdec..e48234f075 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -22,8 +22,9 @@ #include <stdlib.h> #include "sd-bus.h" -#include "log.h" + #include "bus-util.h" +#include "log.h" int main(int argc, char *argv[]) { _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; @@ -43,7 +44,7 @@ int main(int argc, char *argv[]) { * this to avoid an activation loop when we start dbus when we * are called when the dbus service is shut down. */ - r = bus_open_system_systemd(&bus); + r = bus_connect_system_systemd(&bus); if (r < 0) { /* If we couldn't connect we assume this was triggered * while systemd got restarted/transitioned from diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 9cf13cf57d..eea8aea76b 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -19,27 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> -#include <string.h> -#include <stdlib.h> -#include <stdint.h> -#include <unistd.h> #include <alloca.h> +#include <errno.h> #include <getopt.h> #include <signal.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> -#include "path-util.h" -#include "terminal-util.h" -#include "process-util.h" -#include "util.h" -#include "hashmap.h" -#include "cgroup-util.h" -#include "build.h" -#include "fileio.h" #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "parse-util.h" +#include "path-util.h" +#include "process-util.h" +#include "terminal-util.h" #include "unit-name.h" +#include "util.h" typedef struct Group { char *path; @@ -696,9 +699,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_CPU_TYPE: if (optarg) { @@ -863,7 +864,7 @@ static int get_cgroup_root(char **ret) { if (!path) return log_oom(); - r = bus_open_transport(BUS_TRANSPORT_LOCAL, NULL, false, &bus); + r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus); if (r < 0) return log_error_errno(r, "Failed to create bus connection: %m"); diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c index 5a18e263a8..3ae46d8cfb 100644 --- a/src/core/audit-fd.c +++ b/src/core/audit-fd.c @@ -30,6 +30,7 @@ #include "log.h" #include "util.h" +#include "fd-util.h" static bool initialized = false; static int audit_fd; diff --git a/src/core/automount.c b/src/core/automount.c index c88e3311bc..4c229247c5 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -20,29 +20,37 @@ ***/ #include <errno.h> -#include <limits.h> -#include <sys/mount.h> -#include <unistd.h> #include <fcntl.h> +#include <limits.h> +#include <linux/auto_dev-ioctl.h> +#include <linux/auto_fs4.h> #include <sys/epoll.h> +#include <sys/mount.h> #include <sys/stat.h> -#include <linux/auto_fs4.h> -#include <linux/auto_dev-ioctl.h> +#include <unistd.h> -#include "unit.h" +#include "alloc-util.h" +#include "async.h" #include "automount.h" -#include "mount.h" -#include "unit-name.h" -#include "special.h" +#include "bus-error.h" +#include "bus-util.h" +#include "dbus-automount.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" #include "label.h" #include "mkdir.h" +#include "mount-util.h" +#include "mount.h" +#include "parse-util.h" #include "path-util.h" -#include "dbus-automount.h" -#include "bus-util.h" -#include "bus-error.h" -#include "formats-util.h" #include "process-util.h" -#include "async.h" +#include "special.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" +#include "unit-name.h" +#include "unit.h" static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = { [AUTOMOUNT_DEAD] = UNIT_INACTIVE, @@ -81,26 +89,11 @@ static void automount_init(Unit *u) { UNIT(a)->ignore_on_isolate = true; } -static void repeat_unmount(const char *path) { - assert(path); - - for (;;) { - /* If there are multiple mounts on a mount point, this - * removes them all */ - - if (umount2(path, MNT_DETACH) >= 0) - continue; - - if (errno != EINVAL) - log_error_errno(errno, "Failed to unmount: %m"); - - break; - } -} - static int automount_send_ready(Automount *a, Set *tokens, int status); static void unmount_autofs(Automount *a) { + int r; + assert(a); if (a->pipe_fd < 0) @@ -116,8 +109,11 @@ static void unmount_autofs(Automount *a) { * around */ if (a->where && (UNIT(a)->manager->exit_code != MANAGER_RELOAD && - UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) - repeat_unmount(a->where); + UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) { + r = repeat_unmount(a->where, MNT_DETACH); + if (r < 0) + log_error_errno(r, "Failed to unmount: %m"); + } } static void automount_done(Unit *u) { @@ -137,13 +133,12 @@ static void automount_done(Unit *u) { static int automount_add_mount_links(Automount *a) { _cleanup_free_ char *parent = NULL; - int r; assert(a); - r = path_get_parent(a->where, &parent); - if (r < 0) - return r; + parent = dirname_malloc(a->where); + if (!parent) + return -ENOMEM; return unit_require_mounts_for(UNIT(a), parent); } @@ -608,12 +603,16 @@ static void automount_enter_waiting(Automount *a) { return; fail: + log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m"); + safe_close_pair(p); - if (mounted) - repeat_unmount(a->where); + if (mounted) { + r = repeat_unmount(a->where, MNT_DETACH); + if (r < 0) + log_error_errno(r, "Failed to unmount, ignoring: %m"); + } - log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m"); automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES); } @@ -774,8 +773,9 @@ static int automount_stop(Unit *u) { static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { Automount *a = AUTOMOUNT(u); - void *p; Iterator i; + void *p; + int r; assert(a); assert(f); @@ -790,15 +790,9 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) { SET_FOREACH(p, a->expire_tokens, i) unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p)); - if (a->pipe_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, a->pipe_fd); - if (copy < 0) - return copy; - - unit_serialize_item_format(u, f, "pipe-fd", "%i", copy); - } + r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd); + if (r < 0) + return r; return 0; } @@ -1024,15 +1018,6 @@ static bool automount_supported(void) { return supported; } -static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { - [AUTOMOUNT_DEAD] = "dead", - [AUTOMOUNT_WAITING] = "waiting", - [AUTOMOUNT_RUNNING] = "running", - [AUTOMOUNT_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState); - static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = { [AUTOMOUNT_SUCCESS] = "success", [AUTOMOUNT_FAILURE_RESOURCES] = "resources" diff --git a/src/core/automount.h b/src/core/automount.h index 2a50fef68d..43ea9f772d 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -25,15 +25,6 @@ typedef struct Automount Automount; #include "unit.h" -typedef enum AutomountState { - AUTOMOUNT_DEAD, - AUTOMOUNT_WAITING, - AUTOMOUNT_RUNNING, - AUTOMOUNT_FAILED, - _AUTOMOUNT_STATE_MAX, - _AUTOMOUNT_STATE_INVALID = -1 -} AutomountState; - typedef enum AutomountResult { AUTOMOUNT_SUCCESS, AUTOMOUNT_FAILURE_RESOURCES, @@ -66,8 +57,5 @@ extern const UnitVTable automount_vtable; int automount_update_mount(Automount *a, MountState old_state, MountState state); -const char* automount_state_to_string(AutomountState i) _const_; -AutomountState automount_state_from_string(const char *s) _pure_; - const char* automount_result_to_string(AutomountResult i) _const_; AutomountResult automount_result_from_string(const char *s) _pure_; diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c index 0c4b3e7c8b..d22a80c91f 100644 --- a/src/core/bus-endpoint.c +++ b/src/core/bus-endpoint.c @@ -19,10 +19,11 @@ #include <stdlib.h> -#include "kdbus.h" +#include "alloc-util.h" +#include "bus-endpoint.h" #include "bus-kernel.h" #include "bus-policy.h" -#include "bus-endpoint.h" +#include "kdbus.h" int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) { diff --git a/src/core/bus-policy.c b/src/core/bus-policy.c index a6a8fcd4d3..4907c268e8 100644 --- a/src/core/bus-policy.c +++ b/src/core/bus-policy.c @@ -19,10 +19,13 @@ #include <stdlib.h> -#include "kdbus.h" -#include "util.h" +#include "alloc-util.h" #include "bus-kernel.h" #include "bus-policy.h" +#include "kdbus.h" +#include "string-table.h" +#include "user-util.h" +#include "util.h" int bus_kernel_translate_access(BusPolicyAccess access) { assert(access >= 0); diff --git a/src/core/busname.c b/src/core/busname.c index 4020e9dd3c..68508e20d2 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -21,17 +21,23 @@ #include <sys/mman.h> -#include "special.h" -#include "formats-util.h" -#include "signal-util.h" -#include "bus-kernel.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-kernel.h" +#include "bus-policy.h" #include "bus-util.h" +#include "busname.h" +#include "dbus-busname.h" +#include "fd-util.h" +#include "formats-util.h" #include "kdbus.h" -#include "bus-policy.h" +#include "parse-util.h" +#include "process-util.h" #include "service.h" -#include "dbus-busname.h" -#include "busname.h" +#include "signal-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = { [BUSNAME_DEAD] = UNIT_INACTIVE, @@ -358,10 +364,9 @@ static int busname_coldplug(Unit *u) { if (n->deserialized_state == n->state) return 0; - if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) { - - if (n->control_pid <= 0) - return -EBADMSG; + if (n->control_pid > 0 && + pid_is_unwaited(n->control_pid) && + IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) { r = unit_watch_pid(UNIT(n), n->control_pid); if (r < 0) @@ -585,6 +590,12 @@ static void busname_enter_running(BusName *n) { } if (!pending) { + if (!UNIT_ISSET(n->service)) { + log_unit_error(UNIT(n), "Service to activate vanished, refusing activation."); + r = -ENOENT; + goto fail; + } + r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL); if (r < 0) goto fail; @@ -656,6 +667,7 @@ static int busname_stop(Unit *u) { static int busname_serialize(Unit *u, FILE *f, FDSet *fds) { BusName *n = BUSNAME(u); + int r; assert(n); assert(f); @@ -667,15 +679,9 @@ static int busname_serialize(Unit *u, FILE *f, FDSet *fds) { if (n->control_pid > 0) unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid); - if (n->starter_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, n->starter_fd); - if (copy < 0) - return copy; - - unit_serialize_item_format(u, f, "starter-fd", "%i", copy); - } + r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd); + if (r < 0) + return r; return 0; } @@ -991,19 +997,6 @@ static bool busname_supported(void) { return supported; } -static const char* const busname_state_table[_BUSNAME_STATE_MAX] = { - [BUSNAME_DEAD] = "dead", - [BUSNAME_MAKING] = "making", - [BUSNAME_REGISTERED] = "registered", - [BUSNAME_LISTENING] = "listening", - [BUSNAME_RUNNING] = "running", - [BUSNAME_SIGTERM] = "sigterm", - [BUSNAME_SIGKILL] = "sigkill", - [BUSNAME_FAILED] = "failed", -}; - -DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState); - static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { [BUSNAME_SUCCESS] = "success", [BUSNAME_FAILURE_RESOURCES] = "resources", diff --git a/src/core/busname.h b/src/core/busname.h index 69528a2aef..46f7b6f097 100644 --- a/src/core/busname.h +++ b/src/core/busname.h @@ -24,19 +24,7 @@ typedef struct BusName BusName; typedef struct BusNamePolicy BusNamePolicy; - -typedef enum BusNameState { - BUSNAME_DEAD, - BUSNAME_MAKING, - BUSNAME_REGISTERED, - BUSNAME_LISTENING, - BUSNAME_RUNNING, - BUSNAME_SIGTERM, - BUSNAME_SIGKILL, - BUSNAME_FAILED, - _BUSNAME_STATE_MAX, - _BUSNAME_STATE_INVALID = -1 -} BusNameState; +#include "unit.h" typedef enum BusNameResult { BUSNAME_SUCCESS, @@ -77,8 +65,5 @@ struct BusName { extern const UnitVTable busname_vtable; -const char* busname_state_to_string(BusNameState i) _const_; -BusNameState busname_state_from_string(const char *s) _pure_; - const char* busname_result_to_string(BusNameResult i) _const_; BusNameResult busname_result_from_string(const char *s) _pure_; diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 0c790c33da..bed01fde21 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -22,12 +22,18 @@ #include <fcntl.h> #include <fnmatch.h> +#include "alloc-util.h" #include "cgroup-util.h" +#include "cgroup.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "special.h" - -#include "cgroup.h" +#include "string-table.h" +#include "string-util.h" #define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC) @@ -1203,7 +1209,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret) { continue; /* Ignore processes that aren't our kids */ - if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid) + if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid) continue; if (pid != 0) diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c index 5162ce34cb..45f2c2ffd6 100644 --- a/src/core/dbus-automount.c +++ b/src/core/dbus-automount.c @@ -20,8 +20,9 @@ ***/ #include "automount.h" -#include "dbus-automount.h" #include "bus-util.h" +#include "string-util.h" +#include "dbus-automount.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult); diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c index b1ceb05b1a..05ac89c3c0 100644 --- a/src/core/dbus-busname.c +++ b/src/core/dbus-busname.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" +#include "bus-util.h" #include "busname.h" +#include "string-util.h" +#include "unit.h" #include "dbus-busname.h" -#include "bus-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult); diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index f334dc928d..3fd295baa9 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-util.h" -#include "path-util.h" #include "cgroup-util.h" #include "cgroup.h" #include "dbus-cgroup.h" +#include "fd-util.h" +#include "fileio.h" +#include "path-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); @@ -421,7 +424,9 @@ int bus_cgroup_set_property( fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth); } - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(u, mode, name, buf); } @@ -495,7 +500,9 @@ int bus_cgroup_set_property( LIST_FOREACH(device_weights, a, c->blockio_device_weights) fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight); - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(u, mode, name, buf); } @@ -640,7 +647,9 @@ int bus_cgroup_set_property( LIST_FOREACH(device_allow, a, c->device_allow) fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : ""); - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(u, mode, name, buf); } diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h index c2a3910f3d..9dc187c066 100644 --- a/src/core/dbus-cgroup.h +++ b/src/core/dbus-cgroup.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "cgroup.h" extern const sd_bus_vtable bus_cgroup_vtable[]; diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 868c8cc05a..db4206a523 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -25,22 +25,28 @@ #include <seccomp.h> #endif +#include "af-list.h" +#include "alloc-util.h" #include "bus-util.h" -#include "missing.h" -#include "ioprio.h" -#include "strv.h" -#include "fileio.h" -#include "execute.h" -#include "capability.h" +#include "capability-util.h" +#include "dbus-execute.h" #include "env-util.h" -#include "af-list.h" +#include "execute.h" +#include "fd-util.h" +#include "fileio.h" +#include "ioprio.h" +#include "missing.h" #include "namespace.h" +#include "parse-util.h" #include "path-util.h" -#include "dbus-execute.h" - +#include "process-util.h" +#include "rlimit-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "strv.h" +#include "syslog-util.h" +#include "utf8.h" BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput); @@ -83,45 +89,6 @@ static int property_get_environment_files( return sd_bus_message_close_container(reply); } -static int property_get_rlimit( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - struct rlimit *rl; - uint64_t u; - rlim_t x; - - assert(bus); - assert(reply); - assert(userdata); - - rl = *(struct rlimit**) userdata; - if (rl) - x = rl->rlim_max; - else { - struct rlimit buf = {}; - int z; - - z = rlimit_from_string(property); - assert(z >= 0); - - getrlimit(z, &buf); - x = buf.rlim_max; - } - - /* rlim_t might have different sizes, let's map - * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on - * all archs */ - u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x; - - return sd_bus_message_append(reply, "t", u); -} - static int property_get_oom_score_adjust( sd_bus *bus, const char *path, @@ -146,7 +113,7 @@ static int property_get_oom_score_adjust( n = 0; if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) - safe_atoi(t, &n); + safe_atoi32(t, &n); } return sd_bus_message_append(reply, "i", n); @@ -595,28 +562,91 @@ static int property_get_address_families( return sd_bus_message_close_container(reply); } +static int property_get_working_directory( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + const char *wd; + + assert(bus); + assert(reply); + assert(c); + + if (c->working_directory_home) + wd = "~"; + else + wd = c->working_directory; + + if (c->working_directory_missing_ok) + wd = strjoina("!", wd); + + return sd_bus_message_append(reply, "s", wd); +} + +static int property_get_syslog_level( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority)); +} + +static int property_get_syslog_facility( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority)); +} + const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -637,6 +667,8 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -829,7 +861,64 @@ int bus_exec_context_set_transient_property( } return 1; + } else if (streq(name, "SyslogIdentifier")) { + const char *id; + + r = sd_bus_message_read(message, "s", &id); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + + if (isempty(id)) { + c->syslog_identifier = mfree(c->syslog_identifier); + } else { + char *t; + + t = strdup(id); + if (!t) + return -ENOMEM; + + free(c->syslog_identifier); + c->syslog_identifier = t; + } + + unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id); + } + + return 1; + } else if (streq(name, "SyslogLevel")) { + int level; + + r = sd_bus_message_read(message, "i", &level); + if (r < 0) + return r; + + if (!log_level_is_valid(level)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range"); + + if (mode != UNIT_CHECK) { + c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level; + unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level); + } + + return 1; + } else if (streq(name, "SyslogFacility")) { + int facility; + + r = sd_bus_message_read(message, "i", &facility); + if (r < 0) + return r; + + if (!log_facility_unshifted_is_valid(facility)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range"); + if (mode != UNIT_CHECK) { + c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority); + unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility); + } + + return 1; } else if (streq(name, "Nice")) { int n; @@ -847,8 +936,7 @@ int bus_exec_context_set_transient_property( return 1; - } else if (STR_IN_SET(name, - "TTYPath", "WorkingDirectory", "RootDirectory")) { + } else if (STR_IN_SET(name, "TTYPath", "RootDirectory")) { const char *s; r = sd_bus_message_read(message, "s", &s); @@ -859,24 +947,51 @@ int bus_exec_context_set_transient_property( return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name); if (mode != UNIT_CHECK) { - char *t; + if (streq(name, "TTYPath")) + r = free_and_strdup(&c->tty_path, s); + else { + assert(streq(name, "RootDirectory")); + r = free_and_strdup(&c->root_directory, s); + } + if (r < 0) + return r; - t = strdup(s); - if (!t) - return -ENOMEM; + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + } + + return 1; + + } else if (streq(name, "WorkingDirectory")) { + const char *s; + bool missing_ok; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + if (s[0] == '-') { + missing_ok = true; + s++; + } else + missing_ok = false; + + if (!streq(s, "~") && !path_is_absolute(s)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'"); + + if (mode != UNIT_CHECK) { + if (streq(s, "~")) { + c->working_directory = mfree(c->working_directory); + c->working_directory_home = true; + } else { + r = free_and_strdup(&c->working_directory, s); + if (r < 0) + return r; - if (streq(name, "TTYPath")) { - free(c->tty_path); - c->tty_path = t; - } else if (streq(name, "WorkingDirectory")) { - free(c->working_directory); - c->working_directory = t; - } else if (streq(name, "RootDirectory")) { - free(c->root_directory); - c->root_directory = t; + c->working_directory_home = false; } - unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + c->working_directory_missing_ok = missing_ok; + unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s); } return 1; @@ -945,7 +1060,7 @@ int bus_exec_context_set_transient_property( } else if (STR_IN_SET(name, "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "PrivateTmp", "PrivateDevices", "PrivateNetwork", - "NoNewPrivileges")) { + "NoNewPrivileges", "SyslogLevelPrefix")) { int b; r = sd_bus_message_read(message, "b", &b); @@ -967,6 +1082,8 @@ int bus_exec_context_set_transient_property( c->private_network = b; else if (streq(name, "NoNewPrivileges")) c->no_new_privileges = b; + else if (streq(name, "SyslogLevelPrefix")) + c->syslog_level_prefix = b; unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b)); } @@ -1044,18 +1161,267 @@ int bus_exec_context_set_transient_property( _cleanup_free_ char *joined = NULL; char **e; - e = strv_env_merge(2, c->environment, l); - if (!e) - return -ENOMEM; + if (strv_length(l) == 0) { + c->environment = strv_free(c->environment); + unit_write_drop_in_private_format(u, mode, name, "Environment=\n"); + } else { + e = strv_env_merge(2, c->environment, l); + if (!e) + return -ENOMEM; - strv_free(c->environment); - c->environment = e; + strv_free(c->environment); + c->environment = e; - joined = strv_join_quoted(c->environment); - if (!joined) - return -ENOMEM; + joined = strv_join_quoted(c->environment); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined); + } + } + + return 1; + + } else if (streq(name, "TimerSlackNSec")) { + + nsec_t n; + + r = sd_bus_message_read(message, "t", &n); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + c->timer_slack_nsec = n; + unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n); + } + + return 1; + + } else if (streq(name, "OOMScoreAdjust")) { + int oa; + + r = sd_bus_message_read(message, "i", &oa); + if (r < 0) + return r; + + if (!oom_score_adjust_is_valid(oa)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range"); - unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined); + if (mode != UNIT_CHECK) { + c->oom_score_adjust = oa; + c->oom_score_adjust_set = true; + unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa); + } + + return 1; + + } else if (streq(name, "EnvironmentFiles")) { + + _cleanup_free_ char *joined = NULL; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char **l = NULL; + size_t size = 0; + char **i; + + r = sd_bus_message_enter_container(message, 'a', "(sb)"); + if (r < 0) + return r; + + f = open_memstream(&joined, &size); + if (!f) + return -ENOMEM; + + STRV_FOREACH(i, c->environment_files) + fprintf(f, "EnvironmentFile=%s\n", *i); + + while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) { + const char *path; + int b; + + r = sd_bus_message_read(message, "sb", &path, &b); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (!isempty(path) && !path_is_absolute(path)) + return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path); + + if (mode != UNIT_CHECK) { + char *buf = NULL; + + buf = strjoin(b ? "-" : "", path, NULL); + if (!buf) + return -ENOMEM; + + fprintf(f, "EnvironmentFile=%s\n", buf); + + r = strv_consume(&l, buf); + if (r < 0) + return r; + } + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + r = fflush_and_check(f); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + if (strv_isempty(l)) { + c->environment_files = strv_free(c->environment_files); + unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n"); + } else { + r = strv_extend_strv(&c->environment_files, l, true); + if (r < 0) + return r; + + unit_write_drop_in_private(u, mode, name, joined); + } + } + + return 1; + + } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { + + _cleanup_strv_free_ char **l = NULL; + char ***dirs; + char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + STRV_FOREACH(p, l) { + int offset; + if (!utf8_is_valid(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name); + + offset = **p == '-'; + if (!path_is_absolute(*p + offset)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name); + } + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + + if (streq(name, "ReadWriteDirectories")) + dirs = &c->read_write_dirs; + else if (streq(name, "ReadOnlyDirectories")) + dirs = &c->read_only_dirs; + else if (streq(name, "InaccessibleDirectories")) + dirs = &c->inaccessible_dirs; + + if (strv_length(l) == 0) { + *dirs = strv_free(*dirs); + unit_write_drop_in_private_format(u, mode, name, "%s=\n", name); + } else { + r = strv_extend_strv(dirs, l, true); + + if (r < 0) + return -ENOMEM; + + joined = strv_join_quoted(*dirs); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined); + } + + } + + return 1; + + } else if (streq(name, "ProtectSystem")) { + const char *s; + ProtectSystem ps; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + r = parse_boolean(s); + if (r > 0) + ps = PROTECT_SYSTEM_YES; + else if (r == 0) + ps = PROTECT_SYSTEM_NO; + else { + ps = protect_system_from_string(s); + if (ps < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect system value"); + } + + if (mode != UNIT_CHECK) { + c->protect_system = ps; + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + } + + return 1; + + } else if (streq(name, "ProtectHome")) { + const char *s; + ProtectHome ph; + + r = sd_bus_message_read(message, "s", &s); + if (r < 0) + return r; + + r = parse_boolean(s); + if (r > 0) + ph = PROTECT_HOME_YES; + else if (r == 0) + ph = PROTECT_HOME_NO; + else { + ph = protect_home_from_string(s); + if (ph < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect home value"); + } + + if (mode != UNIT_CHECK) { + c->protect_home = ph; + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s); + } + + return 1; + + } else if (streq(name, "RuntimeDirectory")) { + _cleanup_strv_free_ char **l = NULL; + char **p; + + r = sd_bus_message_read_strv(message, &l); + if (r < 0) + return r; + + STRV_FOREACH(p, l) { + if (!filename_is_valid(*p)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p); + } + + if (mode != UNIT_CHECK) { + _cleanup_free_ char *joined = NULL; + + if (strv_isempty(l)) { + c->runtime_directory = strv_free(c->runtime_directory); + unit_write_drop_in_private_format(u, mode, name, "%s=\n", name); + } else { + r = strv_extend_strv(&c->runtime_directory, l, true); + + if (r < 0) + return -ENOMEM; + + joined = strv_join_quoted(c->runtime_directory); + if (!joined) + return -ENOMEM; + + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined); + } } return 1; diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index e4c2d5ddf6..c44517ea22 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "execute.h" #define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \ diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index cd6b909426..8c30d66250 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -19,12 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" #include "sd-bus.h" -#include "selinux-access.h" -#include "job.h" + +#include "alloc-util.h" #include "dbus-job.h" #include "dbus.h" +#include "job.h" +#include "log.h" +#include "selinux-access.h" +#include "string-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState); diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h index fb5f1b513e..0f2fbe2ee2 100644 --- a/src/core/dbus-job.h +++ b/src/core/dbus-job.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "job.h" extern const sd_bus_vtable bus_job_vtable[]; diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h index 7c15f3a90b..794c402048 100644 --- a/src/core/dbus-kill.h +++ b/src/core/dbus-kill.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" #include "kill.h" diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 561b6f8bfa..1f9f25093d 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -20,27 +20,34 @@ ***/ #include <errno.h> +#include <sys/prctl.h> #include <unistd.h> -#include "log.h" -#include "strv.h" +#include "alloc-util.h" +#include "architecture.h" #include "build.h" -#include "install.h" -#include "selinux-access.h" -#include "watchdog.h" +#include "bus-common-errors.h" #include "clock-util.h" -#include "path-util.h" -#include "virt.h" -#include "architecture.h" -#include "env-util.h" -#include "dbus.h" +#include "dbus-execute.h" #include "dbus-job.h" #include "dbus-manager.h" -#include "dbus-unit.h" #include "dbus-snapshot.h" -#include "dbus-execute.h" -#include "bus-common-errors.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "env-util.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "install.h" +#include "log.h" +#include "path-util.h" +#include "selinux-access.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "syslog-util.h" +#include "virt.h" +#include "watchdog.h" static int property_get_version( sd_bus *bus, @@ -81,10 +88,21 @@ static int property_get_virtualization( void *userdata, sd_bus_error *error) { + int v; + assert(bus); assert(reply); - return sd_bus_message_append(reply, "s", virtualization_to_string(detect_virtualization())); + v = detect_virtualization(); + + /* Make sure to return the empty string when we detect no virtualization, as that is the API. + * + * https://github.com/systemd/systemd/issues/1423 + */ + + return sd_bus_message_append( + reply, "s", + v == VIRTUALIZATION_NONE ? "" : virtualization_to_string(v)); } static int property_get_architecture( @@ -111,8 +129,7 @@ static int property_get_tainted( void *userdata, sd_bus_error *error) { - char buf[sizeof("split-usr:mtab-not-symlink:cgroups-missing:local-hwclock:")] = "", *e = buf; - _cleanup_free_ char *p = NULL; + char buf[sizeof("split-usr:cgroups-missing:local-hwclock:")] = "", *e = buf; Manager *m = userdata; assert(bus); @@ -122,9 +139,6 @@ static int property_get_tainted( if (m->taint_usr) e = stpcpy(e, "split-usr:"); - if (readlink_malloc("/etc/mtab", &p) < 0) - e = stpcpy(e, "mtab-not-symlink:"); - if (access("/proc/cgroups", F_OK) < 0) e = stpcpy(e, "cgroups-missing:"); @@ -339,6 +353,21 @@ static int property_set_runtime_watchdog( return watchdog_set_timeout(t); } +static int property_get_timer_slack_nsec( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + assert(bus); + assert(reply); + + return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK)); +} + static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_free_ char *path = NULL; Manager *m = userdata; @@ -1960,6 +1989,33 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0), SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0), SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0), + SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index 24813c6d20..0c91850c52 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -19,13 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "mount.h" +#include "bus-util.h" +#include "dbus-cgroup.h" #include "dbus-execute.h" #include "dbus-kill.h" -#include "dbus-cgroup.h" +#include "mount.h" +#include "string-util.h" +#include "unit.h" #include "dbus-mount.h" -#include "bus-util.h" static int property_get_what( sd_bus *bus, @@ -117,6 +118,7 @@ const sd_bus_vtable bus_mount_vtable[] = { SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Mount, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Mount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("SmackFileSystemRootLabel", "s", NULL, offsetof(Mount, smack_fs_root_label), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_EXEC_COMMAND_VTABLE("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_VTABLE("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h index f7004d252f..dd0bf51bb0 100644 --- a/src/core/dbus-mount.h +++ b/src/core/dbus-mount.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_mount_vtable[]; diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c index 683561999b..9e32b5fb06 100644 --- a/src/core/dbus-path.c +++ b/src/core/dbus-path.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" +#include "bus-util.h" #include "path.h" +#include "string-util.h" +#include "unit.h" #include "dbus-path.h" -#include "bus-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult); diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c index f8fb373bf0..16375b2311 100644 --- a/src/core/dbus-scope.c +++ b/src/core/dbus-scope.c @@ -19,17 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "selinux-access.h" -#include "unit.h" -#include "scope.h" -#include "dbus.h" -#include "bus-util.h" -#include "bus-internal.h" +#include "alloc-util.h" #include "bus-common-errors.h" -#include "dbus-unit.h" +#include "bus-internal.h" +#include "bus-util.h" #include "dbus-cgroup.h" #include "dbus-kill.h" #include "dbus-scope.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "scope.h" +#include "selinux-access.h" +#include "unit.h" static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) { Scope *s = userdata; diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 3436342bef..24f611a593 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -19,15 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" -#include "path-util.h" -#include "unit.h" -#include "service.h" +#include "alloc-util.h" +#include "async.h" +#include "bus-util.h" +#include "dbus-cgroup.h" #include "dbus-execute.h" #include "dbus-kill.h" -#include "dbus-cgroup.h" #include "dbus-service.h" -#include "bus-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "path-util.h" +#include "service.h" +#include "string-util.h" +#include "strv.h" +#include "unit.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult); @@ -58,7 +63,8 @@ const sd_bus_vtable bus_service_vtable[] = { SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", NULL, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0), SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -120,6 +126,37 @@ static int bus_service_set_transient_property( return 1; + } else if (STR_IN_SET(name, + "StandardInputFileDescriptor", + "StandardOutputFileDescriptor", + "StandardErrorFileDescriptor")) { + int fd; + + r = sd_bus_message_read(message, "h", &fd); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + int copy; + + copy = fcntl(fd, F_DUPFD_CLOEXEC, 3); + if (copy < 0) + return -errno; + + if (streq(name, "StandardInputFileDescriptor")) { + asynchronous_close(s->stdin_fd); + s->stdin_fd = copy; + } else if (streq(name, "StandardOutputFileDescriptor")) { + asynchronous_close(s->stdout_fd); + s->stdout_fd = copy; + } else { + asynchronous_close(s->stderr_fd); + s->stderr_fd = copy; + } + } + + return 1; + } else if (streq(name, "ExecStart")) { unsigned n = 0; @@ -211,7 +248,9 @@ static int bus_service_set_transient_property( a); } - fflush(f); + r = fflush_and_check(f); + if (r < 0) + return r; unit_write_drop_in_private(UNIT(s), mode, name, buf); } diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index 86732e2a45..be5ef261a6 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "socket.h" -#include "dbus-execute.h" +#include "alloc-util.h" +#include "bus-util.h" #include "dbus-cgroup.h" +#include "dbus-execute.h" #include "dbus-socket.h" -#include "bus-util.h" +#include "socket.h" +#include "string-util.h" +#include "unit.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only); @@ -84,6 +86,25 @@ static int property_get_listen( return sd_bus_message_close_container(reply); } + +static int property_get_fdname( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Socket *s = SOCKET(userdata); + + assert(bus); + assert(reply); + assert(s); + + return sd_bus_message_append(reply, "s", socket_fdname(s)); +} + const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST), @@ -95,6 +116,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("KeepAliveIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_interval), SD_BUS_VTABLE_PROPERTY_CONST), @@ -127,6 +149,7 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0), SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0), + SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index 0093371306..603ca95fd9 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -20,12 +20,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "swap.h" -#include "dbus-execute.h" +#include "bus-util.h" #include "dbus-cgroup.h" +#include "dbus-execute.h" +#include "string-util.h" +#include "swap.h" +#include "unit.h" #include "dbus-swap.h" -#include "bus-util.h" static int property_get_priority( sd_bus *bus, diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h index 4c4297bc9e..6be9c9f708 100644 --- a/src/core/dbus-target.h +++ b/src/core/dbus-target.h @@ -21,5 +21,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-bus.h" extern const sd_bus_vtable bus_target_vtable[]; diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index 8ea2cf84a4..a8a280d961 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "timer.h" -#include "dbus-timer.h" +#include "alloc-util.h" #include "bus-util.h" +#include "dbus-timer.h" #include "strv.h" +#include "timer.h" +#include "unit.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult); diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index cd88a87340..6320cd1aa9 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -20,14 +20,19 @@ ***/ #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "cgroup-util.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "locale-util.h" #include "log.h" #include "selinux-access.h" -#include "cgroup-util.h" -#include "strv.h" -#include "bus-common-errors.h" #include "special.h" -#include "dbus.h" -#include "dbus-unit.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); @@ -679,7 +684,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("NetClass", "u", bus_property_get_unsigned, offsetof(Unit, cgroup_netclass_id), 0), + SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0), SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED), @@ -984,7 +989,8 @@ int bus_unit_queue_job( if ((type == JOB_START && u->refuse_manual_start) || (type == JOB_STOP && u->refuse_manual_stop) || - ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop))) + ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || + (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id); r = manager_add_job(u->manager, type, u, mode, true, error, &j); diff --git a/src/core/dbus.c b/src/core/dbus.c index 2d6a1ff836..6c44b28adf 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -19,29 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/epoll.h> #include <errno.h> +#include <sys/epoll.h> #include <unistd.h> #include "sd-bus.h" -#include "log.h" -#include "strv.h" -#include "mkdir.h" -#include "missing.h" -#include "dbus-unit.h" -#include "dbus-job.h" -#include "dbus-manager.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-error.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "dbus-cgroup.h" #include "dbus-execute.h" +#include "dbus-job.h" #include "dbus-kill.h" -#include "dbus-cgroup.h" -#include "special.h" +#include "dbus-manager.h" +#include "dbus-unit.h" #include "dbus.h" -#include "bus-util.h" -#include "bus-error.h" -#include "bus-common-errors.h" -#include "strxcpyx.h" -#include "bus-internal.h" +#include "fd-util.h" +#include "log.h" +#include "missing.h" +#include "mkdir.h" #include "selinux-access.h" +#include "special.h" +#include "string-util.h" +#include "strv.h" +#include "strxcpyx.h" +#include "user-util.h" #define CONNECTIONS_MAX 4096 @@ -777,9 +782,9 @@ static int bus_setup_api(Manager *m, sd_bus *bus) { return r; HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) { - r = unit_install_bus_match(bus, u, name); + r = unit_install_bus_match(u, bus, name); if (r < 0) - log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m"); + log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name); } r = sd_bus_add_match( diff --git a/src/core/device.c b/src/core/device.c index 0b54518691..23ee7aee7e 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -21,16 +21,21 @@ #include <errno.h> #include <sys/epoll.h> -#include <libudev.h> -#include "log.h" -#include "unit-name.h" +#include "libudev.h" + +#include "alloc-util.h" #include "dbus-device.h" +#include "device.h" +#include "log.h" +#include "parse-util.h" #include "path-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "swap.h" #include "udev-util.h" +#include "unit-name.h" #include "unit.h" -#include "swap.h" -#include "device.h" static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = { [DEVICE_DEAD] = UNIT_INACTIVE, @@ -816,14 +821,6 @@ int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, return device_update_found_by_name(m, node, add, found, now); } -static const char* const device_state_table[_DEVICE_STATE_MAX] = { - [DEVICE_DEAD] = "dead", - [DEVICE_TENTATIVE] = "tentative", - [DEVICE_PLUGGED] = "plugged", -}; - -DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState); - const UnitVTable device_vtable = { .object_size = sizeof(Device), .sections = diff --git a/src/core/device.h b/src/core/device.h index 10ab113176..da8737870b 100644 --- a/src/core/device.h +++ b/src/core/device.h @@ -23,16 +23,6 @@ typedef struct Device Device; -/* We simply watch devices, we cannot plug/unplug them. That - * simplifies the state engine greatly */ -typedef enum DeviceState { - DEVICE_DEAD, - DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ - DEVICE_PLUGGED, /* announced by udev */ - _DEVICE_STATE_MAX, - _DEVICE_STATE_INVALID = -1 -} DeviceState; - typedef enum DeviceFound { DEVICE_NOT_FOUND = 0, DEVICE_FOUND_UDEV = 1, @@ -56,7 +46,4 @@ struct Device { extern const UnitVTable device_vtable; -const char* device_state_to_string(DeviceState i) _const_; -DeviceState device_state_from_string(const char *s) _pure_; - int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now); diff --git a/src/core/execute.c b/src/core/execute.c index 7796c07fcf..d751065af0 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -21,18 +21,18 @@ #include <errno.h> #include <fcntl.h> -#include <unistd.h> -#include <string.h> +#include <glob.h> +#include <grp.h> +#include <poll.h> #include <signal.h> -#include <sys/socket.h> -#include <sys/un.h> +#include <string.h> +#include <sys/personality.h> #include <sys/prctl.h> +#include <sys/socket.h> #include <sys/stat.h> -#include <grp.h> -#include <poll.h> -#include <glob.h> +#include <sys/un.h> +#include <unistd.h> #include <utmpx.h> -#include <sys/personality.h> #ifdef HAVE_PAM #include <security/pam_appl.h> @@ -50,47 +50,56 @@ #include <sys/apparmor.h> #endif -#include "barrier.h" #include "sd-messages.h" -#include "rm-rf.h" -#include "strv.h" -#include "macro.h" -#include "capability.h" -#include "util.h" -#include "log.h" -#include "ioprio.h" -#include "securebits.h" -#include "namespace.h" -#include "exit-status.h" -#include "missing.h" -#include "utmp-wtmp.h" -#include "def.h" -#include "path-util.h" -#include "env-util.h" -#include "fileio.h" -#include "unit.h" -#include "async.h" -#include "selinux-util.h" -#include "errno-list.h" + #include "af-list.h" -#include "mkdir.h" -#include "smack-util.h" +#include "alloc-util.h" +#ifdef HAVE_APPARMOR +#include "apparmor-util.h" +#endif +#include "async.h" +#include "barrier.h" #include "bus-endpoint.h" #include "cap-list.h" +#include "capability-util.h" +#include "def.h" +#include "env-util.h" +#include "errno-list.h" +#include "execute.h" +#include "exit-status.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "glob-util.h" +#include "io-util.h" +#include "ioprio.h" +#include "log.h" +#include "macro.h" +#include "missing.h" +#include "mkdir.h" +#include "namespace.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" -#include "terminal-util.h" -#include "signal-util.h" - -#ifdef HAVE_APPARMOR -#include "apparmor-util.h" -#endif - +#include "rlimit-util.h" +#include "rm-rf.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif - -#include "execute.h" +#include "securebits.h" +#include "selinux-util.h" +#include "signal-util.h" +#include "smack-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "syslog-util.h" +#include "terminal-util.h" +#include "unit.h" +#include "user-util.h" +#include "util.h" +#include "utmp-wtmp.h" #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC) #define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC) @@ -358,12 +367,28 @@ static int fixup_output(ExecOutput std_output, int socket_fd) { return std_output; } -static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) { +static int setup_input( + const ExecContext *context, + const ExecParameters *params, + int socket_fd) { + ExecInput i; assert(context); + assert(params); - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); + if (params->stdin_fd >= 0) { + if (dup2(params->stdin_fd, STDIN_FILENO) < 0) + return -errno; + + /* Try to make this the controlling tty, if it is a tty, and reset it */ + (void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE); + (void) reset_terminal_fd(STDIN_FILENO, true); + + return STDIN_FILENO; + } + + i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin); switch (i) { @@ -400,16 +425,40 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty } } -static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) { +static int setup_output( + Unit *unit, + const ExecContext *context, + const ExecParameters *params, + int fileno, + int socket_fd, + const char *ident, + uid_t uid, gid_t gid) { + ExecOutput o; ExecInput i; int r; assert(unit); assert(context); + assert(params); assert(ident); - i = fixup_input(context->std_input, socket_fd, apply_tty_stdin); + if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) { + + if (dup2(params->stdout_fd, STDOUT_FILENO) < 0) + return -errno; + + return STDOUT_FILENO; + } + + if (fileno == STDERR_FILENO && params->stderr_fd >= 0) { + if (dup2(params->stderr_fd, STDERR_FILENO) < 0) + return -errno; + + return STDERR_FILENO; + } + + i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin); o = fixup_output(context->std_output, socket_fd); if (fileno == STDERR_FILENO) { @@ -502,9 +551,9 @@ static int chown_terminal(int fd, uid_t uid) { return 0; } -static int setup_confirm_stdio(int *_saved_stdin, - int *_saved_stdout) { - int fd = -1, saved_stdin, saved_stdout = -1, r; +static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) { + _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1; + int r; assert(_saved_stdin); assert(_saved_stdout); @@ -514,10 +563,8 @@ static int setup_confirm_stdio(int *_saved_stdin, return -errno; saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3); - if (saved_stdout < 0) { - r = errno; - goto fail; - } + if (saved_stdout < 0) + return -errno; fd = acquire_terminal( "/dev/console", @@ -525,39 +572,33 @@ static int setup_confirm_stdio(int *_saved_stdin, false, false, DEFAULT_CONFIRM_USEC); - if (fd < 0) { - r = fd; - goto fail; - } + if (fd < 0) + return fd; r = chown_terminal(fd, getuid()); if (r < 0) - goto fail; + return r; - if (dup2(fd, STDIN_FILENO) < 0) { - r = -errno; - goto fail; - } + r = reset_terminal_fd(fd, true); + if (r < 0) + return r; - if (dup2(fd, STDOUT_FILENO) < 0) { - r = -errno; - goto fail; - } + if (dup2(fd, STDIN_FILENO) < 0) + return -errno; + + if (dup2(fd, STDOUT_FILENO) < 0) + return -errno; if (fd >= 2) safe_close(fd); + fd = -1; *_saved_stdin = saved_stdin; *_saved_stdout = saved_stdout; - return 0; - -fail: - safe_close(saved_stdout); - safe_close(saved_stdin); - safe_close(fd); + saved_stdin = saved_stdout = -1; - return r; + return 0; } _printf_(1, 2) static int write_confirm_message(const char *format, ...) { @@ -577,9 +618,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) { return 0; } -static int restore_confirm_stdio(int *saved_stdin, - int *saved_stdout) { - +static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) { int r = 0; assert(saved_stdin); @@ -595,8 +634,8 @@ static int restore_confirm_stdio(int *saved_stdin, if (dup2(*saved_stdout, STDOUT_FILENO) < 0) r = -errno; - safe_close(*saved_stdin); - safe_close(*saved_stdout); + *saved_stdin = safe_close(*saved_stdin); + *saved_stdout = safe_close(*saved_stdout); return r; } @@ -1198,6 +1237,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { static int build_environment( const ExecContext *c, unsigned n_fds, + char ** fd_names, usec_t watchdog_usec, const char *home, const char *username, @@ -1211,11 +1251,13 @@ static int build_environment( assert(c); assert(ret); - our_env = new0(char*, 10); + our_env = new0(char*, 11); if (!our_env) return -ENOMEM; if (n_fds > 0) { + _cleanup_free_ char *joined = NULL; + if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0) return -ENOMEM; our_env[n_env++] = x; @@ -1223,6 +1265,15 @@ static int build_environment( if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0) return -ENOMEM; our_env[n_env++] = x; + + joined = strv_join(fd_names, ":"); + if (!joined) + return -ENOMEM; + + x = strjoin("LISTEN_FDNAMES=", joined, NULL); + if (!x) + return -ENOMEM; + our_env[n_env++] = x; } if (watchdog_usec > 0) { @@ -1273,7 +1324,7 @@ static int build_environment( } our_env[n_env++] = NULL; - assert(n_env <= 10); + assert(n_env <= 11); *ret = our_env; our_env = NULL; @@ -1311,6 +1362,44 @@ static bool exec_needs_mount_namespace( return false; } +static int close_remaining_fds( + const ExecParameters *params, + ExecRuntime *runtime, + int socket_fd, + int *fds, unsigned n_fds) { + + unsigned n_dont_close = 0; + int dont_close[n_fds + 7]; + + assert(params); + + if (params->stdin_fd >= 0) + dont_close[n_dont_close++] = params->stdin_fd; + if (params->stdout_fd >= 0) + dont_close[n_dont_close++] = params->stdout_fd; + if (params->stderr_fd >= 0) + dont_close[n_dont_close++] = params->stderr_fd; + + if (socket_fd >= 0) + dont_close[n_dont_close++] = socket_fd; + if (n_fds > 0) { + memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); + n_dont_close += n_fds; + } + + if (params->bus_endpoint_fd >= 0) + dont_close[n_dont_close++] = params->bus_endpoint_fd; + + if (runtime) { + if (runtime->netns_storage_socket[0] >= 0) + dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; + if (runtime->netns_storage_socket[1] >= 0) + dont_close[n_dont_close++] = runtime->netns_storage_socket[1]; + } + + return close_all_fds(dont_close, n_dont_close); +} + static int exec_child( Unit *unit, ExecCommand *command, @@ -1325,9 +1414,7 @@ static int exec_child( _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL; _cleanup_free_ char *mac_selinux_context_net = NULL; - const char *username = NULL, *home = NULL, *shell = NULL; - unsigned n_dont_close = 0; - int dont_close[n_fds + 4]; + const char *username = NULL, *home = NULL, *shell = NULL, *wd; uid_t uid = UID_INVALID; gid_t gid = GID_INVALID; int i, r; @@ -1367,22 +1454,7 @@ static int exec_child( log_forget_fds(); - if (socket_fd >= 0) - dont_close[n_dont_close++] = socket_fd; - if (n_fds > 0) { - memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); - n_dont_close += n_fds; - } - if (params->bus_endpoint_fd >= 0) - dont_close[n_dont_close++] = params->bus_endpoint_fd; - if (runtime) { - if (runtime->netns_storage_socket[0] >= 0) - dont_close[n_dont_close++] = runtime->netns_storage_socket[0]; - if (runtime->netns_storage_socket[1] >= 0) - dont_close[n_dont_close++] = runtime->netns_storage_socket[1]; - } - - r = close_all_fds(dont_close, n_dont_close); + r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds); if (r < 0) { *exit_status = EXIT_FDS; return r; @@ -1438,21 +1510,21 @@ static int exec_child( /* If a socket is connected to STDIN/STDOUT/STDERR, we * must sure to drop O_NONBLOCK */ if (socket_fd >= 0) - fd_nonblock(socket_fd, false); + (void) fd_nonblock(socket_fd, false); - r = setup_input(context, socket_fd, params->apply_tty_stdin); + r = setup_input(context, params, socket_fd); if (r < 0) { *exit_status = EXIT_STDIN; return r; } - r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid); + r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid); if (r < 0) { *exit_status = EXIT_STDOUT; return r; } - r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid); + r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid); if (r < 0) { *exit_status = EXIT_STDERR; return r; @@ -1698,6 +1770,13 @@ static int exec_child( } } + if (context->working_directory_home) + wd = home; + else if (context->working_directory) + wd = context->working_directory; + else + wd = "/"; + if (params->apply_chroot) { if (!needs_mount_namespace && context->root_directory) if (chroot(context->root_directory) < 0) { @@ -1705,21 +1784,15 @@ static int exec_child( return -errno; } - if (chdir(context->working_directory ?: "/") < 0 && + if (chdir(wd) < 0 && !context->working_directory_missing_ok) { *exit_status = EXIT_CHDIR; return -errno; } } else { - _cleanup_free_ char *d = NULL; - - if (asprintf(&d, "%s/%s", - context->root_directory ?: "", - context->working_directory ?: "") < 0) { - *exit_status = EXIT_MEMORY; - return -ENOMEM; - } + const char *d; + d = strjoina(strempty(context->root_directory), "/", strempty(wd)); if (chdir(d) < 0 && !context->working_directory_missing_ok) { *exit_status = EXIT_CHDIR; @@ -1849,7 +1922,7 @@ static int exec_child( #endif } - r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env); + r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env); if (r < 0) { *exit_status = EXIT_MEMORY; return r; @@ -2249,7 +2322,7 @@ static void strv_fprintf(FILE *f, char **l) { } void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { - char **e; + char **e, **d; unsigned i; assert(c); @@ -2285,6 +2358,11 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { STRV_FOREACH(e, c->environment_files) fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e); + fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode); + + STRV_FOREACH(d, c->runtime_directory) + fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d); + if (c->nice_set) fprintf(f, "%sNice: %i\n", @@ -2711,7 +2789,7 @@ int exec_command_append(ExecCommand *c, const char *path, ...) { if (!l) return -ENOMEM; - r = strv_extend_strv(&c->argv, l); + r = strv_extend_strv(&c->argv, l, false); if (r < 0) return r; diff --git a/src/core/execute.h b/src/core/execute.h index a750246a89..f8995a4203 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -103,6 +103,7 @@ struct ExecContext { struct rlimit *rlimit[_RLIMIT_MAX]; char *working_directory, *root_directory; bool working_directory_missing_ok; + bool working_directory_home; mode_t umask; int oom_score_adjust; @@ -207,21 +208,35 @@ struct ExecContext { struct ExecParameters { char **argv; - int *fds; unsigned n_fds; char **environment; - bool apply_permissions; - bool apply_chroot; - bool apply_tty_stdin; - bool confirm_spawn; - bool selinux_context_net; + + int *fds; + char **fd_names; + unsigned n_fds; + + bool apply_permissions:1; + bool apply_chroot:1; + bool apply_tty_stdin:1; + + bool confirm_spawn:1; + bool selinux_context_net:1; + + bool cgroup_delegate:1; CGroupMask cgroup_supported; const char *cgroup_path; - bool cgroup_delegate; + const char *runtime_prefix; + usec_t watchdog_usec; + int *idle_pipe; + char *bus_endpoint_path; int bus_endpoint_fd; + + int stdin_fd; + int stdout_fd; + int stderr_fd; }; int exec_spawn(Unit *unit, diff --git a/src/core/failure-action.c b/src/core/failure-action.c index 3412accf3e..c7c95984b7 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -23,10 +23,11 @@ #include <sys/reboot.h> #include <linux/reboot.h> -#include "bus-util.h" #include "bus-error.h" -#include "special.h" +#include "bus-util.h" #include "failure-action.h" +#include "special.h" +#include "string-table.h" #include "terminal-util.h" static void log_and_status(Manager *m, const char *message) { diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c index 932ddbf95a..3645f9c515 100644 --- a/src/core/hostname-setup.c +++ b/src/core/hostname-setup.c @@ -19,15 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> +#include <stdio.h> #include <stdlib.h> -#include "macro.h" -#include "util.h" -#include "log.h" +#include "alloc-util.h" #include "fileio.h" #include "hostname-util.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" +#include "util.h" #include "hostname-setup.h" int hostname_setup(void) { @@ -59,8 +61,9 @@ int hostname_setup(void) { hn = "localhost"; } - if (sethostname_idempotent(hn) < 0) - return log_warning_errno(errno, "Failed to set hostname to <%s>: %m", hn); + r = sethostname_idempotent(hn); + if (r < 0) + return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn); log_info("Set hostname to <%s>.", hn); return 0; diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c index 42a3e97459..9572fa17d9 100644 --- a/src/core/ima-setup.c +++ b/src/core/ima-setup.c @@ -24,9 +24,11 @@ #include <unistd.h> #include <errno.h> +#include "fd-util.h" +#include "fileio.h" #include "ima-setup.h" -#include "util.h" #include "log.h" +#include "util.h" #define IMA_SECFS_DIR "/sys/kernel/security/ima" #define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy" diff --git a/src/core/job.c b/src/core/job.c index 558d8d2d52..120381fc3b 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -23,17 +23,24 @@ #include "sd-id128.h" #include "sd-messages.h" -#include "set.h" -#include "unit.h" -#include "macro.h" -#include "strv.h" -#include "log.h" -#include "dbus-job.h" -#include "special.h" + +#include "alloc-util.h" #include "async.h" -#include "virt.h" +#include "dbus-job.h" #include "dbus.h" +#include "escape.h" +#include "job.h" +#include "log.h" +#include "macro.h" +#include "parse-util.h" +#include "set.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" +#include "unit.h" +#include "virt.h" Job* job_new_raw(Unit *unit) { Job *j; diff --git a/src/core/job.h b/src/core/job.h index 1d1b10f1d3..350e9f385f 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -23,6 +23,10 @@ #include <stdbool.h> +#include "sd-event.h" + +#include "list.h" + typedef struct Job Job; typedef struct JobDependency JobDependency; typedef enum JobType JobType; @@ -105,9 +109,7 @@ enum JobResult { _JOB_RESULT_INVALID = -1 }; -#include "sd-event.h" #include "unit.h" -#include "list.h" struct JobDependency { /* Encodes that the 'subject' job needs the 'object' job in diff --git a/src/core/kill.c b/src/core/kill.c index bddfa4460f..1466d5ce64 100644 --- a/src/core/kill.c +++ b/src/core/kill.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "signal-util.h" #include "kill.h" +#include "signal-util.h" +#include "string-table.h" +#include "util.h" void kill_context_init(KillContext *c) { assert(c); diff --git a/src/core/killall.c b/src/core/killall.c index ee5d388560..77f145b4d1 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -19,17 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/wait.h> -#include <signal.h> #include <errno.h> +#include <signal.h> +#include <sys/wait.h> #include <unistd.h> -#include "util.h" -#include "killall.h" -#include "set.h" +#include "alloc-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "killall.h" +#include "parse-util.h" #include "process-util.h" +#include "set.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" #define TIMEOUT_USEC (10 * USEC_PER_SEC) diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index 2068ffd69b..651f79a1fe 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -27,7 +27,7 @@ #endif #include "macro.h" -#include "capability.h" +#include "capability-util.h" #include "bus-util.h" #include "kmod-setup.h" diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index fd293d8287..5b7954dbf9 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -17,7 +17,7 @@ struct ConfigPerfItem; %% m4_dnl Define the context options only once m4_define(`EXEC_CONTEXT_CONFIG_ITEMS', -`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory) +`$1.WorkingDirectory, config_parse_working_directory, 0, offsetof($1, exec_context) $1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory) $1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user) $1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group) @@ -59,18 +59,18 @@ $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CO $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') $1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) -$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) -$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) -$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) -$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) -$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) +$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) $1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) -$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) +$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) $1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) -$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) +$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) $1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) -$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) +$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) $1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) @@ -261,6 +261,7 @@ Socket.SocketGroup, config_parse_unit_string_printf, 0, Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode) Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode) Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept) +Socket.Writable, config_parse_bool, 0, offsetof(Socket, writable) Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections) Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive) Socket.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Socket, keep_alive_time) @@ -286,6 +287,7 @@ Socket.MessageQueueMaxMessages, config_parse_long, 0, Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize) Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop) Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks) +Socket.FileDescriptorName, config_parse_fdname, 0, 0 Socket.Service, config_parse_socket_service, 0, 0 m4_ifdef(`HAVE_SMACK', `Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) @@ -317,6 +319,7 @@ Mount.Type, config_parse_string, 0, Mount.TimeoutSec, config_parse_sec, 0, offsetof(Mount, timeout_usec) Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode) Mount.SloppyOptions, config_parse_bool, 0, offsetof(Mount, sloppy_options) +Mount.SmackFileSystemRootLabel, config_parse_string, 0, offsetof(Mount, smack_fs_root_label) EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index a13f42b5e0..7f12f26b08 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -20,44 +20,52 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <linux/oom.h> #include <errno.h> -#include <string.h> #include <fcntl.h> -#include <sched.h> #include <linux/fs.h> -#include <sys/stat.h> -#include <sys/resource.h> - +#include <linux/oom.h> #ifdef HAVE_SECCOMP #include <seccomp.h> #endif +#include <sched.h> +#include <string.h> +#include <sys/resource.h> +#include <sys/stat.h> -#include "unit.h" -#include "strv.h" +#include "alloc-util.h" +#include "af-list.h" +#include "bus-error.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "cap-list.h" +#include "cgroup.h" #include "conf-parser.h" +#include "cpu-set-util.h" +#include "env-util.h" +#include "errno-list.h" +#include "escape.h" +#include "fd-util.h" +#include "fs-util.h" +#include "ioprio.h" #include "load-fragment.h" #include "log.h" -#include "ioprio.h" -#include "securebits.h" #include "missing.h" -#include "unit-name.h" -#include "unit-printf.h" -#include "utf8.h" +#include "parse-util.h" #include "path-util.h" -#include "env-util.h" -#include "cgroup.h" -#include "bus-util.h" -#include "bus-error.h" -#include "errno-list.h" -#include "af-list.h" -#include "cap-list.h" -#include "signal-util.h" -#include "bus-internal.h" - +#include "process-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif +#include "securebits.h" +#include "signal-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" +#include "utf8.h" +#include "web-util.h" int config_parse_warn_compat( const char *unit, @@ -74,15 +82,15 @@ int config_parse_warn_compat( switch(reason) { case DISABLED_CONFIGURATION: - log_syntax(unit, LOG_DEBUG, filename, line, EINVAL, + log_syntax(unit, LOG_DEBUG, filename, line, 0, "Support for option %s= has been disabled at compile time and it is ignored", lvalue); break; case DISABLED_LEGACY: - log_syntax(unit, LOG_INFO, filename, line, EINVAL, + log_syntax(unit, LOG_INFO, filename, line, 0, "Support for option %s= has been removed and it is ignored", lvalue); break; case DISABLED_EXPERIMENTAL: - log_syntax(unit, LOG_INFO, filename, line, EINVAL, + log_syntax(unit, LOG_INFO, filename, line, 0, "Support for option %s= has not yet been enabled and it is ignored", lvalue); break; }; @@ -120,18 +128,16 @@ int config_parse_unit_deps(const char *unit, r = unit_name_printf(u, t, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); continue; } r = unit_add_dependency_by_name(u, d, k, NULL, true); if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to add dependency on %s, ignoring: %s", k, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring."); return 0; } @@ -166,16 +172,17 @@ int config_parse_unit_string_printf( return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata); } -int config_parse_unit_strv_printf(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_strv_printf( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { Unit *u = userdata; _cleanup_free_ char *k = NULL; @@ -187,24 +194,25 @@ int config_parse_unit_strv_printf(const char *unit, assert(u); r = unit_full_printf(u, rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; + } - return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, - k ? k : rvalue, data, userdata); + return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata); } -int config_parse_unit_path_printf(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_unit_path_printf( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { _cleanup_free_ char *k = NULL; Unit *u = userdata; @@ -217,7 +225,7 @@ int config_parse_unit_path_printf(const char *unit, r = unit_full_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); return 0; } @@ -256,17 +264,17 @@ int config_parse_unit_path_strv_printf( r = unit_full_printf(u, t, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", t); return 0; } if (!utf8_is_valid(k)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); return 0; } if (!path_is_absolute(k)) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, 0, "Symlink path %s is not absolute, ignoring: %m", k); return 0; } @@ -279,7 +287,7 @@ int config_parse_unit_path_strv_printf( k = NULL; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring."); return 0; } @@ -322,12 +330,8 @@ int config_parse_socket_listen(const char *unit, p->type = ltype; r = unit_full_printf(UNIT(s), rvalue, &p->path); if (r < 0) { - p->path = strdup(rvalue); - if (!p->path) - return log_oom(); - else - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; } path_kill_slashes(p->path); @@ -337,14 +341,14 @@ int config_parse_socket_listen(const char *unit, p->type = SOCKET_SOCKET; r = unit_full_printf(UNIT(s), rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; + } - r = socket_address_parse_netlink(&p->address, k ?: rvalue); + r = socket_address_parse_netlink(&p->address, k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse address value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue); return 0; } @@ -353,14 +357,14 @@ int config_parse_socket_listen(const char *unit, p->type = SOCKET_SOCKET; r = unit_full_printf(UNIT(s), rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r,"Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; + } - r = socket_address_parse_and_warn(&p->address, k ? k : rvalue); + r = socket_address_parse_and_warn(&p->address, k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse address value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue); return 0; } @@ -374,8 +378,7 @@ int config_parse_socket_listen(const char *unit, } if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) { - log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP, - "Address family not supported, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Address family not supported, ignoring: %s", rvalue); return 0; } } @@ -422,8 +425,7 @@ int config_parse_socket_bind(const char *unit, r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse bind IPv6 only value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse bind IPv6 only value, ignoring: %s", rvalue); return 0; } @@ -455,14 +457,12 @@ int config_parse_exec_nice(const char *unit, r = safe_atoi(rvalue, &priority); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse nice priority, ignoring: %s. ", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse nice priority, ignoring: %s", rvalue); return 0; } if (priority < PRIO_MIN || priority >= PRIO_MAX) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "Nice priority out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Nice priority out of range, ignoring: %s", rvalue); return 0; } @@ -493,14 +493,12 @@ int config_parse_exec_oom_score_adjust(const char* unit, r = safe_atoi(rvalue, &oa); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse the OOM score adjust value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue); return 0; } if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "OOM score adjust value out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "OOM score adjust value out of range, ignoring: %s", rvalue); return 0; } @@ -533,9 +531,7 @@ int config_parse_exec( assert(e); e += ltype; - rvalue += strspn(rvalue, WHITESPACE); - p = rvalue; if (isempty(rvalue)) { /* An empty assignment resets the list */ @@ -543,14 +539,15 @@ int config_parse_exec( return 0; } + p = rvalue; do { - int i; + _cleanup_free_ char *path = NULL, *firstword = NULL; + bool separate_argv0 = false, ignore = false; + _cleanup_free_ ExecCommand *nce = NULL; _cleanup_strv_free_ char **n = NULL; size_t nlen = 0, nbufsize = 0; - _cleanup_free_ ExecCommand *nce = NULL; - _cleanup_free_ char *path = NULL, *firstword = NULL; char *f; - bool separate_argv0 = false, ignore = false; + int i; semicolon = false; @@ -574,24 +571,19 @@ int config_parse_exec( if (isempty(f)) { /* First word is either "-" or "@" with no command. */ - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Empty path in command line, ignoring: \"%s\"", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue); return 0; } - if (!string_is_safe(f)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Executable path contains special characters, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue); return 0; } if (!path_is_absolute(f)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Executable path is not absolute, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue); return 0; } if (endswith(f, "/")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Executable path specifies a directory, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue); return 0; } @@ -658,8 +650,7 @@ int config_parse_exec( } if (!n || !n[0]) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Empty executable name or zeroeth argument, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue); return 0; } @@ -743,8 +734,7 @@ int config_parse_exec_io_class(const char *unit, x = ioprio_class_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse IO scheduling class, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue); return 0; } @@ -775,8 +765,7 @@ int config_parse_exec_io_priority(const char *unit, r = safe_atoi(rvalue, &i); if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse IO priority, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IO priority, ignoring: %s", rvalue); return 0; } @@ -808,8 +797,7 @@ int config_parse_exec_cpu_sched_policy(const char *unit, x = sched_policy_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, -x, - "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); return 0; } @@ -842,8 +830,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit, r = safe_atoi(rvalue, &i); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); return 0; } @@ -852,8 +839,7 @@ int config_parse_exec_cpu_sched_prio(const char *unit, max = sched_get_priority_max(c->cpu_sched_policy); if (i < min || i > max) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "CPU scheduling priority is out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU scheduling priority is out of range, ignoring: %s", rvalue); return 0; } @@ -883,8 +869,7 @@ int config_parse_exec_cpu_affinity(const char *unit, assert(rvalue); assert(data); - ncpus = parse_cpu_set(rvalue, &cpuset, unit, filename, line, lvalue); - + ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue); if (ncpus < 0) return ncpus; @@ -924,8 +909,7 @@ int config_parse_exec_capabilities(const char *unit, cap = cap_from_text(rvalue); if (!cap) { - log_syntax(unit, LOG_ERR, filename, line, errno, - "Failed to parse capabilities, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capabilities, ignoring: %s", rvalue); return 0; } @@ -976,14 +960,12 @@ int config_parse_exec_secure_bits(const char *unit, else if (first_word(word, "noroot-locked")) c->secure_bits |= 1<<SECURE_NOROOT_LOCKED; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse secure bits, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse secure bits, ignoring: %s", rvalue); return 0; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid syntax, garbage at the end, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring."); return 0; } @@ -1000,10 +982,11 @@ int config_parse_bounding_set(const char *unit, void *userdata) { uint64_t *capability_bounding_set_drop = data; - const char *word, *state; - size_t l; + uint64_t capability_bounding_set; bool invert = false; uint64_t sum = 0; + const char *prev; + const char *cur; assert(filename); assert(lvalue); @@ -1020,30 +1003,38 @@ int config_parse_bounding_set(const char *unit, * non-inverted everywhere to have a fully normalized * interface. */ - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *t = NULL; + prev = cur = rvalue; + for (;;) { + _cleanup_free_ char *word = NULL; int cap; + int r; - t = strndup(word, l); - if (!t) + r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in bounding set, ignoring: %s", prev); + break; + } - cap = capability_from_name(t); + cap = capability_from_name(word); if (cap < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse capability in bounding set, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word); + prev = cur; continue; } sum |= ((uint64_t) 1ULL) << (uint64_t) cap; + prev = cur; } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); - if (invert) - *capability_bounding_set_drop |= sum; + capability_bounding_set = invert ? ~sum : sum; + if (*capability_bounding_set_drop && capability_bounding_set) + *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); else - *capability_bounding_set_drop |= ~sum; + *capability_bounding_set_drop = ~capability_bounding_set; return 0; } @@ -1076,8 +1067,7 @@ int config_parse_limit(const char *unit, r = safe_atollu(rvalue, &u); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse resource value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); return 0; } } @@ -1092,6 +1082,49 @@ int config_parse_limit(const char *unit, return 0; } +int config_parse_bytes_limit(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct rlimit **rl = data; + uint64_t bytes; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + rl += ltype; + + if (streq(rvalue, "infinity")) + bytes = (uint64_t) RLIM_INFINITY; + else { + int r; + + r = parse_size(rvalue, 1024, &bytes); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; + } + } + + if (!*rl) { + *rl = new(struct rlimit, 1); + if (!*rl) + return log_oom(); + } + + (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) bytes; + return 0; +} + #ifdef HAVE_SYSV_COMPAT int config_parse_sysv_priority(const char *unit, const char *filename, @@ -1114,8 +1147,7 @@ int config_parse_sysv_priority(const char *unit, r = safe_atoi(rvalue, &i); if (r < 0 || i < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to parse SysV start priority, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue); return 0; } @@ -1162,12 +1194,12 @@ int config_parse_exec_mount_flags(const char *unit, else if (streq(t, "private")) flags = MS_PRIVATE; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse mount flag %s, ignoring: %s", t, rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue); return 0; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); c->mount_flags = flags; return 0; @@ -1210,8 +1242,7 @@ int config_parse_exec_selinux_context( r = unit_name_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); return 0; } @@ -1259,8 +1290,7 @@ int config_parse_exec_apparmor_profile( r = unit_name_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); return 0; } @@ -1308,8 +1338,7 @@ int config_parse_exec_smack_process_label( r = unit_name_printf(u, rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); return 0; } @@ -1350,23 +1379,18 @@ int config_parse_timer(const char *unit, b = timer_base_from_string(lvalue); if (b < 0) { - log_syntax(unit, LOG_ERR, filename, line, -b, - "Failed to parse timer base, ignoring: %s", lvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue); return 0; } if (b == TIMER_CALENDAR) { if (calendar_spec_from_string(rvalue, &c) < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse calendar specification, ignoring: %s", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", rvalue); return 0; } } else { if (parse_sec(rvalue, &u) < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse timer value, ignoring: %s", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", rvalue); return 0; } } @@ -1409,33 +1433,30 @@ int config_parse_trigger_unit( assert(data); if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Multiple units to trigger specified, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Multiple units to trigger specified, ignoring: %s", rvalue); return 0; } r = unit_name_printf(u, rvalue, &p); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); + return 0; + } - type = unit_name_to_type(p ?: rvalue); + type = unit_name_to_type(p); if (type < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unit type not valid, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue); return 0; } if (type == u->type) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trigger cannot be of same type, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue); return 0; } - r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true); + r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p); return 0; } @@ -1472,25 +1493,18 @@ int config_parse_path_spec(const char *unit, b = path_type_from_string(lvalue); if (b < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse path type, ignoring: %s", lvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue); return 0; } r = unit_full_printf(UNIT(p), rvalue, &k); if (r < 0) { - k = strdup(rvalue); - if (!k) - return log_oom(); - else - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve unit specifiers on %s. Ignoring.", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue); + return 0; } if (!path_is_absolute(k)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Path is not absolute, ignoring: %s", k); + log_syntax(unit, LOG_ERR, filename, line, 0, "Path is not absolute, ignoring: %s", k); return 0; } @@ -1522,10 +1536,10 @@ int config_parse_socket_service( void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *p = NULL; Socket *s = data; - int r; Unit *x; - _cleanup_free_ char *p = NULL; + int r; assert(filename); assert(lvalue); @@ -1539,13 +1553,13 @@ int config_parse_socket_service( } if (!endswith(p, ".service")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue); return 0; } r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); return 0; } @@ -1554,6 +1568,50 @@ int config_parse_socket_service( return 0; } +int config_parse_fdname( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_free_ char *p = NULL; + Socket *s = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + s->fdname = mfree(s->fdname); + return 0; + } + + r = unit_name_printf(UNIT(s), rvalue, &p); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } + + if (!fdname_is_valid(p)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p); + return 0; + } + + free(s->fdname); + s->fdname = p; + p = NULL; + + return 0; +} + int config_parse_service_sockets( const char *unit, const char *filename, @@ -1567,8 +1625,7 @@ int config_parse_service_sockets( void *userdata) { Service *s = data; - const char *word, *state; - size_t l; + const char *p; int r; assert(filename); @@ -1576,21 +1633,28 @@ int config_parse_service_sockets( assert(rvalue); assert(data); - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *t = NULL, *k = NULL; + p = rvalue; + for(;;) { + _cleanup_free_ char *word = NULL, *k = NULL; - t = strndup(word, l); - if (!t) + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue); + break; + } - r = unit_name_printf(UNIT(s), t, &k); + r = unit_name_printf(UNIT(s), word, &k); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); continue; } if (!endswith(k, ".socket")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type socket, ignoring: %s", k); continue; } @@ -1602,8 +1666,6 @@ int config_parse_service_sockets( if (r < 0) log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k); } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring."); return 0; } @@ -1636,7 +1698,7 @@ int config_parse_bus_name( } if (!service_name_is_valid(k)) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid bus name %s, ignoring.", k); return 0; } @@ -1701,21 +1763,18 @@ int config_parse_busname_service( r = unit_name_printf(UNIT(n), rvalue, &p); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); return 0; } if (!endswith(p, ".service")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unit must be of type service, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unit must be of type service, ignoring: %s", rvalue); return 0; } r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r)); return 0; } @@ -1765,8 +1824,7 @@ int config_parse_bus_policy( access_str = strpbrk(id_str, WHITESPACE); if (!access_str) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid busname policy value '%s'", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy value '%s'", rvalue); return 0; } @@ -1776,8 +1834,7 @@ int config_parse_bus_policy( p->access = bus_policy_access_from_string(access_str); if (p->access < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid busname policy access type '%s'", access_str); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid busname policy access type '%s'", access_str); return 0; } @@ -1819,8 +1876,7 @@ int config_parse_bus_endpoint_policy( access_str = strpbrk(name, WHITESPACE); if (!access_str) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid endpoint policy value '%s'", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy value '%s'", rvalue); return 0; } @@ -1831,21 +1887,83 @@ int config_parse_bus_endpoint_policy( access = bus_policy_access_from_string(access_str); if (access <= _BUS_POLICY_ACCESS_INVALID || access >= _BUS_POLICY_ACCESS_MAX) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid endpoint policy access type '%s'", access_str); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid endpoint policy access type '%s'", access_str); return 0; } if (!c->bus_endpoint) { r = bus_endpoint_new(&c->bus_endpoint); - if (r < 0) - return r; + return log_error_errno(r, "Failed to create bus endpoint object: %m"); } return bus_endpoint_add_policy(c->bus_endpoint, name, access); } +int config_parse_working_directory( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ExecContext *c = data; + Unit *u = userdata; + bool missing_ok; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(c); + assert(u); + + if (rvalue[0] == '-') { + missing_ok = true; + rvalue++; + } else + missing_ok = false; + + if (streq(rvalue, "~")) { + c->working_directory_home = true; + c->working_directory = mfree(c->working_directory); + } else { + _cleanup_free_ char *k = NULL; + + r = unit_full_printf(u, rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue); + return 0; + } + + path_kill_slashes(k); + + if (!utf8_is_valid(k)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); + return 0; + } + + if (!path_is_absolute(k)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue); + return 0; + } + + free(c->working_directory); + c->working_directory = k; + k = NULL; + + c->working_directory_home = false; + } + + c->working_directory_missing_ok = missing_ok; + return 0; +} + int config_parse_unit_env_file(const char *unit, const char *filename, unsigned line, @@ -1860,7 +1978,6 @@ int config_parse_unit_env_file(const char *unit, char ***env = data; Unit *u = userdata; _cleanup_free_ char *n = NULL; - const char *s; int r; assert(filename); @@ -1875,18 +1992,17 @@ int config_parse_unit_env_file(const char *unit, } r = unit_full_printf(u, rvalue, &n); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } - s = n ?: rvalue; - if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Path '%s' is not absolute, ignoring.", s); + if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n); return 0; } - r = strv_extend(env, s); + r = strv_extend(env, n); if (r < 0) return log_oom(); @@ -1924,14 +2040,17 @@ int config_parse_environ(const char *unit, if (u) { r = unit_full_printf(u, rvalue, &k); - if (r < 0) - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); + return 0; + } } - if (!k) + if (!k) { k = strdup(rvalue); - if (!k) - return log_oom(); + if (!k) + return log_oom(); + } FOREACH_WORD_QUOTED(word, l, k, state) { _cleanup_free_ char *n = NULL; @@ -1944,7 +2063,7 @@ int config_parse_environ(const char *unit, } if (!env_assignment_is_valid(n)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid environment assignment, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid environment assignment, ignoring: %s", rvalue); continue; } @@ -1956,8 +2075,7 @@ int config_parse_environ(const char *unit, *env = x; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -1982,8 +2100,7 @@ int config_parse_ip_tos(const char *unit, x = ip_tos_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse IP TOS value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue); return 0; } @@ -2031,12 +2148,12 @@ int config_parse_unit_condition_path( r = unit_full_printf(u, rvalue, &p); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); return 0; } if (!path_is_absolute(p)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p); + log_syntax(unit, LOG_ERR, filename, line, 0, "Path in condition not absolute, ignoring: %s", p); return 0; } @@ -2088,7 +2205,7 @@ int config_parse_unit_condition_string( r = unit_full_printf(u, rvalue, &s); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve specifiers, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue); return 0; } @@ -2137,7 +2254,7 @@ int config_parse_unit_condition_null( b = parse_boolean(rvalue); if (b < 0) { - log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, b, "Failed to parse boolean value in condition, ignoring: %s", rvalue); return 0; } @@ -2185,20 +2302,18 @@ int config_parse_unit_requires_mounts_for( return log_oom(); if (!utf8_is_valid(n)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); continue; } r = unit_require_mounts_for(u, n); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to add required mount for, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add required mount for, ignoring: %s", rvalue); continue; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -2239,8 +2354,7 @@ int config_parse_documentation(const char *unit, if (documentation_url_is_valid(*a)) *(b++) = *a; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid URL, ignoring: %s", *a); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid URL, ignoring: %s", *a); free(*a); } } @@ -2335,8 +2449,7 @@ int config_parse_syscall_filter( id = seccomp_syscall_resolve_name(t); if (id < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse system call, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t); continue; } @@ -2353,8 +2466,7 @@ int config_parse_syscall_filter( set_remove(c->syscall_filter, INT_TO_PTR(id + 1)); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); /* Turn on NNP, but only if it wasn't configured explicitly * before, and only if we are in user mode. */ @@ -2400,8 +2512,7 @@ int config_parse_syscall_archs( r = seccomp_arch_from_string(t, &a); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse system call architecture, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call architecture, ignoring: %s", t); continue; } @@ -2412,8 +2523,7 @@ int config_parse_syscall_archs( return log_oom(); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -2445,8 +2555,7 @@ int config_parse_syscall_errno( e = errno_from_name(rvalue); if (e < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse error number, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue); return 0; } @@ -2506,8 +2615,7 @@ int config_parse_address_families( af = af_from_name(t); if (af <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse address family, ignoring: %s", t); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse address family, ignoring: %s", t); continue; } @@ -2524,8 +2632,7 @@ int config_parse_address_families( set_remove(c->address_families, INT_TO_PTR(af)); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -2628,15 +2735,12 @@ int config_parse_cpu_quota( } if (!endswith(rvalue, "%")) { - - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue); return 0; } if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "CPU quota '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2668,7 +2772,7 @@ int config_parse_memory_limit( r = parse_size(rvalue, 1024, &bytes); if (r < 0 || bytes < 1) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2699,10 +2803,11 @@ int config_parse_tasks_max( r = safe_atou64(rvalue, &u); if (r < 0 || u < 1) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue); return 0; } + c->tasks_max = u; return 0; } @@ -2739,8 +2844,7 @@ int config_parse_device_allow( if (!startswith(path, "/dev/") && !startswith(path, "block-") && !startswith(path, "char-")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid device node path '%s'. Ignoring.", path); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); return 0; } @@ -2749,8 +2853,7 @@ int config_parse_device_allow( m = "rwm"; if (!in_charset(m, "rwm")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid device rights '%s'. Ignoring.", m); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device rights '%s'. Ignoring.", m); return 0; } @@ -2832,7 +2935,7 @@ int config_parse_blockio_device_weight( weight += strspn(weight, WHITESPACE); if (isempty(weight)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Expected block device and device weight. Ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring."); return 0; } @@ -2841,7 +2944,7 @@ int config_parse_blockio_device_weight( return log_oom(); if (!path_startswith(path, "/dev")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid device node path '%s'. Ignoring.", path); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); return 0; } @@ -2908,8 +3011,7 @@ int config_parse_blockio_bandwidth( bandwidth += strspn(bandwidth, WHITESPACE); if (!*bandwidth) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Expected space separated pair of device node and bandwidth. Ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Expected space separated pair of device node and bandwidth. Ignoring."); return 0; } @@ -2918,15 +3020,13 @@ int config_parse_blockio_bandwidth( return log_oom(); if (!path_startswith(path, "/dev")) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid device node path '%s'. Ignoring.", path); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path); return 0; } r = parse_size(bandwidth, 1000, &bytes); if (r < 0 || bytes <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue); return 0; } @@ -2971,13 +3071,12 @@ int config_parse_netclass( r = safe_atou32(rvalue, &v); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Netclass '%s' invalid. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Netclass '%s' invalid. Ignoring.", rvalue); return 0; } if (v > CGROUP_NETCLASS_FIXED_MAX) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, + log_syntax(unit, LOG_ERR, filename, line, 0, "Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX); c->netclass_id = v; @@ -3009,8 +3108,7 @@ int config_parse_job_mode_isolate( r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Failed to parse boolean, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse boolean, ignoring: %s", rvalue); return 0; } @@ -3056,14 +3154,12 @@ int config_parse_runtime_directory( r = unit_name_printf(u, t, &n); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Failed to resolve specifiers, ignoring: %s", strerror(-r)); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m"); continue; } if (!filename_is_valid(n)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Runtime directory is not valid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Runtime directory is not valid, ignoring assignment: %s", rvalue); continue; } @@ -3074,8 +3170,7 @@ int config_parse_runtime_directory( n = NULL; } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -3122,15 +3217,13 @@ int config_parse_set_status( val = signal_from_string_try_harder(temp); if (val <= 0) { - log_syntax(unit, LOG_ERR, filename, line, -val, - "Failed to parse value, ignoring: %s", word); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse value, ignoring: %s", word); continue; } set = &status_set->signal; } else { if (val < 0 || val > 255) { - log_syntax(unit, LOG_ERR, filename, line, ERANGE, - "Value %d is outside range 0-255, ignoring", val); + log_syntax(unit, LOG_ERR, filename, line, 0, "Value %d is outside range 0-255, ignoring", val); continue; } set = &status_set->status; @@ -3142,14 +3235,12 @@ int config_parse_set_status( r = set_put(*set, INT_TO_PTR(val)); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, - "Unable to store: %s", word); + log_syntax(unit, LOG_ERR, filename, line, r, "Unable to store: %s", word); return r; } } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -3167,8 +3258,8 @@ int config_parse_namespace_path_strv( void *userdata) { char*** sv = data; - const char *word, *state; - size_t l; + const char *prev; + const char *cur; int r; assert(filename); @@ -3182,37 +3273,43 @@ int config_parse_namespace_path_strv( return 0; } - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *n; + prev = cur = rvalue; + for (;;) { + _cleanup_free_ char *word = NULL; int offset; - n = strndup(word, l); - if (!n) + r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES); + if (r == 0) + break; + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev); + return 0; + } - if (!utf8_is_valid(n)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + if (!utf8_is_valid(word)) { + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word); + prev = cur; continue; } - offset = n[0] == '-'; - if (!path_is_absolute(n + offset)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Not an absolute path, ignoring: %s", rvalue); + offset = word[0] == '-'; + if (!path_is_absolute(word + offset)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word); + prev = cur; continue; } - path_kill_slashes(n); + path_kill_slashes(word + offset); - r = strv_push(sv, n); + r = strv_push(sv, word); if (r < 0) return log_oom(); - n = NULL; + prev = cur; + word = NULL; } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); return 0; } @@ -3239,8 +3336,7 @@ int config_parse_no_new_privileges( k = parse_boolean(rvalue); if (k < 0) { - log_syntax(unit, LOG_ERR, filename, line, -k, - "Failed to parse boolean value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue); return 0; } @@ -3283,8 +3379,7 @@ int config_parse_protect_home( h = protect_home_from_string(rvalue); if (h < 0){ - log_syntax(unit, LOG_ERR, filename, line, -h, - "Failed to parse protect home value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect home value, ignoring: %s", rvalue); return 0; } @@ -3327,8 +3422,7 @@ int config_parse_protect_system( s = protect_system_from_string(rvalue); if (s < 0){ - log_syntax(unit, LOG_ERR, filename, line, -s, - "Failed to parse protect system value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse protect system value, ignoring: %s", rvalue); return 0; } diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 5d0a09249f..029775bb46 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -56,6 +56,7 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); @@ -106,6 +107,8 @@ int config_parse_protect_home(const char* unit, const char *filename, unsigned l int config_parse_protect_system(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_bus_name(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index 6961c26674..bd632131b9 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -19,16 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> +#include <stdlib.h> -#include "locale-setup.h" -#include "util.h" -#include "virt.h" -#include "fileio.h" -#include "strv.h" #include "env-util.h" +#include "fileio.h" #include "locale-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" +#include "virt.h" +#include "locale-setup.h" int locale_setup(char ***environment) { char **add; diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c index 4503fc9dcc..4a57793104 100644 --- a/src/core/loopback-setup.c +++ b/src/core/loopback-setup.c @@ -23,9 +23,10 @@ #include <stdlib.h> #include "sd-netlink.h" -#include "netlink-util.h" -#include "missing.h" + #include "loopback-setup.h" +#include "missing.h" +#include "netlink-util.h" static int start_loopback(sd_netlink *rtnl) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 8f682c6d10..145ba2a28d 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -19,24 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <stdio.h> #include <errno.h> -#include <string.h> #include <fcntl.h> +#include <sched.h> +#include <stdio.h> +#include <string.h> #include <sys/mount.h> +#include <unistd.h> -#include "systemd/sd-id128.h" +#include "sd-id128.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hexdecoct.h" +#include "io-util.h" +#include "log.h" #include "machine-id-setup.h" #include "macro.h" -#include "util.h" #include "mkdir.h" -#include "log.h" -#include "virt.h" -#include "fileio.h" +#include "mount-util.h" #include "path-util.h" #include "process-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "umask-util.h" +#include "util.h" +#include "virt.h" static int shorten_uuid(char destination[34], const char source[36]) { unsigned i, j; diff --git a/src/core/main.c b/src/core/main.c index bc72a2b00b..950315e857 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -19,63 +19,73 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> -#include <string.h> -#include <unistd.h> -#include <sys/stat.h> +#include <fcntl.h> #include <getopt.h> #include <signal.h> -#include <fcntl.h> -#include <sys/prctl.h> +#include <stdio.h> +#include <string.h> #include <sys/mount.h> - -#ifdef HAVE_VALGRIND_VALGRIND_H -#include <valgrind/valgrind.h> -#endif +#include <sys/prctl.h> +#include <sys/reboot.h> +#include <sys/stat.h> +#include <unistd.h> #ifdef HAVE_SECCOMP #include <seccomp.h> #endif +#ifdef HAVE_VALGRIND_VALGRIND_H +#include <valgrind/valgrind.h> +#endif #include "sd-daemon.h" #include "sd-bus.h" -#include "log.h" -#include "fdset.h" -#include "special.h" -#include "conf-parser.h" -#include "missing.h" -#include "pager.h" + +#include "alloc-util.h" +#include "architecture.h" #include "build.h" -#include "strv.h" +#include "bus-error.h" +#include "bus-util.h" +#include "capability-util.h" +#include "clock-util.h" +#include "conf-parser.h" +#include "cpu-set-util.h" +#include "dbus-manager.h" #include "def.h" -#include "virt.h" -#include "architecture.h" -#include "watchdog.h" -#include "switch-root.h" -#include "capability.h" -#include "killall.h" #include "env-util.h" -#include "clock-util.h" +#include "fd-util.h" +#include "fdset.h" #include "fileio.h" -#include "bus-error.h" -#include "bus-util.h" -#include "selinux-util.h" #include "formats-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "signal-util.h" -#include "manager.h" -#include "dbus-manager.h" +#include "fs-util.h" +#include "hostname-setup.h" +#include "ima-setup.h" +#include "killall.h" +#include "kmod-setup.h" #include "load-fragment.h" - -#include "mount-setup.h" +#include "log.h" #include "loopback-setup.h" -#include "hostname-setup.h" #include "machine-id-setup.h" +#include "manager.h" +#include "missing.h" +#include "mount-setup.h" +#include "pager.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "rlimit-util.h" #include "selinux-setup.h" -#include "ima-setup.h" +#include "selinux-util.h" +#include "signal-util.h" #include "smack-setup.h" -#include "kmod-setup.h" +#include "special.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "strv.h" +#include "switch-root.h" +#include "terminal-util.h" +#include "user-util.h" +#include "virt.h" +#include "watchdog.h" static enum { ACTION_RUN, @@ -88,8 +98,9 @@ static enum { static char *arg_default_unit = NULL; static ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID; static bool arg_dump_core = true; -static bool arg_crash_shell = false; static int arg_crash_chvt = -1; +static bool arg_crash_shell = false; +static bool arg_crash_reboot = false; static bool arg_confirm_spawn = false; static ShowStatus arg_show_status = _SHOW_STATUS_UNSET; static bool arg_switched_root = false; @@ -116,8 +127,6 @@ static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; static bool arg_default_tasks_accounting = false; -static void nop_handler(int sig) {} - static void pager_open_if_enabled(void) { if (arg_no_pager <= 0) @@ -126,49 +135,66 @@ static void pager_open_if_enabled(void) { pager_open(false); } +noreturn static void freeze_or_reboot(void) { + + if (arg_crash_reboot) { + log_notice("Rebooting in 10s..."); + (void) sleep(10); + + log_notice("Rebooting now..."); + (void) reboot(RB_AUTOBOOT); + log_emergency_errno(errno, "Failed to reboot: %m"); + } + + log_emergency("Freezing execution."); + freeze(); +} + noreturn static void crash(int sig) { + struct sigaction sa; + pid_t pid; if (getpid() != 1) /* Pass this on immediately, if this is not PID 1 */ - raise(sig); + (void) raise(sig); else if (!arg_dump_core) log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig)); else { - struct sigaction sa = { - .sa_handler = nop_handler, + sa = (struct sigaction) { + .sa_handler = nop_signal_handler, .sa_flags = SA_NOCLDSTOP|SA_RESTART, }; - pid_t pid; /* We want to wait for the core process, hence let's enable SIGCHLD */ - sigaction(SIGCHLD, &sa, NULL); + (void) sigaction(SIGCHLD, &sa, NULL); pid = raw_clone(SIGCHLD, NULL); if (pid < 0) log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig)); - else if (pid == 0) { - struct rlimit rl = {}; + struct rlimit rl = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; /* Enable default signal handler for core dump */ - zero(sa); - sa.sa_handler = SIG_DFL; - sigaction(sig, &sa, NULL); + sa = (struct sigaction) { + .sa_handler = SIG_DFL, + }; + (void) sigaction(sig, &sa, NULL); /* Don't limit the core dump size */ - rl.rlim_cur = RLIM_INFINITY; - rl.rlim_max = RLIM_INFINITY; - setrlimit(RLIMIT_CORE, &rl); + (void) setrlimit(RLIMIT_CORE, &rl); /* Just to be sure... */ (void) chdir("/"); /* Raise the signal again */ pid = raw_getpid(); - kill(pid, sig); /* raise() would kill the parent */ + (void) kill(pid, sig); /* raise() would kill the parent */ assert_not_reached("We shouldn't be here..."); - _exit(1); + _exit(EXIT_FAILURE); } else { siginfo_t status; int r; @@ -190,37 +216,38 @@ noreturn static void crash(int sig) { } } - if (arg_crash_chvt) - chvt(arg_crash_chvt); + if (arg_crash_chvt >= 0) + (void) chvt(arg_crash_chvt); - if (arg_crash_shell) { - struct sigaction sa = { - .sa_handler = SIG_IGN, - .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART, - }; - pid_t pid; + sa = (struct sigaction) { + .sa_handler = SIG_IGN, + .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART, + }; - log_info("Executing crash shell in 10s..."); - sleep(10); + /* Let the kernel reap children for us */ + (void) sigaction(SIGCHLD, &sa, NULL); - /* Let the kernel reap children for us */ - assert_se(sigaction(SIGCHLD, &sa, NULL) == 0); + if (arg_crash_shell) { + log_notice("Executing crash shell in 10s..."); + (void) sleep(10); pid = raw_clone(SIGCHLD, NULL); if (pid < 0) log_emergency_errno(errno, "Failed to fork off crash shell: %m"); else if (pid == 0) { - make_console_stdio(); - execle("/bin/sh", "/bin/sh", NULL, environ); + (void) setsid(); + (void) make_console_stdio(); + (void) execle("/bin/sh", "/bin/sh", NULL, environ); log_emergency_errno(errno, "execle() failed: %m"); - _exit(1); - } else - log_info("Successfully spawned crash shell as PID "PID_FMT".", pid); + _exit(EXIT_FAILURE); + } else { + log_info("Spawned crash shell as PID "PID_FMT".", pid); + (void) wait_for_terminate(pid, NULL); + } } - log_emergency("Freezing execution."); - freeze(); + freeze_or_reboot(); } static void install_crash_handler(void) { @@ -254,37 +281,26 @@ static int console_setup(void) { return 0; } -static int set_default_unit(const char *u) { - char *c; +static int parse_crash_chvt(const char *value) { + int b; - assert(u); + if (safe_atoi(value, &arg_crash_chvt) >= 0) + return 0; - c = strdup(u); - if (!c) - return -ENOMEM; + b = parse_boolean(value); + if (b < 0) + return b; - free(arg_default_unit); - arg_default_unit = c; + if (b > 0) + arg_crash_chvt = 0; /* switch to where kmsg goes */ + else + arg_crash_chvt = -1; /* turn off switching */ return 0; } static int parse_proc_cmdline_item(const char *key, const char *value) { - static const char * const rlmap[] = { - "emergency", SPECIAL_EMERGENCY_TARGET, - "-b", SPECIAL_EMERGENCY_TARGET, - "rescue", SPECIAL_RESCUE_TARGET, - "single", SPECIAL_RESCUE_TARGET, - "-s", SPECIAL_RESCUE_TARGET, - "s", SPECIAL_RESCUE_TARGET, - "S", SPECIAL_RESCUE_TARGET, - "1", SPECIAL_RESCUE_TARGET, - "2", SPECIAL_MULTI_USER_TARGET, - "3", SPECIAL_MULTI_USER_TARGET, - "4", SPECIAL_MULTI_USER_TARGET, - "5", SPECIAL_GRAPHICAL_TARGET, - }; int r; assert(key); @@ -292,12 +308,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { if (streq(key, "systemd.unit") && value) { if (!in_initrd()) - return set_default_unit(value); + return free_and_strdup(&arg_default_unit, value); } else if (streq(key, "rd.systemd.unit") && value) { if (in_initrd()) - return set_default_unit(value); + return free_and_strdup(&arg_default_unit, value); } else if (streq(key, "systemd.dump_core") && value) { @@ -307,6 +323,11 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_dump_core = r; + } else if (streq(key, "systemd.crash_chvt") && value) { + + if (parse_crash_chvt(value) < 0) + log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + } else if (streq(key, "systemd.crash_shell") && value) { r = parse_boolean(value); @@ -315,12 +336,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { else arg_crash_shell = r; - } else if (streq(key, "systemd.crash_chvt") && value) { + } else if (streq(key, "systemd.crash_reboot") && value) { - if (safe_atoi(value, &r) < 0) - log_warning("Failed to parse crash chvt switch %s. Ignoring.", value); + r = parse_boolean(value); + if (r < 0) + log_warning("Failed to parse crash reboot switch %s. Ignoring.", value); else - arg_crash_chvt = r; + arg_crash_reboot = r; } else if (streq(key, "systemd.confirm_spawn") && value) { @@ -379,12 +401,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { log_set_target(LOG_TARGET_CONSOLE); } else if (!in_initrd() && !value) { - unsigned i; + const char *target; /* SysV compatibility */ - for (i = 0; i < ELEMENTSOF(rlmap); i += 2) - if (streq(key, rlmap[i])) - return set_default_unit(rlmap[i+1]); + target = runlevel_to_target(key); + if (target) + return free_and_strdup(&arg_default_unit, target); } return 0; @@ -410,9 +432,9 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { \ r = func(rvalue); \ if (r < 0) \ - log_syntax(unit, LOG_ERR, filename, line, -r, \ - "Invalid " descr "'%s': %s", \ - rvalue, strerror(-r)); \ + log_syntax(unit, LOG_ERR, filename, line, r, \ + "Invalid " descr "'%s': %m", \ + rvalue); \ \ return 0; \ } @@ -437,8 +459,7 @@ static int config_parse_cpu_affinity2( _cleanup_cpu_free_ cpu_set_t *c = NULL; int ncpus; - ncpus = parse_cpu_set(rvalue, &c, unit, filename, line, lvalue); - + ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue); if (ncpus < 0) return ncpus; @@ -470,29 +491,38 @@ static int config_parse_show_status( k = parse_show_status(rvalue, b); if (k < 0) { - log_syntax(unit, LOG_ERR, filename, line, -k, - "Failed to parse show status setting, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse show status setting, ignoring: %s", rvalue); return 0; } return 0; } -static void strv_free_free(char ***l) { - char ***i; +static int config_parse_crash_chvt( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { - if (!l) - return; + int r; - for (i = l; *i; i++) - strv_free(*i); + assert(filename); + assert(lvalue); + assert(rvalue); - free(l); -} + r = parse_crash_chvt(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue); + return 0; + } -static void free_join_controllers(void) { - strv_free_free(arg_join_controllers); - arg_join_controllers = NULL; + return 0; } static int config_parse_join_controllers(const char *unit, @@ -513,7 +543,7 @@ static int config_parse_join_controllers(const char *unit, assert(lvalue); assert(rvalue); - free_join_controllers(); + arg_join_controllers = strv_free_free(arg_join_controllers); for (;;) { _cleanup_free_ char *word = NULL; @@ -530,7 +560,7 @@ static int config_parse_join_controllers(const char *unit, l = strv_split(word, ","); if (!l) - log_oom(); + return log_oom(); strv_uniq(l); if (strv_length(l) <= 1) { @@ -564,7 +594,7 @@ static int config_parse_join_controllers(const char *unit, for (a = arg_join_controllers; *a; a++) { if (strv_overlap(*a, l)) { - if (strv_extend_strv(&l, *a) < 0) { + if (strv_extend_strv(&l, *a, false) < 0) { strv_free(l); strv_free_free(t); return log_oom(); @@ -591,8 +621,7 @@ static int config_parse_join_controllers(const char *unit, } } if (!isempty(rvalue)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -605,9 +634,11 @@ static int parse_config_file(void) { { "Manager", "LogColor", config_parse_color, 0, NULL }, { "Manager", "LogLocation", config_parse_location, 0, NULL }, { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core }, + { "Manager", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, NULL }, + { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, NULL }, { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell }, + { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot }, { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status }, - { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt }, { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL }, { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, @@ -627,18 +658,18 @@ static int parse_config_file(void) { { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] }, - { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, - { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, - { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, - { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, - { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, + { "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] }, + { "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] }, + { "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] }, + { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, + { "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] }, - { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, + { "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] }, - { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, + { "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] }, { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] }, - { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, + { "Manager", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] }, { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] }, { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] }, { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, @@ -695,7 +726,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION, ARG_DUMP_CONFIGURATION_ITEMS, ARG_DUMP_CORE, + ARG_CRASH_CHVT, ARG_CRASH_SHELL, + ARG_CRASH_REBOOT, ARG_CONFIRM_SPAWN, ARG_SHOW_STATUS, ARG_DESERIALIZE, @@ -718,7 +751,9 @@ static int parse_argv(int argc, char *argv[]) { { "version", no_argument, NULL, ARG_VERSION }, { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS }, { "dump-core", optional_argument, NULL, ARG_DUMP_CORE }, + { "crash-chvt", required_argument, NULL, ARG_CRASH_CHVT }, { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL }, + { "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT }, { "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN }, { "show-status", optional_argument, NULL, ARG_SHOW_STATUS }, { "deserialize", required_argument, NULL, ARG_DESERIALIZE }, @@ -803,7 +838,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_UNIT: - r = set_default_unit(optarg); + r = free_and_strdup(&arg_default_unit, optarg); if (r < 0) return log_error_errno(r, "Failed to set default unit %s: %m", optarg); @@ -836,21 +871,42 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DUMP_CORE: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse dump core boolean %s.", optarg); - return r; + if (!optarg) + arg_dump_core = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg); + arg_dump_core = r; } - arg_dump_core = r; + break; + + case ARG_CRASH_CHVT: + r = parse_crash_chvt(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg); break; case ARG_CRASH_SHELL: - r = optarg ? parse_boolean(optarg) : 1; - if (r < 0) { - log_error("Failed to parse crash shell boolean %s.", optarg); - return r; + if (!optarg) + arg_crash_shell = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_shell = r; + } + break; + + case ARG_CRASH_REBOOT: + if (!optarg) + arg_crash_reboot = true; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg); + arg_crash_reboot = r; } - arg_crash_shell = r; break; case ARG_CONFIRM_SPAWN: @@ -880,17 +936,16 @@ static int parse_argv(int argc, char *argv[]) { r = safe_atoi(optarg, &fd); if (r < 0 || fd < 0) { log_error("Failed to parse deserialize option %s.", optarg); - return r < 0 ? r : -EINVAL; + return -EINVAL; } - fd_cloexec(fd, true); + (void) fd_cloexec(fd, true); f = fdopen(fd, "r"); if (!f) return log_error_errno(errno, "Failed to open serialization fd: %m"); safe_fclose(arg_serialization); - arg_serialization = f; break; @@ -950,14 +1005,16 @@ static int help(void) { " --unit=UNIT Set default unit\n" " --system Run a system instance, even if PID != 1\n" " --user Run a user instance\n" - " --dump-core[=0|1] Dump core on crash\n" - " --crash-shell[=0|1] Run shell on crash\n" - " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n" - " --show-status[=0|1] Show status updates on the console during bootup\n" + " --dump-core[=BOOL] Dump core on crash\n" + " --crash-vt=NR Change to specified VT on crash\n" + " --crash-reboot[=BOOL] Reboot on crash\n" + " --crash-shell[=BOOL] Run shell on crash\n" + " --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n" + " --show-status[=BOOL] Show status updates on the console during bootup\n" " --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n" " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n" - " --log-color[=0|1] Highlight important log messages\n" - " --log-location[=0|1] Include code location in log messages\n" + " --log-color[=BOOL] Highlight important log messages\n" + " --log-location[=BOOL] Include code location in log messages\n" " --default-standard-output= Set default standard output for services\n" " --default-standard-error= Set default standard error output for services\n", program_invocation_short_name); @@ -965,16 +1022,9 @@ static int help(void) { return 0; } -static int version(void) { - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - - return 0; -} - static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) { - FILE *f = NULL; - FDSet *fds = NULL; + _cleanup_fdset_free_ FDSet *fds = NULL; + _cleanup_fclose_ FILE *f = NULL; int r; assert(m); @@ -982,56 +1032,39 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching assert(_fds); r = manager_open_serialization(m, &f); - if (r < 0) { - log_error_errno(r, "Failed to create serialization file: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to create serialization file: %m"); /* Make sure nothing is really destructed when we shut down */ m->n_reloading ++; bus_manager_send_reloading(m, true); fds = fdset_new(); - if (!fds) { - r = -ENOMEM; - log_error_errno(r, "Failed to allocate fd set: %m"); - goto fail; - } + if (!fds) + return log_oom(); r = manager_serialize(m, f, fds, switching_root); - if (r < 0) { - log_error_errno(r, "Failed to serialize state: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to serialize state: %m"); - if (fseeko(f, 0, SEEK_SET) < 0) { - log_error_errno(errno, "Failed to rewind serialization fd: %m"); - goto fail; - } + if (fseeko(f, 0, SEEK_SET) == (off_t) -1) + return log_error_errno(errno, "Failed to rewind serialization fd: %m"); r = fd_cloexec(fileno(f), false); - if (r < 0) { - log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m"); r = fdset_cloexec(fds, false); - if (r < 0) { - log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m"); - goto fail; - } + if (r < 0) + return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m"); *_f = f; *_fds = fds; - return 0; - -fail: - fdset_free(fds); - - safe_fclose(f); + f = NULL; + fds = NULL; - return r; + return 0; } static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { @@ -1066,33 +1099,6 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) { return 0; } -static void test_mtab(void) { - - static const char ok[] = - "/proc/self/mounts\0" - "/proc/mounts\0" - "../proc/self/mounts\0" - "../proc/mounts\0"; - - _cleanup_free_ char *p = NULL; - int r; - - /* Check that /etc/mtab is a symlink to the right place or - * non-existing. But certainly not a file, or a symlink to - * some weird place... */ - - r = readlink_malloc("/etc/mtab", &p); - if (r == -ENOENT) - return; - if (r >= 0 && nulstr_contains(ok, p)) - return; - - log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. " - "This is not supported anymore. " - "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output."); - freeze(); -} - static void test_usr(void) { /* Check that /usr is not a separate fs */ @@ -1116,15 +1122,19 @@ static int initialize_join_controllers(void) { return -ENOMEM; arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL); - arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL); - arg_join_controllers[2] = NULL; + if (!arg_join_controllers[0]) + goto oom; - if (!arg_join_controllers[0] || !arg_join_controllers[1]) { - free_join_controllers(); - return -ENOMEM; - } + arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL); + if (!arg_join_controllers[1]) + goto oom; + arg_join_controllers[2] = NULL; return 0; + +oom: + arg_join_controllers = strv_free_free(arg_join_controllers); + return -ENOMEM; } static int enforce_syscall_archs(Set *archs) { @@ -1191,12 +1201,50 @@ static int status_welcome(void) { static int write_container_id(void) { const char *c; + int r; c = getenv("container"); if (isempty(c)) return 0; - return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE); + r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE); + if (r < 0) + return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m"); + + return 1; +} + +static int bump_unix_max_dgram_qlen(void) { + _cleanup_free_ char *qlen = NULL; + unsigned long v; + int r; + + /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel + * default of 16 is simply too low. We set the value really + * really early during boot, so that it is actually applied to + * all our sockets, including the $NOTIFY_SOCKET one. */ + + r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen); + if (r < 0) + return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m"); + + r = safe_atolu(qlen, &v); + if (r < 0) + return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m"); + + if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN) + return 0; + + qlen = mfree(qlen); + if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0) + return log_oom(); + + r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0); + if (r < 0) + return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, + "Failed to bump AF_UNIX datagram queue length, ignoring: %m"); + + return 1; } int main(int argc, char *argv[]) { @@ -1222,7 +1270,6 @@ int main(int argc, char *argv[]) { char *switch_root_dir = NULL, *switch_root_init = NULL; struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0); const char *error_message = NULL; - uint8_t shutdown_exit_code = 0; #ifdef HAVE_SYSV_COMPAT if (getpid() != 1 && strstr(program_invocation_short_name, "init")) { @@ -1369,7 +1416,7 @@ int main(int argc, char *argv[]) { } /* Initialize default unit */ - r = set_default_unit(SPECIAL_DEFAULT_TARGET); + r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); if (r < 0) { log_emergency_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET); error_message = "Failed to set default unit"; @@ -1563,8 +1610,8 @@ int main(int argc, char *argv[]) { hostname_setup(); machine_id_setup(NULL); loopback_setup(); + bump_unix_max_dgram_qlen(); - test_mtab(); test_usr(); } @@ -1646,8 +1693,7 @@ int main(int argc, char *argv[]) { /* This will close all file descriptors that were opened, but * not claimed by any unit. */ - fdset_free(fds); - fds = NULL; + fds = fdset_free(fds); arg_serialization = safe_fclose(arg_serialization); @@ -1775,8 +1821,9 @@ int main(int argc, char *argv[]) { goto finish; case MANAGER_EXIT: + retval = m->return_value; + if (m->running_as == MANAGER_USER) { - retval = EXIT_SUCCESS; log_debug("Exit."); goto finish; } @@ -1809,21 +1856,17 @@ int main(int argc, char *argv[]) { finish: pager_close(); - if (m) { + if (m) arg_shutdown_watchdog = m->shutdown_watchdog; - shutdown_exit_code = m->return_value; - } + m = manager_free(m); for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) arg_default_rlimit[j] = mfree(arg_default_rlimit[j]); arg_default_unit = mfree(arg_default_unit); - - free_join_controllers(); - + arg_join_controllers = strv_free_free(arg_join_controllers); arg_default_environment = strv_free(arg_default_environment); - arg_syscall_archs = set_free(arg_syscall_archs); mac_selinux_finish(); @@ -1841,7 +1884,7 @@ finish: * that the new systemd can pass the kernel default to * its child processes */ if (saved_rlimit_nofile.rlim_cur > 0) - setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile); + (void) setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile); if (switch_root_dir) { /* Kill all remaining processes from the @@ -1883,10 +1926,10 @@ finish: /* do not pass along the environment we inherit from the kernel or initrd */ if (switch_root_dir) - clearenv(); + (void) clearenv(); assert(i <= args_size); - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); } /* Try the fallback, if there is any, without any @@ -1896,14 +1939,10 @@ finish: * but let's hope that doesn't matter.) */ arg_serialization = safe_fclose(arg_serialization); - - if (fds) { - fdset_free(fds); - fds = NULL; - } + fds = fdset_free(fds); /* Reopen the console */ - make_console_stdio(); + (void) make_console_stdio(); for (j = 1, i = 1; j < (unsigned) argc; j++) args[i++] = argv[j]; @@ -1917,30 +1956,26 @@ finish: if (switch_root_init) { args[0] = switch_root_init; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m"); } args[0] = "/sbin/init"; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); if (errno == ENOENT) { log_warning("No /sbin/init, trying fallback"); args[0] = "/bin/sh"; args[1] = NULL; - execv(args[0], (char* const*) args); + (void) execv(args[0], (char* const*) args); log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m"); } else log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m"); } arg_serialization = safe_fclose(arg_serialization); - - if (fds) { - fdset_free(fds); - fds = NULL; - } + fds = fdset_free(fds); #ifdef HAVE_VALGRIND_VALGRIND_H /* If we are PID 1 and running under valgrind, then let's exit @@ -1969,6 +2004,7 @@ finish: xsprintf(log_level, "%d", log_get_max_level()); switch (log_get_target()) { + case LOG_TARGET_KMSG: case LOG_TARGET_JOURNAL_OR_KMSG: case LOG_TARGET_SYSLOG_OR_KMSG: @@ -1994,7 +2030,7 @@ finish: if (streq(shutdown_verb, "exit")) { command_line[pos++] = "--exit-code"; command_line[pos++] = exit_code; - xsprintf(exit_code, "%d", shutdown_exit_code); + xsprintf(exit_code, "%d", retval); } assert(pos < ELEMENTSOF(command_line)); @@ -2010,7 +2046,7 @@ finish: /* Tell the binary how often to ping, ignore failure */ if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0) - strv_push(&env_block, e); + (void) strv_push(&env_block, e); } else watchdog_close(true); @@ -2030,7 +2066,7 @@ finish: manager_status_printf(NULL, STATUS_TYPE_EMERGENCY, ANSI_HIGHLIGHT_RED "!!!!!!" ANSI_NORMAL, "%s, freezing.", error_message); - freeze(); + freeze_or_reboot(); } return retval; diff --git a/src/core/manager.c b/src/core/manager.c index 9bfe867ea0..b13663e702 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -19,19 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <dirent.h> #include <errno.h> -#include <string.h> +#include <fcntl.h> +#include <linux/kd.h> #include <signal.h> -#include <sys/wait.h> -#include <unistd.h> -#include <sys/inotify.h> +#include <string.h> #include <sys/epoll.h> -#include <sys/reboot.h> +#include <sys/inotify.h> #include <sys/ioctl.h> -#include <linux/kd.h> -#include <fcntl.h> -#include <dirent.h> +#include <sys/reboot.h> #include <sys/timerfd.h> +#include <sys/wait.h> +#include <unistd.h> #ifdef HAVE_AUDIT #include <libaudit.h> @@ -40,40 +40,53 @@ #include "sd-daemon.h" #include "sd-messages.h" -#include "hashmap.h" -#include "macro.h" -#include "strv.h" -#include "log.h" -#include "util.h" -#include "mkdir.h" -#include "ratelimit.h" -#include "locale-setup.h" -#include "unit-name.h" -#include "missing.h" -#include "rm-rf.h" -#include "path-lookup.h" -#include "special.h" -#include "exit-status.h" -#include "virt.h" -#include "watchdog.h" -#include "path-util.h" +#include "alloc-util.h" #include "audit-fd.h" #include "boot-timestamps.h" -#include "env-util.h" #include "bus-common-errors.h" #include "bus-error.h" -#include "bus-util.h" #include "bus-kernel.h" -#include "time-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "signal-util.h" -#include "dbus.h" -#include "dbus-unit.h" +#include "bus-util.h" #include "dbus-job.h" #include "dbus-manager.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "env-util.h" +#include "escape.h" +#include "exit-status.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hashmap.h" +#include "io-util.h" +#include "locale-setup.h" +#include "log.h" +#include "macro.h" #include "manager.h" +#include "missing.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-lookup.h" +#include "path-util.h" +#include "process-util.h" +#include "ratelimit.h" +#include "rm-rf.h" +#include "signal-util.h" +#include "special.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "terminal-util.h" +#include "time-util.h" #include "transaction.h" +#include "umask-util.h" +#include "unit-name.h" +#include "util.h" +#include "virt.h" +#include "watchdog.h" + +#define NOTIFY_RCVBUF_SIZE (8*1024*1024) /* Initial delay and the interval for printing status messages about running jobs */ #define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC) @@ -495,6 +508,7 @@ static void manager_clean_environment(Manager *m) { "MANAGERPID", "LISTEN_PID", "LISTEN_FDS", + "LISTEN_FDNAMES", "WATCHDOG_PID", "WATCHDOG_USEC", NULL); @@ -677,6 +691,8 @@ static int manager_setup_notify(Manager *m) { if (fd < 0) return log_error_errno(errno, "Failed to allocate notification socket: %m"); + fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE); + if (m->running_as == MANAGER_SYSTEM) m->notify_socket = strdup("/run/systemd/notify"); else { @@ -1476,7 +1492,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { return n; } -static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) { +static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) { _cleanup_strv_free_ char **tags = NULL; assert(m); @@ -1497,9 +1513,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char * } static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + _cleanup_fdset_free_ FDSet *fds = NULL; Manager *m = userdata; + + char buf[NOTIFY_BUFFER_MAX+1]; + struct iovec iovec = { + .iov_base = buf, + .iov_len = sizeof(buf)-1, + }; + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + + CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; + } control = {}; + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + + struct cmsghdr *cmsg; + struct ucred *ucred = NULL; + bool found = false; + Unit *u1, *u2, *u3; + int r, *fd_array = NULL; + unsigned n_fds = 0; ssize_t n; - int r; assert(m); assert(m->notify_fd == fd); @@ -1509,106 +1549,80 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t return 0; } - for (;;) { - _cleanup_fdset_free_ FDSet *fds = NULL; - char buf[NOTIFY_BUFFER_MAX+1]; - struct iovec iovec = { - .iov_base = buf, - .iov_len = sizeof(buf)-1, - }; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) + - CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)]; - } control = {}; - struct msghdr msghdr = { - .msg_iov = &iovec, - .msg_iovlen = 1, - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - struct ucred *ucred = NULL; - bool found = false; - Unit *u1, *u2, *u3; - int *fd_array = NULL; - unsigned n_fds = 0; - - n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); - if (n < 0) { - if (errno == EAGAIN || errno == EINTR) - break; + n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC); + if (n < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; - return -errno; - } + return -errno; + } - CMSG_FOREACH(cmsg, &msghdr) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { + CMSG_FOREACH(cmsg, &msghdr) { + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - fd_array = (int*) CMSG_DATA(cmsg); - n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); + fd_array = (int*) CMSG_DATA(cmsg); + n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int); - } else if (cmsg->cmsg_level == SOL_SOCKET && - cmsg->cmsg_type == SCM_CREDENTIALS && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) { - ucred = (struct ucred*) CMSG_DATA(cmsg); - } + ucred = (struct ucred*) CMSG_DATA(cmsg); } + } - if (n_fds > 0) { - assert(fd_array); + if (n_fds > 0) { + assert(fd_array); - r = fdset_new_array(&fds, fd_array, n_fds); - if (r < 0) { - close_many(fd_array, n_fds); - return log_oom(); - } + r = fdset_new_array(&fds, fd_array, n_fds); + if (r < 0) { + close_many(fd_array, n_fds); + return log_oom(); } + } - if (!ucred || ucred->pid <= 0) { - log_warning("Received notify message without valid credentials. Ignoring."); - continue; - } + if (!ucred || ucred->pid <= 0) { + log_warning("Received notify message without valid credentials. Ignoring."); + return 0; + } - if ((size_t) n >= sizeof(buf)) { - log_warning("Received notify message exceeded maximum size. Ignoring."); - continue; - } + if ((size_t) n >= sizeof(buf)) { + log_warning("Received notify message exceeded maximum size. Ignoring."); + return 0; + } - buf[n] = 0; + buf[n] = 0; - /* Notify every unit that might be interested, but try - * to avoid notifying the same one multiple times. */ - u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid); - if (u1) { - manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); - found = true; - } + /* Notify every unit that might be interested, but try + * to avoid notifying the same one multiple times. */ + u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid); + if (u1) { + manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds); + found = true; + } - u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid)); - if (u2 && u2 != u1) { - manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); - found = true; - } + u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid)); + if (u2 && u2 != u1) { + manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds); + found = true; + } - u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid)); - if (u3 && u3 != u2 && u3 != u1) { - manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); - found = true; - } + u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid)); + if (u3 && u3 != u2 && u3 != u1) { + manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds); + found = true; + } - if (!found) - log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); + if (!found) + log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid); - if (fdset_size(fds) > 0) - log_warning("Got auxiliary fds with notification message, closing all."); - } + if (fdset_size(fds) > 0) + log_warning("Got auxiliary fds with notification message, closing all."); return 0; } -static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) { +static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) { assert(m); assert(u); assert(si); @@ -1990,8 +2004,7 @@ int manager_loop(Manager *m) { m->exit_code = MANAGER_OK; /* Release the path cache */ - set_free_free(m->unit_path_cache); - m->unit_path_cache = NULL; + m->unit_path_cache = set_free_free(m->unit_path_cache); manager_check_finished(m); @@ -2101,6 +2114,9 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { const char *msg; int audit_fd, r; + if (m->running_as != MANAGER_SYSTEM) + return; + audit_fd = get_audit_fd(); if (audit_fd < 0) return; @@ -2110,9 +2126,6 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) { if (m->n_reloading > 0) return; - if (m->running_as != MANAGER_SYSTEM) - return; - if (u->type != UNIT_SERVICE) return; @@ -2761,8 +2774,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name) return log_oom(); if (!mkdtemp(p)) { - log_error_errno(errno, "Failed to create generator directory %s: %m", - p); + log_error_errno(errno, "Failed to create generator directory %s: %m", p); free(p); return -errno; } @@ -2951,9 +2963,9 @@ void manager_set_show_status(Manager *m, ShowStatus mode) { m->show_status = mode; if (mode > 0) - touch("/run/systemd/show-status"); + (void) touch("/run/systemd/show-status"); else - unlink("/run/systemd/show-status"); + (void) unlink("/run/systemd/show-status"); } static bool manager_get_show_status(Manager *m, StatusType type) { @@ -3012,30 +3024,6 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons va_end(ap); } -int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) { - _cleanup_free_ char *p = NULL; - Unit *found; - int r; - - assert(m); - assert(path); - assert(suffix); - assert(_found); - - r = unit_name_from_path(path, suffix, &p); - if (r < 0) - return r; - - found = manager_get_unit(m, p); - if (!found) { - *_found = NULL; - return 0; - } - - *_found = found; - return 1; -} - Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) { char p[strlen(path)+1]; diff --git a/src/core/manager.h b/src/core/manager.h index cc0e5e3361..38d2770e97 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -27,8 +27,8 @@ #include "sd-bus.h" #include "sd-event.h" -#include "fdset.h" #include "cgroup-util.h" +#include "fdset.h" #include "hashmap.h" #include "list.h" #include "ratelimit.h" @@ -69,11 +69,11 @@ typedef enum StatusType { STATUS_TYPE_EMERGENCY, } StatusType; +#include "execute.h" #include "job.h" #include "path-lookup.h" -#include "execute.h" -#include "unit-name.h" #include "show-status.h" +#include "unit-name.h" struct Manager { /* Note that the set of units we know of is allowed to be @@ -322,8 +322,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds); Job *manager_get_job(Manager *m, uint32_t id); Unit *manager_get_unit(Manager *m, const char *name); -int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found); - int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j); int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 9b16eaa0e2..b2596d1cd1 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -25,22 +25,25 @@ #include <unistd.h> #include <ftw.h> -#include "mount-setup.h" -#include "dev-setup.h" +#include "alloc-util.h" #include "bus-util.h" +#include "cgroup-util.h" +#include "dev-setup.h" +#include "efivars.h" +#include "label.h" #include "log.h" #include "macro.h" -#include "util.h" -#include "label.h" -#include "set.h" -#include "strv.h" +#include "missing.h" #include "mkdir.h" +#include "mount-setup.h" +#include "mount-util.h" #include "path-util.h" -#include "missing.h" -#include "virt.h" -#include "efivars.h" +#include "set.h" #include "smack-util.h" -#include "cgroup-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" +#include "virt.h" typedef enum MountMode { MNT_NONE = 0, diff --git a/src/core/mount.c b/src/core/mount.c index e7aae6e19a..950d5d76d5 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -20,25 +20,34 @@ ***/ #include <errno.h> +#include <signal.h> #include <stdio.h> #include <sys/epoll.h> -#include <signal.h> -#include "manager.h" -#include "unit.h" -#include "mount.h" -#include "log.h" #include "sd-messages.h" -#include "strv.h" -#include "mkdir.h" -#include "path-util.h" -#include "mount-setup.h" -#include "unit-name.h" + +#include "alloc-util.h" #include "dbus-mount.h" -#include "special.h" +#include "escape.h" #include "exit-status.h" -#include "fstab-util.h" #include "formats-util.h" +#include "fstab-util.h" +#include "log.h" +#include "manager.h" +#include "mkdir.h" +#include "mount-setup.h" +#include "mount-util.h" +#include "mount.h" +#include "parse-util.h" +#include "path-util.h" +#include "process-util.h" +#include "smack-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit.h" #define RETRY_UMOUNT_MAX 32 @@ -202,6 +211,7 @@ static void mount_done(Unit *u) { assert(m); m->where = mfree(m->where); + m->smack_fs_root_label = mfree(m->smack_fs_root_label); mount_parameters_done(&m->parameters_proc_self_mountinfo); mount_parameters_done(&m->parameters_fragment); @@ -246,9 +256,10 @@ static int mount_add_mount_links(Mount *m) { if (!path_equal(m->where, "/")) { /* Adds in links to other mount points that might lie further * up in the hierarchy */ - r = path_get_parent(m->where, &parent); - if (r < 0) - return r; + + parent = dirname_malloc(m->where); + if (!parent) + return -ENOMEM; r = unit_require_mounts_for(UNIT(m), parent); if (r < 0) @@ -621,19 +632,19 @@ static int mount_coldplug(Unit *u) { if (new_state == m->state) return 0; - if (new_state == MOUNT_MOUNTING || - new_state == MOUNT_MOUNTING_DONE || - new_state == MOUNT_REMOUNTING || - new_state == MOUNT_UNMOUNTING || - new_state == MOUNT_MOUNTING_SIGTERM || - new_state == MOUNT_MOUNTING_SIGKILL || - new_state == MOUNT_UNMOUNTING_SIGTERM || - new_state == MOUNT_UNMOUNTING_SIGKILL || - new_state == MOUNT_REMOUNTING_SIGTERM || - new_state == MOUNT_REMOUNTING_SIGKILL) { - - if (m->control_pid <= 0) - return -EBADMSG; + if (m->control_pid > 0 && + pid_is_unwaited(m->control_pid) && + IN_SET(new_state, + MOUNT_MOUNTING, + MOUNT_MOUNTING_DONE, + MOUNT_REMOUNTING, + MOUNT_UNMOUNTING, + MOUNT_MOUNTING_SIGTERM, + MOUNT_MOUNTING_SIGKILL, + MOUNT_UNMOUNTING_SIGTERM, + MOUNT_UNMOUNTING_SIGKILL, + MOUNT_REMOUNTING_SIGTERM, + MOUNT_REMOUNTING_SIGKILL)) { r = unit_watch_pid(UNIT(m), m->control_pid); if (r < 0) @@ -666,7 +677,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { "%sOptions: %s\n" "%sFrom /proc/self/mountinfo: %s\n" "%sFrom fragment: %s\n" - "%sDirectoryMode: %04o\n", + "%sDirectoryMode: %04o\n" + "%sSmackFileSystemRootLabel: %s\n", prefix, mount_state_to_string(m->state), prefix, mount_result_to_string(m->result), prefix, m->where, @@ -675,7 +687,8 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) { prefix, p ? strna(p->options) : "n/a", prefix, yes_no(m->from_proc_self_mountinfo), prefix, yes_no(m->from_fragment), - prefix, m->directory_mode); + prefix, m->directory_mode, + prefix, strna(m->smack_fs_root_label)); if (m->control_pid > 0) fprintf(f, @@ -694,6 +707,9 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { .apply_chroot = true, .apply_tty_stdin = true, .bus_endpoint_fd = -1, + .stdin_fd = -1, + .stdout_fd = -1, + .stderr_fd = -1, }; assert(m); @@ -849,6 +865,31 @@ fail: mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES); } +static int mount_get_opts(Mount *m, char **_opts) { + int r; + char *o = NULL, *opts = NULL; + + r = fstab_filter_options(m->parameters_fragment.options, + "nofail\0" "noauto\0" "auto\0", NULL, NULL, &o); + if (r < 0) + return r; + + if (mac_smack_use() && m->smack_fs_root_label) { + if (!isempty(o)) { + opts = strjoin(o, ",", "smackfsroot=", m->smack_fs_root_label, NULL); + free(o); + } else + opts = strjoin("smackfsroot=", m->smack_fs_root_label, NULL); + + if (!opts) + return -ENOMEM; + } else + opts = o; + + *_opts = opts; + return 0; +} + static void mount_enter_mounting(Mount *m) { int r; MountParameters *p; @@ -874,8 +915,7 @@ static void mount_enter_mounting(Mount *m) { if (m->from_fragment) { _cleanup_free_ char *opts = NULL; - r = fstab_filter_options(m->parameters_fragment.options, - "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts); + r = mount_get_opts(m, &opts); if (r < 0) goto fail; @@ -1756,24 +1796,6 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error); } -static const char* const mount_state_table[_MOUNT_STATE_MAX] = { - [MOUNT_DEAD] = "dead", - [MOUNT_MOUNTING] = "mounting", - [MOUNT_MOUNTING_DONE] = "mounting-done", - [MOUNT_MOUNTED] = "mounted", - [MOUNT_REMOUNTING] = "remounting", - [MOUNT_UNMOUNTING] = "unmounting", - [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm", - [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill", - [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm", - [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill", - [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm", - [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill", - [MOUNT_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState); - static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = { [MOUNT_EXEC_MOUNT] = "ExecMount", [MOUNT_EXEC_UNMOUNT] = "ExecUnmount", diff --git a/src/core/mount.h b/src/core/mount.h index 280ea0d638..b344b5aa13 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -26,24 +26,6 @@ typedef struct Mount Mount; #include "kill.h" #include "execute.h" -typedef enum MountState { - MOUNT_DEAD, - MOUNT_MOUNTING, /* /usr/bin/mount is running, but the mount is not done yet. */ - MOUNT_MOUNTING_DONE, /* /usr/bin/mount is running, and the mount is done. */ - MOUNT_MOUNTED, - MOUNT_REMOUNTING, - MOUNT_UNMOUNTING, - MOUNT_MOUNTING_SIGTERM, - MOUNT_MOUNTING_SIGKILL, - MOUNT_REMOUNTING_SIGTERM, - MOUNT_REMOUNTING_SIGKILL, - MOUNT_UNMOUNTING_SIGTERM, - MOUNT_UNMOUNTING_SIGKILL, - MOUNT_FAILED, - _MOUNT_STATE_MAX, - _MOUNT_STATE_INVALID = -1 -} MountState; - typedef enum MountExecCommand { MOUNT_EXEC_MOUNT, MOUNT_EXEC_UNMOUNT, @@ -89,6 +71,7 @@ struct Mount { bool reset_cpu_usage:1; bool sloppy_options; + char *smack_fs_root_label; MountResult result; MountResult reload_result; @@ -120,9 +103,6 @@ extern const UnitVTable mount_vtable; void mount_fd_event(Manager *m, int events); -const char* mount_state_to_string(MountState i) _const_; -MountState mount_state_from_string(const char *s) _pure_; - const char* mount_exec_command_to_string(MountExecCommand i) _const_; MountExecCommand mount_exec_command_from_string(const char *s) _pure_; diff --git a/src/core/namespace.c b/src/core/namespace.c index eb88574f8f..81ba09ea5d 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -20,23 +20,31 @@ ***/ #include <errno.h> -#include <sys/mount.h> -#include <string.h> +#include <sched.h> #include <stdio.h> -#include <unistd.h> +#include <string.h> +#include <sys/mount.h> #include <sys/stat.h> -#include <sched.h> +#include <unistd.h> #include <linux/fs.h> -#include "strv.h" -#include "util.h" -#include "path-util.h" -#include "missing.h" -#include "loopback-setup.h" +#include "alloc-util.h" #include "dev-setup.h" -#include "selinux-util.h" -#include "namespace.h" +#include "fd-util.h" +#include "loopback-setup.h" +#include "missing.h" #include "mkdir.h" +#include "mount-util.h" +#include "namespace.h" +#include "path-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "umask-util.h" +#include "user-util.h" +#include "util.h" typedef enum MountMode { /* This is ordered by priority! */ @@ -643,16 +651,7 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) { int setup_netns(int netns_storage_socket[2]) { _cleanup_close_ int netns = -1; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control = {}; - struct msghdr mh = { - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - int r; + int r, q; assert(netns_storage_socket); assert(netns_storage_socket[0] >= 0); @@ -669,12 +668,8 @@ int setup_netns(int netns_storage_socket[2]) { if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0) return -errno; - if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) { - if (errno != EAGAIN) { - r = -errno; - goto fail; - } - + netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT); + if (netns == -EAGAIN) { /* Nothing stored yet, so let's create a new namespace */ if (unshare(CLONE_NEWNET) < 0) { @@ -691,15 +686,13 @@ int setup_netns(int netns_storage_socket[2]) { } r = 1; - } else { - /* Yay, found something, so let's join the namespace */ - CMSG_FOREACH(cmsg, &mh) - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int))); - netns = *(int*) CMSG_DATA(cmsg); - } + } else if (netns < 0) { + r = netns; + goto fail; + } else { + /* Yay, found something, so let's join the namespace */ if (setns(netns, CLONE_NEWNET) < 0) { r = -errno; goto fail; @@ -708,21 +701,14 @@ int setup_netns(int netns_storage_socket[2]) { r = 0; } - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &netns, sizeof(int)); - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) { - r = -errno; + q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT); + if (q < 0) { + r = q; goto fail; } fail: lockf(netns_storage_socket[0], F_ULOCK, 0); - return r; } diff --git a/src/core/path.c b/src/core/path.c index e9111d0612..35e1753583 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -19,20 +19,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/inotify.h> -#include <sys/epoll.h> #include <errno.h> +#include <sys/epoll.h> +#include <sys/inotify.h> #include <unistd.h> -#include "unit.h" -#include "unit-name.h" -#include "path.h" -#include "mkdir.h" +#include "bus-error.h" +#include "bus-util.h" #include "dbus-path.h" -#include "special.h" +#include "fd-util.h" +#include "fs-util.h" +#include "glob-util.h" #include "macro.h" -#include "bus-util.h" -#include "bus-error.h" +#include "mkdir.h" +#include "path.h" +#include "special.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "unit-name.h" +#include "unit.h" static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = { [PATH_DEAD] = UNIT_INACTIVE, @@ -715,15 +721,6 @@ static void path_reset_failed(Unit *u) { p->result = PATH_SUCCESS; } -static const char* const path_state_table[_PATH_STATE_MAX] = { - [PATH_DEAD] = "dead", - [PATH_WAITING] = "waiting", - [PATH_RUNNING] = "running", - [PATH_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(path_state, PathState); - static const char* const path_type_table[_PATH_TYPE_MAX] = { [PATH_EXISTS] = "PathExists", [PATH_EXISTS_GLOB] = "PathExistsGlob", diff --git a/src/core/path.h b/src/core/path.h index dec39333e4..deb9bab1e5 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -26,15 +26,6 @@ typedef struct PathSpec PathSpec; #include "unit.h" -typedef enum PathState { - PATH_DEAD, - PATH_WAITING, - PATH_RUNNING, - PATH_FAILED, - _PATH_STATE_MAX, - _PATH_STATE_INVALID = -1 -} PathState; - typedef enum PathType { PATH_EXISTS, PATH_EXISTS_GLOB, @@ -96,9 +87,6 @@ void path_free_specs(Path *p); extern const UnitVTable path_vtable; -const char* path_state_to_string(PathState i) _const_; -PathState path_state_from_string(const char *s) _pure_; - const char* path_type_to_string(PathType i) _const_; PathType path_type_from_string(const char *s) _pure_; diff --git a/src/core/scope.c b/src/core/scope.c index 98395becfd..6bacb226e8 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -22,14 +22,17 @@ #include <errno.h> #include <unistd.h> +#include "alloc-util.h" +#include "dbus-scope.h" +#include "load-dropin.h" #include "log.h" -#include "strv.h" +#include "scope.h" #include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" #include "unit-name.h" #include "unit.h" -#include "scope.h" -#include "dbus-scope.h" -#include "load-dropin.h" static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = { [SCOPE_DEAD] = UNIT_INACTIVE, @@ -534,6 +537,9 @@ static int scope_enumerate(Manager *m) { u->transient = true; u->default_dependencies = false; u->no_gc = true; + u->ignore_on_isolate = true; + u->refuse_manual_start = true; + u->refuse_manual_stop = true; SCOPE(u)->deserialized_state = SCOPE_RUNNING; SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14; @@ -549,17 +555,6 @@ static int scope_enumerate(Manager *m) { return 0; } -static const char* const scope_state_table[_SCOPE_STATE_MAX] = { - [SCOPE_DEAD] = "dead", - [SCOPE_RUNNING] = "running", - [SCOPE_ABANDONED] = "abandoned", - [SCOPE_STOP_SIGTERM] = "stop-sigterm", - [SCOPE_STOP_SIGKILL] = "stop-sigkill", - [SCOPE_FAILED] = "failed", -}; - -DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState); - static const char* const scope_result_table[_SCOPE_RESULT_MAX] = { [SCOPE_SUCCESS] = "success", [SCOPE_FAILURE_RESOURCES] = "resources", diff --git a/src/core/scope.h b/src/core/scope.h index 4452fe2c94..f838ee5357 100644 --- a/src/core/scope.h +++ b/src/core/scope.h @@ -25,17 +25,6 @@ typedef struct Scope Scope; #include "kill.h" -typedef enum ScopeState { - SCOPE_DEAD, - SCOPE_RUNNING, - SCOPE_ABANDONED, - SCOPE_STOP_SIGTERM, - SCOPE_STOP_SIGKILL, - SCOPE_FAILED, - _SCOPE_STATE_MAX, - _SCOPE_STATE_INVALID = -1 -} ScopeState; - typedef enum ScopeResult { SCOPE_SUCCESS, SCOPE_FAILURE_RESOURCES, @@ -64,8 +53,5 @@ extern const UnitVTable scope_vtable; int scope_abandon(Scope *s); -const char* scope_state_to_string(ScopeState i) _const_; -ScopeState scope_state_from_string(const char *s) _pure_; - const char* scope_result_to_string(ScopeResult i) _const_; ScopeResult scope_result_from_string(const char *s) _pure_; diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index 40ca0c6166..4bcdd27389 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -32,13 +32,16 @@ #endif #include "sd-bus.h" + +#include "alloc-util.h" +#include "audit-fd.h" #include "bus-util.h" -#include "util.h" #include "log.h" +#include "path-util.h" #include "selinux-util.h" -#include "audit-fd.h" +#include "stdio-util.h" #include "strv.h" -#include "path-util.h" +#include "util.h" static bool initialized = false; @@ -178,17 +181,6 @@ static int mac_selinux_access_init(sd_bus_error *error) { } #endif -void mac_selinux_access_free(void) { - -#ifdef HAVE_SELINUX - if (!initialized) - return; - - avc_destroy(); - initialized = false; -#endif -} - /* This function communicates with the kernel to check whether or not it should allow the access. diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index e6b4dd7fee..30725521cb 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -25,8 +25,6 @@ #include "bus-util.h" #include "manager.h" -void mac_selinux_access_free(void); - int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error); #ifdef HAVE_SELINUX diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index e5b457643b..d9b00fb95c 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -19,19 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <stdio.h> #include <errno.h> +#include <stdio.h> +#include <unistd.h> #ifdef HAVE_SELINUX #include <selinux/selinux.h> #endif -#include "selinux-setup.h" -#include "selinux-util.h" +#include "log.h" #include "macro.h" +#include "selinux-util.h" +#include "string-util.h" #include "util.h" -#include "log.h" +#include "selinux-setup.h" #ifdef HAVE_SELINUX _printf_(2,3) @@ -78,14 +79,14 @@ int mac_selinux_setup(bool *loaded_policy) { before_load = now(CLOCK_MONOTONIC); r = selinux_init_load_policy(&enforce); if (r == 0) { + _cleanup_(mac_selinux_freep) char *label = NULL; char timespan[FORMAT_TIMESPAN_MAX]; - char *label; mac_selinux_retest(); /* Transition to the new context */ r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label); - if (r < 0 || label == NULL) { + if (r < 0 || !label) { log_open(); log_error("Failed to compute init label, ignoring."); } else { @@ -94,8 +95,6 @@ int mac_selinux_setup(bool *loaded_policy) { log_open(); if (r < 0) log_error("Failed to transition into init label '%s', ignoring.", label); - - mac_selinux_free(label); } after_load = now(CLOCK_MONOTONIC); diff --git a/src/core/service.c b/src/core/service.c index f7de5e89ff..586eddd99a 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -23,31 +23,38 @@ #include <signal.h> #include <unistd.h> +#include "alloc-util.h" #include "async.h" -#include "manager.h" -#include "unit.h" -#include "service.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "log.h" -#include "strv.h" -#include "unit-name.h" -#include "unit-printf.h" +#include "bus-error.h" +#include "bus-kernel.h" +#include "bus-util.h" #include "dbus-service.h" -#include "special.h" -#include "exit-status.h" #include "def.h" -#include "path-util.h" -#include "util.h" -#include "utf8.h" #include "env-util.h" +#include "escape.h" +#include "exit-status.h" +#include "fd-util.h" #include "fileio.h" -#include "bus-error.h" -#include "bus-util.h" -#include "bus-kernel.h" #include "formats-util.h" +#include "fs-util.h" +#include "load-dropin.h" +#include "load-fragment.h" +#include "log.h" +#include "manager.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" +#include "service.h" #include "signal-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" +#include "utf8.h" +#include "util.h" static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = { [SERVICE_DEAD] = UNIT_INACTIVE, @@ -108,6 +115,7 @@ static void service_init(Unit *u) { s->type = _SERVICE_TYPE_INVALID; s->socket_fd = -1; s->bus_endpoint_fd = -1; + s->stdin_fd = s->stdout_fd = s->stderr_fd = -1; s->guess_main_pid = true; RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst); @@ -167,7 +175,7 @@ static int service_set_main_pid(Service *s, pid_t pid) { s->main_pid = pid; s->main_pid_known = true; - if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) { + if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid()) { log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid); s->main_pid_alien = true; } else @@ -261,6 +269,7 @@ static void service_fd_store_unlink(ServiceFDStore *fs) { sd_event_source_unref(fs->event_source); } + free(fs->fdname); safe_close(fs->fd); free(fs); } @@ -270,11 +279,15 @@ static void service_release_resources(Unit *u) { assert(s); - if (!s->fd_store) + if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0) return; log_unit_debug(u, "Releasing all resources."); + s->stdin_fd = safe_close(s->stdin_fd); + s->stdout_fd = safe_close(s->stdout_fd); + s->stderr_fd = safe_close(s->stderr_fd); + while (s->fd_store) service_fd_store_unlink(s->fd_store); @@ -334,7 +347,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us return 0; } -static int service_add_fd_store(Service *s, int fd) { +static int service_add_fd_store(Service *s, int fd, const char *name) { ServiceFDStore *fs; int r; @@ -361,9 +374,15 @@ static int service_add_fd_store(Service *s, int fd) { fs->fd = fd; fs->service = s; + fs->fdname = strdup(name ?: "stored"); + if (!fs->fdname) { + free(fs); + return -ENOMEM; + } r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs); if (r < 0) { + free(fs->fdname); free(fs); return r; } @@ -376,7 +395,7 @@ static int service_add_fd_store(Service *s, int fd) { return 1; } -static int service_add_fd_store_set(Service *s, FDSet *fds) { +static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) { int r; assert(s); @@ -391,7 +410,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) { if (fd < 0) break; - r = service_add_fd_store(s, fd); + r = service_add_fd_store(s, fd, name); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m"); if (r > 0) { @@ -401,7 +420,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) { } if (fdset_size(fds) > 0) - log_unit_warning(UNIT(s), "Tried to store more fds than FDStoreMax=%u allows, closing remaining.", s->n_fd_store_max); + log_unit_warning(UNIT(s), "Tried to store more fds than FileDescriptorStoreMax=%u allows, closing remaining.", s->n_fd_store_max); return 0; } @@ -884,7 +903,6 @@ static void service_set_state(Service *s, ServiceState state) { log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state)); unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS); - s->reload_result = SERVICE_SUCCESS; } static int service_coldplug(Unit *u) { @@ -894,125 +912,143 @@ static int service_coldplug(Unit *u) { assert(s); assert(s->state == SERVICE_DEAD); - if (s->deserialized_state != s->state) { - - if (IN_SET(s->deserialized_state, - SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, - SERVICE_RELOAD, - SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - - usec_t k; - - k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec; + if (s->deserialized_state == s->state) + return 0; - /* For the start/stop timeouts 0 means off */ - if (k > 0) { - r = service_arm_timer(s, k); - if (r < 0) - return r; - } - } + if (IN_SET(s->deserialized_state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - if (s->deserialized_state == SERVICE_AUTO_RESTART) { + usec_t k; - /* The restart timeouts 0 means immediately */ - r = service_arm_timer(s, s->restart_usec); - if (r < 0) - return r; - } + k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec; - if (pid_is_unwaited(s->main_pid) && - ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) || - IN_SET(s->deserialized_state, - SERVICE_START, SERVICE_START_POST, - SERVICE_RUNNING, SERVICE_RELOAD, - SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { - r = unit_watch_pid(UNIT(s), s->main_pid); + /* For the start/stop timeouts 0 means off */ + if (k > 0) { + r = service_arm_timer(s, k); if (r < 0) return r; } + } - if (pid_is_unwaited(s->control_pid) && - IN_SET(s->deserialized_state, - SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, - SERVICE_RELOAD, - SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - r = unit_watch_pid(UNIT(s), s->control_pid); - if (r < 0) - return r; - } + if (s->deserialized_state == SERVICE_AUTO_RESTART) { - if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) - unit_watch_all_pids(UNIT(s)); + /* The restart timeouts 0 means immediately */ + r = service_arm_timer(s, s->restart_usec); + if (r < 0) + return r; + } - if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) - service_start_watchdog(s); + if (s->main_pid > 0 && + pid_is_unwaited(s->main_pid) && + ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) || + IN_SET(s->deserialized_state, + SERVICE_START, SERVICE_START_POST, + SERVICE_RUNNING, SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { + r = unit_watch_pid(UNIT(s), s->main_pid); + if (r < 0) + return r; + } - service_set_state(s, s->deserialized_state); + if (s->control_pid > 0 && + pid_is_unwaited(s->control_pid) && + IN_SET(s->deserialized_state, + SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RELOAD, + SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { + r = unit_watch_pid(UNIT(s), s->control_pid); + if (r < 0) + return r; } + if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) + unit_watch_all_pids(UNIT(s)); + + if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) + service_start_watchdog(s); + + service_set_state(s, s->deserialized_state); return 0; } -static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { +static int service_collect_fds(Service *s, int **fds, char ***fd_names) { + _cleanup_strv_free_ char **rfd_names = NULL; _cleanup_free_ int *rfds = NULL; - unsigned rn_fds = 0; - Iterator i; - int r; - Unit *u; + int rn_fds = 0, r; assert(s); assert(fds); - assert(n_fds); + assert(fd_names); - if (s->socket_fd >= 0) - return 0; + if (s->socket_fd >= 0) { - SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) { - int *cfds; - unsigned cn_fds; - Socket *sock; + /* Pass the per-connection socket */ - if (u->type != UNIT_SOCKET) - continue; + rfds = new(int, 1); + if (!rfds) + return -ENOMEM; + rfds[0] = s->socket_fd; - sock = SOCKET(u); + rfd_names = strv_new("connection", NULL); + if (!rfd_names) + return -ENOMEM; - r = socket_collect_fds(sock, &cfds, &cn_fds); - if (r < 0) - return r; + rn_fds = 1; + } else { + Iterator i; + Unit *u; - if (cn_fds <= 0) { - free(cfds); - continue; - } + /* Pass all our configured sockets for singleton services */ - if (!rfds) { - rfds = cfds; - rn_fds = cn_fds; - } else { - int *t; + SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) { + _cleanup_free_ int *cfds = NULL; + Socket *sock; + int cn_fds; - t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int)); - if (!t) { - free(cfds); - return -ENOMEM; - } + if (u->type != UNIT_SOCKET) + continue; + + sock = SOCKET(u); + + cn_fds = socket_collect_fds(sock, &cfds); + if (cn_fds < 0) + return cn_fds; + + if (cn_fds <= 0) + continue; + + if (!rfds) { + rfds = cfds; + rn_fds = cn_fds; + + cfds = NULL; + } else { + int *t; - memcpy(t + rn_fds, cfds, cn_fds * sizeof(int)); - rfds = t; - rn_fds += cn_fds; + t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int)); + if (!t) + return -ENOMEM; + + memcpy(t + rn_fds, cfds, cn_fds * sizeof(int)); - free(cfds); + rfds = t; + rn_fds += cn_fds; + } + r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds); + if (r < 0) + return r; } } if (s->n_fd_store > 0) { ServiceFDStore *fs; + char **nl; int *t; t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int)); @@ -1020,15 +1056,32 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) { return -ENOMEM; rfds = t; - LIST_FOREACH(fd_store, fs, s->fd_store) - rfds[rn_fds++] = fs->fd; + + nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*)); + if (!nl) + return -ENOMEM; + + rfd_names = nl; + + LIST_FOREACH(fd_store, fs, s->fd_store) { + rfds[rn_fds] = fs->fd; + rfd_names[rn_fds] = strdup(strempty(fs->fdname)); + if (!rfd_names[rn_fds]) + return -ENOMEM; + + rn_fds++; + } + + rfd_names[rn_fds] = NULL; } *fds = rfds; - *n_fds = rn_fds; + *fd_names = rfd_names; rfds = NULL; - return 0; + rfd_names = NULL; + + return rn_fds; } static int service_spawn( @@ -1042,23 +1095,25 @@ static int service_spawn( bool is_control, pid_t *_pid) { - pid_t pid; - int r; - int *fds = NULL; - _cleanup_free_ int *fdsbuf = NULL; - unsigned n_fds = 0, n_env = 0; + _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL; _cleanup_free_ char *bus_endpoint_path = NULL; - _cleanup_strv_free_ char - **argv = NULL, **final_env = NULL, **our_env = NULL; + _cleanup_free_ int *fds = NULL; + unsigned n_fds = 0, n_env = 0; const char *path; + pid_t pid; + ExecParameters exec_params = { - .apply_permissions = apply_permissions, - .apply_chroot = apply_chroot, - .apply_tty_stdin = apply_tty_stdin, - .bus_endpoint_fd = -1, - .selinux_context_net = s->socket_fd_selinux_context_net + .apply_permissions = apply_permissions, + .apply_chroot = apply_chroot, + .apply_tty_stdin = apply_tty_stdin, + .bus_endpoint_fd = -1, + .stdin_fd = -1, + .stdout_fd = -1, + .stderr_fd = -1, }; + int r; + assert(s); assert(c); assert(_pid); @@ -1078,16 +1133,11 @@ static int service_spawn( s->exec_context.std_output == EXEC_OUTPUT_SOCKET || s->exec_context.std_error == EXEC_OUTPUT_SOCKET) { - if (s->socket_fd >= 0) { - fds = &s->socket_fd; - n_fds = 1; - } else { - r = service_collect_fds(s, &fdsbuf, &n_fds); - if (r < 0) - goto fail; + r = service_collect_fds(s, &fds, &fd_names); + if (r < 0) + goto fail; - fds = fdsbuf; - } + n_fds = r; } if (timeout > 0) { @@ -1125,7 +1175,7 @@ static int service_spawn( goto fail; } - if (UNIT_DEREF(s->accept_socket)) { + if (s->socket_fd >= 0) { union sockaddr_union sa; socklen_t salen = sizeof(sa); @@ -1173,7 +1223,7 @@ static int service_spawn( if (is_control && UNIT(s)->cgroup_path) { path = strjoina(UNIT(s)->cgroup_path, "/control"); - cg_create(SYSTEMD_CGROUP_CONTROLLER, path); + (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path); } else path = UNIT(s)->cgroup_path; @@ -1191,6 +1241,7 @@ static int service_spawn( exec_params.argv = argv; exec_params.fds = fds; + exec_params.fd_names = fd_names; exec_params.n_fds = n_fds; exec_params.environment = final_env; exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn; @@ -1200,8 +1251,12 @@ static int service_spawn( exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager); exec_params.watchdog_usec = s->watchdog_usec; exec_params.bus_endpoint_path = bus_endpoint_path; + exec_params.selinux_context_net = s->socket_fd_selinux_context_net; if (s->type == SERVICE_IDLE) exec_params.idle_pipe = UNIT(s)->manager->idle_pipe; + exec_params.stdin_fd = s->stdin_fd; + exec_params.stdout_fd = s->stdout_fd; + exec_params.stderr_fd = s->stderr_fd; r = exec_spawn(UNIT(s), c, @@ -1778,6 +1833,7 @@ static void service_enter_reload(Service *s) { assert(s); service_unwatch_control_pid(s); + s->reload_result = SERVICE_SUCCESS; s->control_command = s->exec_command[SERVICE_EXEC_RELOAD]; if (s->control_command) { @@ -2001,6 +2057,7 @@ _pure_ static bool service_can_reload(Unit *u) { static int service_serialize(Unit *u, FILE *f, FDSet *fds) { Service *s = SERVICE(u); ServiceFDStore *fs; + int r; assert(u); assert(f); @@ -2019,12 +2076,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known)); unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good)); - if (s->status_text) { - _cleanup_free_ char *c = NULL; - - c = cescape(s->status_text); - unit_serialize_item(u, f, "status-text", strempty(c)); - } + r = unit_serialize_item_escaped(u, f, "status-text", s->status_text); + if (r < 0) + return r; /* FIXME: There's a minor uncleanliness here: if there are * multiple commands attached here, we will start from the @@ -2032,34 +2086,34 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { if (s->control_command_id >= 0) unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id)); - if (s->socket_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, s->socket_fd); - if (copy < 0) - return copy; - - unit_serialize_item_format(u, f, "socket-fd", "%i", copy); - } - - if (s->bus_endpoint_fd >= 0) { - int copy; - - copy = fdset_put_dup(fds, s->bus_endpoint_fd); - if (copy < 0) - return copy; + r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd); + if (r < 0) + return r; + r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd); + if (r < 0) + return r; + r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd); + if (r < 0) + return r; - unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy); - } + r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd); + if (r < 0) + return r; + r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd); + if (r < 0) + return r; LIST_FOREACH(fd_store, fs, s->fd_store) { + _cleanup_free_ char *c = NULL; int copy; copy = fdset_put_dup(fds, fs->fd); if (copy < 0) return copy; - unit_serialize_item_format(u, f, "fd-store-fd", "%i", copy); + c = cescape(fs->fdname); + + unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c)); } if (s->main_exec_status.pid > 0) { @@ -2076,8 +2130,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { if (dual_timestamp_is_set(&s->watchdog_timestamp)) dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp); - if (s->forbid_restart) - unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); + unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart)); return 0; } @@ -2189,12 +2242,24 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, s->bus_endpoint_fd = fdset_remove(fds, fd); } } else if (streq(key, "fd-store-fd")) { + const char *fdv; + size_t pf; int fd; - if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + pf = strcspn(value, WHITESPACE); + fdv = strndupa(value, pf); + + if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value); else { - r = service_add_fd_store(s, fd); + _cleanup_free_ char *t = NULL; + const char *fdn; + + fdn = value + pf; + fdn += strspn(fdn, WHITESPACE); + (void) cunescape(fdn, 0, &t); + + r = service_add_fd_store(s, fd, t); if (r < 0) log_unit_error_errno(u, r, "Failed to add fd to store: %m"); else if (r > 0) @@ -2236,6 +2301,33 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, log_unit_debug(u, "Failed to parse forbid-restart value: %s", value); else s->forbid_restart = b; + } else if (streq(key, "stdin-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_unit_debug(u, "Failed to parse stdin-fd value: %s", value); + else { + asynchronous_close(s->stdin_fd); + s->stdin_fd = fdset_remove(fds, fd); + } + } else if (streq(key, "stdout-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_unit_debug(u, "Failed to parse stdout-fd value: %s", value); + else { + asynchronous_close(s->stdout_fd); + s->stdout_fd = fdset_remove(fds, fd); + } + } else if (streq(key, "stderr-fd")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd)) + log_unit_debug(u, "Failed to parse stderr-fd value: %s", value); + else { + asynchronous_close(s->stderr_fd); + s->stderr_fd = fdset_remove(fds, fd); + } } else log_unit_debug(u, "Unknown serialization key: %s", key); @@ -2948,8 +3040,17 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) if (strv_find(tags, "WATCHDOG=1")) service_reset_watchdog(s); - if (strv_find(tags, "FDSTORE=1")) - service_add_fd_store_set(s, fds); + if (strv_find(tags, "FDSTORE=1")) { + const char *name; + + name = strv_find_startswith(tags, "FDNAME="); + if (name && !fdname_is_valid(name)) { + log_unit_warning(u, "Passed FDNAME= name is invalid, ignoring."); + name = NULL; + } + + service_add_fd_store_set(s, fds, name); + } /* Notify clients about changed status or main pid */ if (notify_dbus) @@ -3092,27 +3193,6 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error); } -static const char* const service_state_table[_SERVICE_STATE_MAX] = { - [SERVICE_DEAD] = "dead", - [SERVICE_START_PRE] = "start-pre", - [SERVICE_START] = "start", - [SERVICE_START_POST] = "start-post", - [SERVICE_RUNNING] = "running", - [SERVICE_EXITED] = "exited", - [SERVICE_RELOAD] = "reload", - [SERVICE_STOP] = "stop", - [SERVICE_STOP_SIGABRT] = "stop-sigabrt", - [SERVICE_STOP_SIGTERM] = "stop-sigterm", - [SERVICE_STOP_SIGKILL] = "stop-sigkill", - [SERVICE_STOP_POST] = "stop-post", - [SERVICE_FINAL_SIGTERM] = "final-sigterm", - [SERVICE_FINAL_SIGKILL] = "final-sigkill", - [SERVICE_FAILED] = "failed", - [SERVICE_AUTO_RESTART] = "auto-restart", -}; - -DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState); - static const char* const service_restart_table[_SERVICE_RESTART_MAX] = { [SERVICE_RESTART_NO] = "no", [SERVICE_RESTART_ON_SUCCESS] = "on-success", diff --git a/src/core/service.h b/src/core/service.h index 789dff23a9..e765668247 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -29,27 +29,6 @@ typedef struct ServiceFDStore ServiceFDStore; #include "kill.h" #include "exit-status.h" -typedef enum ServiceState { - SERVICE_DEAD, - SERVICE_START_PRE, - SERVICE_START, - SERVICE_START_POST, - SERVICE_RUNNING, - SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */ - SERVICE_RELOAD, - SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */ - SERVICE_STOP_SIGABRT, /* Watchdog timeout */ - SERVICE_STOP_SIGTERM, - SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */ - SERVICE_FINAL_SIGKILL, - SERVICE_FAILED, - SERVICE_AUTO_RESTART, - _SERVICE_STATE_MAX, - _SERVICE_STATE_INVALID = -1 -} ServiceState; - typedef enum ServiceRestart { SERVICE_RESTART_NO, SERVICE_RESTART_ON_SUCCESS, @@ -118,6 +97,7 @@ struct ServiceFDStore { Service *service; int fd; + char *fdname; sd_event_source *event_source; LIST_FIELDS(ServiceFDStore, fd_store); @@ -215,15 +195,16 @@ struct Service { char *usb_function_descriptors; char *usb_function_strings; + + int stdin_fd; + int stdout_fd; + int stderr_fd; }; extern const UnitVTable service_vtable; int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net); -const char* service_state_to_string(ServiceState i) _const_; -ServiceState service_state_from_string(const char *s) _pure_; - const char* service_restart_to_string(ServiceRestart i) _const_; ServiceRestart service_restart_from_string(const char *s) _pure_; diff --git a/src/core/show-status.c b/src/core/show-status.c index 02b1be73e3..e4e12a3365 100644 --- a/src/core/show-status.c +++ b/src/core/show-status.c @@ -19,7 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "parse-util.h" #include "show-status.h" +#include "string-util.h" +#include "terminal-util.h" #include "util.h" int parse_show_status(const char *v, ShowStatus *ret) { @@ -40,3 +46,81 @@ int parse_show_status(const char *v, ShowStatus *ret) { *ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO; return 0; } + +int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { + static const char status_indent[] = " "; /* "[" STATUS "] " */ + _cleanup_free_ char *s = NULL; + _cleanup_close_ int fd = -1; + struct iovec iovec[6] = {}; + int n = 0; + static bool prev_ephemeral; + + assert(format); + + /* This is independent of logging, as status messages are + * optional and go exclusively to the console. */ + + if (vasprintf(&s, format, ap) < 0) + return log_oom(); + + fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return fd; + + if (ellipse) { + char *e; + size_t emax, sl; + int c; + + c = fd_columns(fd); + if (c <= 0) + c = 80; + + sl = status ? sizeof(status_indent)-1 : 0; + + emax = c - sl - 1; + if (emax < 3) + emax = 3; + + e = ellipsize(s, emax, 50); + if (e) { + free(s); + s = e; + } + } + + if (prev_ephemeral) + IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); + prev_ephemeral = ephemeral; + + if (status) { + if (!isempty(status)) { + IOVEC_SET_STRING(iovec[n++], "["); + IOVEC_SET_STRING(iovec[n++], status); + IOVEC_SET_STRING(iovec[n++], "] "); + } else + IOVEC_SET_STRING(iovec[n++], status_indent); + } + + IOVEC_SET_STRING(iovec[n++], s); + if (!ephemeral) + IOVEC_SET_STRING(iovec[n++], "\n"); + + if (writev(fd, iovec, n) < 0) + return -errno; + + return 0; +} + +int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) { + va_list ap; + int r; + + assert(format); + + va_start(ap, format); + r = status_vprintf(status, ellipse, ephemeral, format, ap); + va_end(ap); + + return r; +} diff --git a/src/core/show-status.h b/src/core/show-status.h index a2b2153746..c79d4acb66 100644 --- a/src/core/show-status.h +++ b/src/core/show-status.h @@ -21,6 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <stdbool.h> + +#include "macro.h" + /* Manager status */ typedef enum ShowStatus { @@ -32,3 +36,6 @@ typedef enum ShowStatus { } ShowStatus; int parse_show_status(const char *v, ShowStatus *ret); + +int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); +int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 5296efce1d..3a95b5fd72 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -19,31 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/mman.h> -#include <sys/reboot.h> -#include <linux/reboot.h> -#include <sys/stat.h> -#include <sys/mount.h> #include <errno.h> -#include <unistd.h> +#include <getopt.h> +#include <linux/reboot.h> #include <signal.h> #include <stdbool.h> #include <stdlib.h> -#include <getopt.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/reboot.h> +#include <sys/stat.h> +#include <unistd.h> -#include "missing.h" -#include "log.h" +#include "alloc-util.h" +#include "cgroup-util.h" +#include "def.h" #include "fileio.h" +#include "killall.h" +#include "log.h" +#include "missing.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" +#include "switch-root.h" +#include "terminal-util.h" #include "umount.h" #include "util.h" #include "virt.h" #include "watchdog.h" -#include "killall.h" -#include "cgroup-util.h" -#include "def.h" -#include "switch-root.h" -#include "process-util.h" -#include "terminal-util.h" #define FINALIZE_ATTEMPTS 50 @@ -430,6 +433,5 @@ int main(int argc, char *argv[]) { error: log_emergency_errno(r, "Critical error while doing system shutdown: %m"); - freeze(); } diff --git a/src/core/slice.c b/src/core/slice.c index b414462066..4602144150 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -21,13 +21,15 @@ #include <errno.h> +#include "alloc-util.h" +#include "dbus-slice.h" #include "log.h" -#include "strv.h" #include "special.h" +#include "string-util.h" +#include "strv.h" #include "unit-name.h" #include "unit.h" #include "slice.h" -#include "dbus-slice.h" static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = { [SLICE_DEAD] = UNIT_INACTIVE, @@ -274,6 +276,9 @@ static int slice_enumerate(Manager *m) { u->default_dependencies = false; u->no_gc = true; + u->ignore_on_isolate = true; + u->refuse_manual_start = true; + u->refuse_manual_stop = true; SLICE(u)->deserialized_state = SLICE_ACTIVE; if (!u->description) @@ -287,13 +292,6 @@ static int slice_enumerate(Manager *m) { return 0; } -static const char* const slice_state_table[_SLICE_STATE_MAX] = { - [SLICE_DEAD] = "dead", - [SLICE_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState); - const UnitVTable slice_vtable = { .object_size = sizeof(Slice), .cgroup_context_offset = offsetof(Slice, cgroup_context), diff --git a/src/core/slice.h b/src/core/slice.h index ac648e56f8..0c356651e3 100644 --- a/src/core/slice.h +++ b/src/core/slice.h @@ -23,14 +23,6 @@ typedef struct Slice Slice; - -typedef enum SliceState { - SLICE_DEAD, - SLICE_ACTIVE, - _SLICE_STATE_MAX, - _SLICE_STATE_INVALID = -1 -} SliceState; - struct Slice { Unit meta; @@ -40,6 +32,3 @@ struct Slice { }; extern const UnitVTable slice_vtable; - -const char* slice_state_to_string(SliceState i) _const_; -SliceState slice_state_from_string(const char *s) _pure_; diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index cbe7d0b4a9..0661ff9ecd 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -21,18 +21,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <dirent.h> #include <errno.h> -#include <string.h> -#include <stdlib.h> #include <fcntl.h> -#include <dirent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" #include "macro.h" #include "smack-setup.h" +#include "string-util.h" #include "util.h" -#include "fileio.h" -#include "log.h" #ifdef HAVE_SMACK @@ -215,16 +219,14 @@ int mac_smack_setup(bool *loaded_policy) { log_info("Successfully loaded Smack policies."); break; default: - log_warning("Failed to load Smack access rules: %s, ignoring.", - strerror(abs(r))); + log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m"); return 0; } #ifdef SMACK_RUN_LABEL r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0); if (r) - log_warning("Failed to set SMACK label \"%s\" on self: %s", - SMACK_RUN_LABEL, strerror(-r)); + log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL); #endif r = write_cipso2_rules("/etc/smack/cipso.d/"); @@ -239,8 +241,7 @@ int mac_smack_setup(bool *loaded_policy) { log_info("Successfully loaded Smack/CIPSO policies."); break; default: - log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.", - strerror(abs(r))); + log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m"); return 0; } diff --git a/src/core/snapshot.c b/src/core/snapshot.c index 336ff20f84..ba3135f401 100644 --- a/src/core/snapshot.c +++ b/src/core/snapshot.c @@ -21,11 +21,15 @@ #include <errno.h> -#include "unit.h" +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "dbus-snapshot.h" +#include "parse-util.h" +#include "parse-util.h" #include "snapshot.h" +#include "string-util.h" #include "unit-name.h" -#include "dbus-snapshot.h" -#include "bus-common-errors.h" +#include "unit.h" static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = { [SNAPSHOT_DEAD] = UNIT_INACTIVE, @@ -272,13 +276,6 @@ void snapshot_remove(Snapshot *s) { unit_add_to_cleanup_queue(UNIT(s)); } -static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = { - [SNAPSHOT_DEAD] = "dead", - [SNAPSHOT_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState); - const UnitVTable snapshot_vtable = { .object_size = sizeof(Snapshot), diff --git a/src/core/snapshot.h b/src/core/snapshot.h index f2451b1193..bd52dea408 100644 --- a/src/core/snapshot.h +++ b/src/core/snapshot.h @@ -23,13 +23,7 @@ typedef struct Snapshot Snapshot; - -typedef enum SnapshotState { - SNAPSHOT_DEAD, - SNAPSHOT_ACTIVE, - _SNAPSHOT_STATE_MAX, - _SNAPSHOT_STATE_INVALID = -1 -} SnapshotState; +#include "unit.h" struct Snapshot { Unit meta; @@ -43,6 +37,3 @@ extern const UnitVTable snapshot_vtable; int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s); void snapshot_remove(Snapshot *s); - -const char* snapshot_state_to_string(SnapshotState i) _const_; -SnapshotState snapshot_state_from_string(const char *s) _pure_; diff --git a/src/core/socket.c b/src/core/socket.c index 54e94c4f74..3c7f972fbc 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -19,38 +19,46 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/stat.h> -#include <unistd.h> +#include <arpa/inet.h> #include <errno.h> #include <fcntl.h> -#include <sys/epoll.h> -#include <signal.h> -#include <arpa/inet.h> -#include <netinet/tcp.h> #include <mqueue.h> +#include <netinet/tcp.h> +#include <signal.h> +#include <sys/epoll.h> +#include <sys/stat.h> +#include <unistd.h> #include "sd-event.h" + +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" +#include "copy.h" +#include "dbus-socket.h" +#include "def.h" +#include "exit-status.h" +#include "fd-util.h" +#include "formats-util.h" +#include "label.h" #include "log.h" -#include "strv.h" +#include "missing.h" #include "mkdir.h" +#include "parse-util.h" #include "path-util.h" -#include "unit-name.h" -#include "unit-printf.h" -#include "missing.h" -#include "special.h" -#include "label.h" -#include "exit-status.h" -#include "def.h" -#include "smack-util.h" -#include "bus-util.h" -#include "bus-error.h" +#include "process-util.h" #include "selinux-util.h" -#include "dbus-socket.h" -#include "unit.h" -#include "formats-util.h" #include "signal-util.h" +#include "smack-util.h" #include "socket.h" -#include "copy.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "unit-printf.h" +#include "unit.h" +#include "user-util.h" static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = { [SOCKET_DEAD] = UNIT_INACTIVE, @@ -106,11 +114,9 @@ static void socket_unwatch_control_pid(Socket *s) { } static void socket_cleanup_fd_list(SocketPort *p) { - int k = p->n_auxiliary_fds; - - while (k--) - safe_close(p->auxiliary_fds[k]); + assert(p); + close_many(p->auxiliary_fds, p->n_auxiliary_fds); p->auxiliary_fds = mfree(p->auxiliary_fds); p->n_auxiliary_fds = 0; } @@ -506,6 +512,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { "%sPassSecurity: %s\n" "%sTCPCongestion: %s\n" "%sRemoveOnStop: %s\n" + "%sWritable: %s\n" + "%sFDName: %s\n" "%sSELinuxContextFromNet: %s\n", prefix, socket_state_to_string(s->state), prefix, socket_result_to_string(s->result), @@ -522,6 +530,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(s->pass_sec), prefix, strna(s->tcp_congestion), prefix, yes_no(s->remove_on_stop), + prefix, yes_no(s->writable), + prefix, socket_fdname(s), prefix, yes_no(s->selinux_context_from_net)); if (s->control_pid > 0) @@ -642,7 +652,8 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) { int r; char *k = NULL; - if ((r = socket_address_print(&p->address, &k)) < 0) + r = socket_address_print(&p->address, &k); + if (r < 0) t = strerror(-r); else t = k; @@ -955,50 +966,48 @@ static void socket_apply_fifo_options(Socket *s, int fd) { if (s->pipe_size > 0) if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0) - log_unit_warning_errno(UNIT(s), errno, "F_SETPIPE_SZ: %m"); + log_unit_warning_errno(UNIT(s), errno, "Setting pipe size failed, ignoring: %m"); if (s->smack) { r = mac_smack_apply_fd(fd, SMACK_ATTR_ACCESS, s->smack); if (r < 0) - log_unit_error_errno(UNIT(s), r, "mac_smack_apply_fd: %m"); + log_unit_error_errno(UNIT(s), r, "SMACK relabelling failed, ignoring: %m"); } } static int fifo_address_create( const char *path, mode_t directory_mode, - mode_t socket_mode, - int *_fd) { + mode_t socket_mode) { - int fd = -1, r = 0; - struct stat st; + _cleanup_close_ int fd = -1; mode_t old_mask; + struct stat st; + int r; assert(path); - assert(_fd); mkdir_parents_label(path, directory_mode); r = mac_selinux_create_file_prepare(path, S_IFIFO); if (r < 0) - goto fail; + return r; /* Enforce the right access mode for the fifo */ old_mask = umask(~ socket_mode); /* Include the original umask in our mask */ - umask(~socket_mode | old_mask); + (void) umask(~socket_mode | old_mask); r = mkfifo(path, socket_mode); - umask(old_mask); + (void) umask(old_mask); if (r < 0 && errno != EEXIST) { r = -errno; goto fail; } - fd = open(path, - O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW); + fd = open(path, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW); if (fd < 0) { r = -errno; goto fail; @@ -1015,66 +1024,50 @@ static int fifo_address_create( (st.st_mode & 0777) != (socket_mode & ~old_mask) || st.st_uid != getuid() || st.st_gid != getgid()) { - r = -EEXIST; goto fail; } - *_fd = fd; - return 0; + r = fd; + fd = -1; + + return r; fail: mac_selinux_create_file_clear(); - safe_close(fd); - return r; } -static int special_address_create( - const char *path, - int *_fd) { - - int fd = -1, r = 0; +static int special_address_create(const char *path, bool writable) { + _cleanup_close_ int fd = -1; struct stat st; + int r; assert(path); - assert(_fd); - fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW); - if (fd < 0) { - r = -errno; - goto fail; - } + fd = open(path, (writable ? O_RDWR : O_RDONLY)|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW); + if (fd < 0) + return -errno; - if (fstat(fd, &st) < 0) { - r = -errno; - goto fail; - } + if (fstat(fd, &st) < 0) + return -errno; /* Check whether this is a /proc, /sys or /dev file or char device */ - if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) { - r = -EEXIST; - goto fail; - } - - *_fd = fd; - return 0; + if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) + return -EEXIST; -fail: - safe_close(fd); + r = fd; + fd = -1; return r; } -static int ffs_address_create( - const char *path, - int *_fd) { - +static int usbffs_address_create(const char *path) { _cleanup_close_ int fd = -1; struct stat st; + int r; assert(path); - assert(_fd); fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW); if (fd < 0) @@ -1087,32 +1080,32 @@ static int ffs_address_create( if (!S_ISREG(st.st_mode)) return -EEXIST; - *_fd = fd; + r = fd; fd = -1; - return 0; + return r; } static int mq_address_create( const char *path, mode_t mq_mode, long maxmsg, - long msgsize, - int *_fd) { + long msgsize) { - int fd = -1, r = 0; + _cleanup_close_ int fd = -1; struct stat st; mode_t old_mask; struct mq_attr _attr, *attr = NULL; + int r; assert(path); - assert(_fd); if (maxmsg > 0 && msgsize > 0) { - zero(_attr); - _attr.mq_flags = O_NONBLOCK; - _attr.mq_maxmsg = maxmsg; - _attr.mq_msgsize = msgsize; + _attr = (struct mq_attr) { + .mq_flags = O_NONBLOCK, + .mq_maxmsg = maxmsg, + .mq_msgsize = msgsize, + }; attr = &_attr; } @@ -1120,33 +1113,24 @@ static int mq_address_create( old_mask = umask(~ mq_mode); /* Include the original umask in our mask */ - umask(~mq_mode | old_mask); + (void) umask(~mq_mode | old_mask); fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr); - umask(old_mask); + (void) umask(old_mask); - if (fd < 0) { - r = -errno; - goto fail; - } + if (fd < 0) + return -errno; - if (fstat(fd, &st) < 0) { - r = -errno; - goto fail; - } + if (fstat(fd, &st) < 0) + return -errno; if ((st.st_mode & 0777) != (mq_mode & ~old_mask) || st.st_uid != getuid() || - st.st_gid != getgid()) { - - r = -EEXIST; - goto fail; - } + st.st_gid != getgid()) + return -EEXIST; - *_fd = fd; - return 0; + r = fd; + fd = -1; -fail: - safe_close(fd); return r; } @@ -1166,8 +1150,7 @@ static int socket_symlink(Socket *s) { return 0; } -static int ffs_write_descs(int fd, Unit *u) { - Service *s = SERVICE(u); +static int usbffs_write_descs(int fd, Service *s) { int r; if (!s->usb_function_descriptors || !s->usb_function_strings) @@ -1175,27 +1158,25 @@ static int ffs_write_descs(int fd, Unit *u) { r = copy_file_fd(s->usb_function_descriptors, fd, false); if (r < 0) - return 0; - - r = copy_file_fd(s->usb_function_strings, fd, false); + return r; - return r; + return copy_file_fd(s->usb_function_strings, fd, false); } -static int select_ep(const struct dirent *d) { +static int usbffs_select_ep(const struct dirent *d) { return d->d_name[0] != '.' && !streq(d->d_name, "ep0"); } -static int ffs_dispatch_eps(SocketPort *p) { +static int usbffs_dispatch_eps(SocketPort *p) { _cleanup_free_ struct dirent **ent = NULL; - int r, i, n, k; _cleanup_free_ char *path = NULL; + int r, i, n, k; - r = path_get_parent(p->path, &path); - if (r < 0) - return r; + path = dirname_malloc(p->path); + if (!path) + return -ENOMEM; - r = scandir(path, &ent, select_ep, alphasort); + r = scandir(path, &ent, usbffs_select_ep, alphasort); if (r < 0) return -errno; @@ -1216,10 +1197,12 @@ static int ffs_dispatch_eps(SocketPort *p) { path_kill_slashes(ep); - r = ffs_address_create(ep, &p->auxiliary_fds[k]); + r = usbffs_address_create(ep); if (r < 0) goto fail; + p->auxiliary_fds[k] = r; + ++k; free(ent[i]); } @@ -1227,9 +1210,7 @@ static int ffs_dispatch_eps(SocketPort *p) { return r; fail: - while (k) - safe_close(p->auxiliary_fds[--k]); - + close_many(p->auxiliary_fds, k); p->auxiliary_fds = mfree(p->auxiliary_fds); p->n_auxiliary_fds = 0; @@ -1237,10 +1218,10 @@ fail: } static int socket_open_fds(Socket *s) { + _cleanup_(mac_selinux_freep) char *label = NULL; + bool know_label = false; SocketPort *p; int r; - char *label = NULL; - bool know_label = false; assert(s); @@ -1249,7 +1230,9 @@ static int socket_open_fds(Socket *s) { if (p->fd >= 0) continue; - if (p->type == SOCKET_SOCKET) { + switch (p->type) { + + case SOCKET_SOCKET: if (!know_label) { /* Figure out label, if we don't it know @@ -1300,64 +1283,72 @@ static int socket_open_fds(Socket *s) { p->fd = r; socket_apply_socket_options(s, p->fd); socket_symlink(s); + break; - } else if (p->type == SOCKET_SPECIAL) { + case SOCKET_SPECIAL: - r = special_address_create( - p->path, - &p->fd); - if (r < 0) + p->fd = special_address_create(p->path, s->writable); + if (p->fd < 0) { + r = p->fd; goto rollback; + } + break; - } else if (p->type == SOCKET_FIFO) { + case SOCKET_FIFO: - r = fifo_address_create( + p->fd = fifo_address_create( p->path, s->directory_mode, - s->socket_mode, - &p->fd); - if (r < 0) + s->socket_mode); + if (p->fd < 0) { + r = p->fd; goto rollback; + } socket_apply_fifo_options(s, p->fd); socket_symlink(s); + break; - } else if (p->type == SOCKET_MQUEUE) { + case SOCKET_MQUEUE: - r = mq_address_create( + p->fd = mq_address_create( p->path, s->socket_mode, s->mq_maxmsg, - s->mq_msgsize, - &p->fd); - if (r < 0) + s->mq_msgsize); + if (p->fd < 0) { + r = p->fd; goto rollback; - } else if (p->type == SOCKET_USB_FUNCTION) { + } + break; - r = ffs_address_create( - p->path, - &p->fd); - if (r < 0) + case SOCKET_USB_FUNCTION: + + p->fd = usbffs_address_create(p->path); + if (p->fd < 0) { + r = p->fd; goto rollback; + } - r = ffs_write_descs(p->fd, s->service.unit); + r = usbffs_write_descs(p->fd, SERVICE(UNIT_DEREF(s->service))); if (r < 0) goto rollback; - r = ffs_dispatch_eps(p); + r = usbffs_dispatch_eps(p); if (r < 0) goto rollback; - } else + + break; + + default: assert_not_reached("Unknown port type"); + } } - mac_selinux_free(label); return 0; rollback: socket_close_fds(s); - mac_selinux_free(label); - return r; } @@ -1464,7 +1455,9 @@ static int socket_coldplug(Unit *u) { if (s->deserialized_state == s->state) return 0; - if (IN_SET(s->deserialized_state, + if (s->control_pid > 0 && + pid_is_unwaited(s->control_pid) && + IN_SET(s->deserialized_state, SOCKET_START_PRE, SOCKET_START_CHOWN, SOCKET_START_POST, @@ -1475,9 +1468,6 @@ static int socket_coldplug(Unit *u) { SOCKET_FINAL_SIGTERM, SOCKET_FINAL_SIGKILL)) { - if (s->control_pid <= 0) - return -EBADMSG; - r = unit_watch_pid(UNIT(s), s->control_pid); if (r < 0) return r; @@ -1519,6 +1509,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { .apply_chroot = true, .apply_tty_stdin = true, .bus_endpoint_fd = -1, + .stdin_fd = -1, + .stdout_fd = -1, + .stderr_fd = -1, }; assert(s); @@ -2644,49 +2637,43 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use return 0; } -int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { - int *rfds; - unsigned rn_fds, k; - int i; +int socket_collect_fds(Socket *s, int **fds) { + int *rfds, k = 0, n = 0; SocketPort *p; assert(s); assert(fds); - assert(n_fds); /* Called from the service code for requesting our fds */ - rn_fds = 0; LIST_FOREACH(port, p, s->ports) { if (p->fd >= 0) - rn_fds++; - rn_fds += p->n_auxiliary_fds; + n++; + n += p->n_auxiliary_fds; } - if (rn_fds <= 0) { + if (n <= 0) { *fds = NULL; - *n_fds = 0; return 0; } - rfds = new(int, rn_fds); + rfds = new(int, n); if (!rfds) return -ENOMEM; - k = 0; LIST_FOREACH(port, p, s->ports) { + int i; + if (p->fd >= 0) rfds[k++] = p->fd; for (i = 0; i < p->n_auxiliary_fds; ++i) rfds[k++] = p->auxiliary_fds[i]; } - assert(k == rn_fds); + assert(k == n); *fds = rfds; - *n_fds = rn_fds; - - return 0; + return n; } static void socket_reset_failed(Unit *u) { @@ -2782,23 +2769,18 @@ static int socket_get_timeout(Unit *u, uint64_t *timeout) { return 1; } -static const char* const socket_state_table[_SOCKET_STATE_MAX] = { - [SOCKET_DEAD] = "dead", - [SOCKET_START_PRE] = "start-pre", - [SOCKET_START_CHOWN] = "start-chown", - [SOCKET_START_POST] = "start-post", - [SOCKET_LISTENING] = "listening", - [SOCKET_RUNNING] = "running", - [SOCKET_STOP_PRE] = "stop-pre", - [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm", - [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill", - [SOCKET_STOP_POST] = "stop-post", - [SOCKET_FINAL_SIGTERM] = "final-sigterm", - [SOCKET_FINAL_SIGKILL] = "final-sigkill", - [SOCKET_FAILED] = "failed" -}; +char *socket_fdname(Socket *s) { + assert(s); + + /* Returns the name to use for $LISTEN_NAMES. If the user + * didn't specify anything specifically, use the socket unit's + * name as fallback. */ -DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState); + if (s->fdname) + return s->fdname; + + return UNIT(s)->id; +} static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = { [SOCKET_EXEC_START_PRE] = "StartPre", diff --git a/src/core/socket.h b/src/core/socket.h index 286397b41c..94cda8a90d 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -27,24 +27,6 @@ typedef struct Socket Socket; #include "mount.h" #include "service.h" -typedef enum SocketState { - SOCKET_DEAD, - SOCKET_START_PRE, - SOCKET_START_CHOWN, - SOCKET_START_POST, - SOCKET_LISTENING, - SOCKET_RUNNING, - SOCKET_STOP_PRE, - SOCKET_STOP_PRE_SIGTERM, - SOCKET_STOP_PRE_SIGKILL, - SOCKET_STOP_POST, - SOCKET_FINAL_SIGTERM, - SOCKET_FINAL_SIGKILL, - SOCKET_FAILED, - _SOCKET_STATE_MAX, - _SOCKET_STATE_INVALID = -1 -} SocketState; - typedef enum SocketExecCommand { SOCKET_EXEC_START_PRE, SOCKET_EXEC_START_CHOWN, @@ -136,6 +118,7 @@ struct Socket { bool accept; bool remove_on_stop; + bool writable; /* Socket options */ bool keep_alive; @@ -171,20 +154,23 @@ struct Socket { char *user, *group; bool reset_cpu_usage:1; + + char *fdname; }; /* Called from the service code when collecting fds */ -int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds); +int socket_collect_fds(Socket *s, int **fds); /* Called from the service code when a per-connection service ended */ void socket_connection_unref(Socket *s); void socket_free_ports(Socket *s); -extern const UnitVTable socket_vtable; +int socket_instantiate_service(Socket *s); -const char* socket_state_to_string(SocketState i) _const_; -SocketState socket_state_from_string(const char *s) _pure_; +char *socket_fdname(Socket *s); + +extern const UnitVTable socket_vtable; const char* socket_exec_command_to_string(SocketExecCommand i) _const_; SocketExecCommand socket_exec_command_from_string(const char *s) _pure_; @@ -193,5 +179,3 @@ const char* socket_result_to_string(SocketResult i) _const_; SocketResult socket_result_from_string(const char *s) _pure_; const char* socket_port_type_to_string(SocketPort *p) _pure_; - -int socket_instantiate_service(Socket *s); diff --git a/src/core/swap.c b/src/core/swap.c index bef457069f..baaa27b6a3 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -20,22 +20,30 @@ ***/ #include <errno.h> -#include <unistd.h> #include <sys/epoll.h> #include <sys/stat.h> -#include <libudev.h> +#include <unistd.h> -#include "unit.h" -#include "swap.h" -#include "unit-name.h" +#include "libudev.h" + +#include "alloc-util.h" #include "dbus-swap.h" -#include "special.h" +#include "escape.h" #include "exit-status.h" +#include "fd-util.h" +#include "formats-util.h" +#include "fstab-util.h" +#include "parse-util.h" #include "path-util.h" -#include "virt.h" +#include "process-util.h" +#include "special.h" +#include "string-table.h" +#include "string-util.h" +#include "swap.h" #include "udev-util.h" -#include "fstab-util.h" -#include "formats-util.h" +#include "unit-name.h" +#include "unit.h" +#include "virt.h" static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = { [SWAP_DEAD] = UNIT_INACTIVE, @@ -520,16 +528,16 @@ static int swap_coldplug(Unit *u) { if (new_state == s->state) return 0; - if (new_state == SWAP_ACTIVATING || - new_state == SWAP_ACTIVATING_SIGTERM || - new_state == SWAP_ACTIVATING_SIGKILL || - new_state == SWAP_ACTIVATING_DONE || - new_state == SWAP_DEACTIVATING || - new_state == SWAP_DEACTIVATING_SIGTERM || - new_state == SWAP_DEACTIVATING_SIGKILL) { - - if (s->control_pid <= 0) - return -EBADMSG; + if (s->control_pid > 0 && + pid_is_unwaited(s->control_pid) && + IN_SET(new_state, + SWAP_ACTIVATING, + SWAP_ACTIVATING_SIGTERM, + SWAP_ACTIVATING_SIGKILL, + SWAP_ACTIVATING_DONE, + SWAP_DEACTIVATING, + SWAP_DEACTIVATING_SIGTERM, + SWAP_DEACTIVATING_SIGKILL)) { r = unit_watch_pid(UNIT(s), s->control_pid); if (r < 0) @@ -597,6 +605,9 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { .apply_chroot = true, .apply_tty_stdin = true, .bus_endpoint_fd = -1, + .stdin_fd = -1, + .stdout_fd = -1, + .stderr_fd = -1, }; assert(s); @@ -1195,7 +1206,7 @@ static Unit *swap_following(Unit *u) { if (other->from_fragment) return UNIT(other); - /* Otherwise make everybody follow the unit that's named after + /* Otherwise, make everybody follow the unit that's named after * the swap device in the kernel */ if (streq_ptr(s->what, s->devnode)) @@ -1398,21 +1409,6 @@ static bool swap_supported(void) { return supported; } -static const char* const swap_state_table[_SWAP_STATE_MAX] = { - [SWAP_DEAD] = "dead", - [SWAP_ACTIVATING] = "activating", - [SWAP_ACTIVATING_DONE] = "activating-done", - [SWAP_ACTIVE] = "active", - [SWAP_DEACTIVATING] = "deactivating", - [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm", - [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill", - [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm", - [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill", - [SWAP_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState); - static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = { [SWAP_EXEC_ACTIVATE] = "ExecActivate", [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate", diff --git a/src/core/swap.h b/src/core/swap.h index 9136b9abab..303b926568 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -22,26 +22,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <libudev.h> +#include "libudev.h" typedef struct Swap Swap; - -typedef enum SwapState { - SWAP_DEAD, - SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */ - SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */ - SWAP_ACTIVE, - SWAP_DEACTIVATING, - SWAP_ACTIVATING_SIGTERM, - SWAP_ACTIVATING_SIGKILL, - SWAP_DEACTIVATING_SIGTERM, - SWAP_DEACTIVATING_SIGKILL, - SWAP_FAILED, - _SWAP_STATE_MAX, - _SWAP_STATE_INVALID = -1 -} SwapState; - typedef enum SwapExecCommand { SWAP_EXEC_ACTIVATE, SWAP_EXEC_DEACTIVATE, @@ -120,9 +104,6 @@ extern const UnitVTable swap_vtable; int swap_process_device_new(Manager *m, struct udev_device *dev); int swap_process_device_remove(Manager *m, struct udev_device *dev); -const char* swap_state_to_string(SwapState i) _const_; -SwapState swap_state_from_string(const char *s) _pure_; - const char* swap_exec_command_to_string(SwapExecCommand i) _const_; SwapExecCommand swap_exec_command_from_string(const char *s) _pure_; diff --git a/src/core/system.conf b/src/core/system.conf index 231609033b..50668e12c4 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -17,9 +17,10 @@ #LogColor=yes #LogLocation=no #DumpCore=yes -#CrashShell=no #ShowStatus=yes -#CrashChVT=1 +#CrashChangeVT=no +#CrashShell=no +#CrashReboot=no #CPUAffinity=1 2 #JoinControllers=cpu,cpuacct net_cls,net_prio #RuntimeWatchdogSec=0 @@ -39,6 +40,7 @@ #DefaultCPUAccounting=no #DefaultBlockIOAccounting=no #DefaultMemoryAccounting=no +#DefaultTasksAccounting=no #DefaultLimitCPU= #DefaultLimitFSIZE= #DefaultLimitDATA= diff --git a/src/core/target.c b/src/core/target.c index f714cb31c2..c3e79fffc8 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -19,13 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "unit.h" -#include "target.h" -#include "log.h" #include "dbus-target.h" +#include "log.h" #include "special.h" +#include "string-util.h" #include "unit-name.h" +#include "unit.h" +#include "target.h" static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = { [TARGET_DEAD] = UNIT_INACTIVE, @@ -192,13 +192,6 @@ _pure_ static const char *target_sub_state_to_string(Unit *u) { return target_state_to_string(TARGET(u)->state); } -static const char* const target_state_table[_TARGET_STATE_MAX] = { - [TARGET_DEAD] = "dead", - [TARGET_ACTIVE] = "active" -}; - -DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState); - const UnitVTable target_vtable = { .object_size = sizeof(Target), diff --git a/src/core/target.h b/src/core/target.h index 0a25ef469a..3cc6c07bfa 100644 --- a/src/core/target.h +++ b/src/core/target.h @@ -23,14 +23,6 @@ typedef struct Target Target; - -typedef enum TargetState { - TARGET_DEAD, - TARGET_ACTIVE, - _TARGET_STATE_MAX, - _TARGET_STATE_INVALID = -1 -} TargetState; - struct Target { Unit meta; @@ -38,6 +30,3 @@ struct Target { }; extern const UnitVTable target_vtable; - -const char* target_state_to_string(TargetState i) _const_; -TargetState target_state_from_string(const char *s) _pure_; diff --git a/src/core/timer.c b/src/core/timer.c index eb6567bbfa..c9dc97d4fb 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -21,13 +21,20 @@ #include <errno.h> -#include "unit.h" -#include "unit-name.h" -#include "timer.h" +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" #include "dbus-timer.h" +#include "fs-util.h" +#include "parse-util.h" #include "special.h" -#include "bus-util.h" -#include "bus-error.h" +#include "string-table.h" +#include "string-util.h" +#include "timer.h" +#include "unit-name.h" +#include "unit.h" +#include "user-util.h" +#include "virt.h" static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = { [TIMER_DEAD] = UNIT_INACTIVE, @@ -353,10 +360,14 @@ static void timer_enter_waiting(Timer *t, bool initial) { break; case TIMER_BOOT: - /* CLOCK_MONOTONIC equals the uptime on Linux */ - base = 0; - break; - + if (detect_container() <= 0) { + /* CLOCK_MONOTONIC equals the uptime on Linux */ + base = 0; + break; + } + /* In a container we don't want to include the time the host + * was already up when the container started, so count from + * our own startup. Fall through. */ case TIMER_STARTUP: base = UNIT(t)->manager->userspace_timestamp.monotonic; break; @@ -713,16 +724,6 @@ static void timer_time_change(Unit *u) { timer_enter_waiting(t, false); } -static const char* const timer_state_table[_TIMER_STATE_MAX] = { - [TIMER_DEAD] = "dead", - [TIMER_WAITING] = "waiting", - [TIMER_RUNNING] = "running", - [TIMER_ELAPSED] = "elapsed", - [TIMER_FAILED] = "failed" -}; - -DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState); - static const char* const timer_base_table[_TIMER_BASE_MAX] = { [TIMER_ACTIVE] = "OnActiveSec", [TIMER_BOOT] = "OnBootSec", diff --git a/src/core/timer.h b/src/core/timer.h index 9d919e4d3e..ac5af6a93c 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -25,16 +25,6 @@ typedef struct Timer Timer; #include "calendarspec.h" -typedef enum TimerState { - TIMER_DEAD, - TIMER_WAITING, - TIMER_RUNNING, - TIMER_ELAPSED, - TIMER_FAILED, - _TIMER_STATE_MAX, - _TIMER_STATE_INVALID = -1 -} TimerState; - typedef enum TimerBase { TIMER_ACTIVE, TIMER_BOOT, @@ -91,9 +81,6 @@ void timer_free_values(Timer *t); extern const UnitVTable timer_vtable; -const char *timer_state_to_string(TimerState i) _const_; -TimerState timer_state_from_string(const char *s) _pure_; - const char *timer_base_to_string(TimerBase i) _const_; TimerBase timer_base_from_string(const char *s) _pure_; diff --git a/src/core/transaction.c b/src/core/transaction.c index d1c1b9a3cd..69f28c902f 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -22,10 +22,11 @@ #include <unistd.h> #include <fcntl.h> +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-error.h" -#include "transaction.h" #include "terminal-util.h" +#include "transaction.h" static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); diff --git a/src/core/umount.c b/src/core/umount.c index 22dbe67259..9d1f7660db 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -21,23 +21,30 @@ #include <errno.h> #include <fcntl.h> +#include <linux/dm-ioctl.h> +#include <linux/loop.h> #include <string.h> #include <sys/mount.h> #include <sys/swap.h> -#include <linux/loop.h> -#include <linux/dm-ioctl.h> +#include "libudev.h" + +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fstab-util.h" #include "list.h" #include "mount-setup.h" -#include "umount.h" #include "path-util.h" +#include "string-util.h" +#include "udev-util.h" +#include "umount.h" #include "util.h" #include "virt.h" -#include "libudev.h" -#include "udev-util.h" typedef struct MountPoint { char *path; + char *options; dev_t devnum; LIST_FIELDS(struct MountPoint, mount_point); } MountPoint; @@ -71,7 +78,7 @@ static int mount_points_list_get(MountPoint **head) { return -errno; for (i = 1;; i++) { - _cleanup_free_ char *path = NULL; + _cleanup_free_ char *path = NULL, *options = NULL; char *p = NULL; MountPoint *m; int k; @@ -82,15 +89,15 @@ static int mount_points_list_get(MountPoint **head) { "%*s " /* (3) major:minor */ "%*s " /* (4) root */ "%ms " /* (5) mount point */ - "%*s" /* (6) mount options */ + "%*s" /* (6) mount flags */ "%*[^-]" /* (7) optional fields */ "- " /* (8) separator */ "%*s " /* (9) file system type */ "%*s" /* (10) mount source */ - "%*s" /* (11) mount options 2 */ + "%ms" /* (11) mount options */ "%*[^\n]", /* some rubbish at the end */ - &path); - if (k != 1) { + &path, &options); + if (k != 2) { if (k == EOF) break; @@ -125,6 +132,9 @@ static int mount_points_list_get(MountPoint **head) { } m->path = p; + m->options = options; + options = NULL; + LIST_PREPEND(mount_point, *head, m); } @@ -369,6 +379,14 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e benefits, but might confuse the host, as we remount the superblock here, not the bind mound. */ if (detect_container() <= 0) { + _cleanup_free_ char *options = NULL; + /* MS_REMOUNT requires that the data parameter + * should be the same from the original mount + * except for the desired changes. Since we want + * to remount read-only, we should filter out + * rw (and ro too, because it confuses the kernel) */ + (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options); + /* We always try to remount directories * read-only first, before we go on and umount * them. @@ -385,7 +403,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e * alias read-only we hence should be * relatively safe regarding keeping the fs we * can otherwise not see dirty. */ - (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL); + log_info("Remounting '%s' read-only with options '%s'.", m->path, options); + (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options); } /* Skip / and /usr since we cannot unmount that diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 0889769d03..721c8ccce9 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -19,14 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" +#include "alloc-util.h" +#include "cgroup-util.h" +#include "formats-util.h" +#include "macro.h" #include "specifier.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" #include "unit-printf.h" -#include "macro.h" -#include "cgroup-util.h" -#include "formats-util.h" +#include "unit.h" +#include "user-util.h" static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { Unit *u = userdata; @@ -63,10 +66,7 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda assert(u); - if (!u->instance) - return -EINVAL; - - return unit_name_unescape(u->instance, ret); + return unit_name_unescape(strempty(u->instance), ret); } static int specifier_filename(char specifier, void *data, void *userdata, char **ret) { @@ -128,6 +128,8 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch n = unit_default_cgroup_path(slice); } else n = strdup(u->manager->cgroup_root); + if (!n) + return -ENOMEM; *ret = n; return 0; @@ -166,7 +168,7 @@ static int specifier_user_name(char specifier, void *data, void *userdata, char c = unit_get_exec_context(u); if (!c) - return -EINVAL; + return -EOPNOTSUPP; if (u->manager->running_as == MANAGER_SYSTEM) { diff --git a/src/core/unit.c b/src/core/unit.c index 3a6313e4a2..6c130d4cd1 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -20,36 +20,43 @@ ***/ #include <errno.h> -#include <string.h> #include <stdlib.h> -#include <unistd.h> +#include <string.h> #include <sys/stat.h> +#include <unistd.h> #include "sd-id128.h" #include "sd-messages.h" -#include "set.h" -#include "macro.h" -#include "strv.h" -#include "path-util.h" -#include "log.h" + +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "bus-util.h" #include "cgroup-util.h" -#include "missing.h" -#include "mkdir.h" +#include "dbus-unit.h" +#include "dbus.h" +#include "dropin.h" +#include "escape.h" +#include "execute.h" #include "fileio-label.h" #include "formats-util.h" +#include "load-dropin.h" +#include "load-fragment.h" +#include "log.h" +#include "macro.h" +#include "missing.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" -#include "virt.h" -#include "bus-common-errors.h" -#include "bus-util.h" -#include "dropin.h" -#include "unit-name.h" +#include "set.h" #include "special.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" #include "unit.h" -#include "load-fragment.h" -#include "load-dropin.h" -#include "dbus.h" -#include "dbus-unit.h" -#include "execute.h" +#include "user-util.h" +#include "virt.h" const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { [UNIT_SERVICE] = &service_vtable, @@ -412,12 +419,11 @@ static void unit_remove_transient(Unit *u) { STRV_FOREACH(i, u->dropin_paths) { _cleanup_free_ char *p = NULL; - int r; (void) unlink(*i); - r = path_get_parent(*i, &p); - if (r >= 0) + p = dirname_malloc(*i); + if (p) (void) rmdir(p); } } @@ -1129,12 +1135,12 @@ static int unit_add_slice_dependencies(Unit *u) { return 0; if (UNIT_ISSET(u->slice)) - return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true); + return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true); - if (streq(u->id, SPECIAL_ROOT_SLICE)) + if (unit_has_name(u, SPECIAL_ROOT_SLICE)) return 0; - return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true); + return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_ROOT_SLICE, NULL, true); } static int unit_add_mount_dependencies(Unit *u) { @@ -1147,13 +1153,23 @@ static int unit_add_mount_dependencies(Unit *u) { char prefix[strlen(*i) + 1]; PATH_FOREACH_PREFIX_MORE(prefix, *i) { + _cleanup_free_ char *p = NULL; Unit *m; - r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m); + r = unit_name_from_path(prefix, ".mount", &p); if (r < 0) return r; - if (r == 0) + + m = manager_get_unit(u->manager, p); + if (!m) { + /* Make sure to load the mount unit if + * it exists. If so the dependencies + * on this unit will be added later + * during the loading of the mount + * unit. */ + (void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m); continue; + } if (m == u) continue; @@ -2310,47 +2326,9 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency return unit_add_two_dependencies(u, d, e, other, add_reference); } -int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) { - _cleanup_free_ char *buf = NULL; - Unit *other; - int r; - - assert(u); - assert(name || path); - - r = resolve_template(u, name, path, &buf, &name); - if (r < 0) - return r; - - r = manager_load_unit(u->manager, name, path, NULL, &other); - if (r < 0) - return r; - - return unit_add_dependency(other, d, u, add_reference); -} - -int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) { - _cleanup_free_ char *buf = NULL; - Unit *other; - int r; - - assert(u); - assert(name || path); - - r = resolve_template(u, name, path, &buf, &name); - if (r < 0) - return r; - - r = manager_load_unit(u->manager, name, path, NULL, &other); - if (r < 0) - return r; - - return unit_add_two_dependencies(other, d, e, u, add_reference); -} - int set_unit_path(const char *p) { /* This is mostly for debug purposes */ - if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0) + if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 0) return -errno; return 0; @@ -2498,26 +2476,23 @@ static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd return 0; } -int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) { - _cleanup_free_ char *match = NULL; - Manager *m = u->manager; +int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) { + const char *match; - assert(m); + assert(u); + assert(bus); + assert(name); if (u->match_bus_slot) return -EBUSY; - match = strjoin("type='signal'," + match = strjoina("type='signal'," "sender='org.freedesktop.DBus'," "path='/org/freedesktop/DBus'," "interface='org.freedesktop.DBus'," "member='NameOwnerChanged'," - "arg0='", - name, - "'", + "arg0='", name, "'", NULL); - if (!match) - return -ENOMEM; return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u); } @@ -2534,9 +2509,9 @@ int unit_watch_bus_name(Unit *u, const char *name) { if (u->manager->api_bus) { /* If the bus is already available, install the match directly. * Otherwise, just put the name in the list. bus_setup_api() will take care later. */ - r = unit_install_bus_match(u->manager->api_bus, u, name); + r = unit_install_bus_match(u, u->manager->api_bus, name); if (r < 0) - return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m"); + return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name); } r = hashmap_put(u->manager->watch_bus, name, u); @@ -2624,6 +2599,62 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { return 0; } +int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { + assert(u); + assert(f); + assert(key); + + if (!value) + return 0; + + fputs(key, f); + fputc('=', f); + fputs(value, f); + fputc('\n', f); + + return 1; +} + +int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) { + _cleanup_free_ char *c = NULL; + + assert(u); + assert(f); + assert(key); + + if (!value) + return 0; + + c = cescape(value); + if (!c) + return -ENOMEM; + + fputs(key, f); + fputc('=', f); + fputs(c, f); + fputc('\n', f); + + return 1; +} + +int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) { + int copy; + + assert(u); + assert(f); + assert(key); + + if (fd < 0) + return 0; + + copy = fdset_put_dup(fds, fd); + if (copy < 0) + return copy; + + fprintf(f, "%s=%i\n", key, copy); + return 1; +} + void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) { va_list ap; @@ -2642,15 +2673,6 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f fputc('\n', f); } -void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) { - assert(u); - assert(f); - assert(key); - assert(value); - - fprintf(f, "%s=%s\n", key, value); -} - int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { ExecRuntime **rt = NULL; size_t offset; @@ -3311,19 +3333,6 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, return 0; } -static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) { - _cleanup_free_ char *dir = NULL; - int r; - - assert(u); - - r = unit_drop_in_dir(u, mode, u->transient, &dir); - if (r < 0) - return r; - - return drop_in_file(dir, u->id, 50, name, p, q); -} - int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) { _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL; @@ -3422,28 +3431,6 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const return unit_write_drop_in_private(u, mode, name, p); } -int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) { - _cleanup_free_ char *p = NULL, *q = NULL; - int r; - - assert(u); - - if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME)) - return 0; - - r = unit_drop_in_file(u, mode, name, &p, &q); - if (r < 0) - return r; - - if (unlink(q) < 0) - r = errno == ENOENT ? 0 : -errno; - else - r = 1; - - rmdir(p); - return r; -} - int unit_make_transient(Unit *u) { assert(u); @@ -3729,14 +3716,3 @@ int unit_fail_if_symlink(Unit *u, const char* where) { return -ELOOP; } - -static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = { - [UNIT_ACTIVE] = "active", - [UNIT_RELOADING] = "reloading", - [UNIT_INACTIVE] = "inactive", - [UNIT_FAILED] = "failed", - [UNIT_ACTIVATING] = "activating", - [UNIT_DEACTIVATING] = "deactivating" -}; - -DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState); diff --git a/src/core/unit.h b/src/core/unit.h index c868d75c79..6f775c5ce1 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -27,7 +27,6 @@ typedef struct Unit Unit; typedef struct UnitVTable UnitVTable; -typedef enum UnitActiveState UnitActiveState; typedef struct UnitRef UnitRef; typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; @@ -37,17 +36,6 @@ typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; #include "unit-name.h" #include "failure-action.h" -enum UnitActiveState { - UNIT_ACTIVE, - UNIT_RELOADING, - UNIT_INACTIVE, - UNIT_FAILED, - UNIT_ACTIVATING, - UNIT_DEACTIVATING, - _UNIT_ACTIVE_STATE_MAX, - _UNIT_ACTIVE_STATE_INVALID = -1 -}; - typedef enum KillOperation { KILL_TERMINATE, KILL_KILL, @@ -476,9 +464,6 @@ int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); -int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference); -int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference); - int unit_add_exec_dependencies(Unit *u, ExecContext *c); int unit_choose_id(Unit *u, const char *name); @@ -532,7 +517,7 @@ void unit_unwatch_all_pids(Unit *u); void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2); -int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name); +int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name); int unit_watch_bus_name(Unit *u, const char *name); void unit_unwatch_bus_name(Unit *u, const char *name); @@ -545,11 +530,15 @@ char *unit_dbus_path(Unit *u); int unit_load_related_unit(Unit *u, const char *type, Unit **_found); bool unit_can_serialize(Unit *u) _pure_; + int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); -void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); -void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); int unit_deserialize(Unit *u, FILE *f, FDSet *fds); +int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value); +int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value); +int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd); +void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); + int unit_add_node_link(Unit *u, const char *what, bool wants); int unit_coldplug(Unit *u); @@ -600,8 +589,6 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data); int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5); -int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name); - int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien); int unit_make_transient(Unit *u); @@ -617,9 +604,6 @@ static inline bool unit_supported(Unit *u) { void unit_warn_if_dir_nonempty(Unit *u, const char* where); int unit_fail_if_symlink(Unit *u, const char* where); -const char *unit_active_state_to_string(UnitActiveState i) _const_; -UnitActiveState unit_active_state_from_string(const char *s) _pure_; - /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full(unit, level, error, ...) \ diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index ab91afec4d..ae53bac600 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -21,13 +21,19 @@ #include <errno.h> +#include "alloc-util.h" #include "dropin.h" +#include "fd-util.h" +#include "fileio.h" +#include "fstab-util.h" #include "generator.h" #include "hashmap.h" #include "log.h" #include "mkdir.h" +#include "parse-util.h" #include "path-util.h" -#include "fstab-util.h" +#include "proc-cmdline.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" #include "util.h" diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 5d5872b7f4..98fe52a81b 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -19,21 +19,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> -#include <sys/mman.h> +#include <libcryptsetup.h> #include <mntent.h> +#include <string.h> +#include <sys/mman.h> -#include <libcryptsetup.h> +#include "sd-device.h" +#include "alloc-util.h" +#include "ask-password-api.h" +#include "device-util.h" +#include "escape.h" #include "fileio.h" #include "log.h" -#include "util.h" +#include "mount-util.h" +#include "parse-util.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" -#include "ask-password-api.h" -#include "sd-device.h" -#include "device-util.h" +#include "util.h" static const char *arg_type = NULL; /* CRYPT_LUKS1, CRYPT_TCRYPT or CRYPT_PLAIN */ static char *arg_cipher = NULL; @@ -312,19 +317,16 @@ static char *disk_mount_point(const char *label) { return NULL; } -static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***passwords) { - int r = 0; - char **p; - _cleanup_free_ char *text = NULL; - _cleanup_free_ char *escaped_name = NULL; - char *id; +static int get_password(const char *vol, const char *src, usec_t until, bool accept_cached, char ***ret) { + _cleanup_free_ char *description = NULL, *name_buffer = NULL, *mount_point = NULL, *maj_min = NULL, *text = NULL, *escaped_name = NULL; + _cleanup_strv_free_erase_ char **passwords = NULL; const char *name = NULL; - _cleanup_free_ char *description = NULL, *name_buffer = NULL, - *mount_point = NULL, *maj_min = NULL; + char **p, *id; + int r = 0; assert(vol); assert(src); - assert(passwords); + assert(ret); description = disk_description(src); mount_point = disk_mount_point(vol); @@ -364,42 +366,45 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc id = strjoina("cryptsetup:", escaped_name); - r = ask_password_auto(text, "drive-harddisk", id, until, accept_cached, passwords); + r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, + ASK_PASSWORD_PUSH_CACHE | (accept_cached*ASK_PASSWORD_ACCEPT_CACHED), + &passwords); if (r < 0) return log_error_errno(r, "Failed to query password: %m"); if (arg_verify) { - _cleanup_strv_free_ char **passwords2 = NULL; + _cleanup_strv_free_erase_ char **passwords2 = NULL; - assert(strv_length(*passwords) == 1); + assert(strv_length(passwords) == 1); if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) return log_oom(); id = strjoina("cryptsetup-verification:", escaped_name); - r = ask_password_auto(text, "drive-harddisk", id, until, false, &passwords2); + r = ask_password_auto(text, "drive-harddisk", id, "cryptsetup", until, ASK_PASSWORD_PUSH_CACHE, &passwords2); if (r < 0) return log_error_errno(r, "Failed to query verification password: %m"); assert(strv_length(passwords2) == 1); - if (!streq(*passwords[0], passwords2[0])) { + if (!streq(passwords[0], passwords2[0])) { log_warning("Passwords did not match, retrying."); return -EAGAIN; } } - strv_uniq(*passwords); + strv_uniq(passwords); - STRV_FOREACH(p, *passwords) { + STRV_FOREACH(p, passwords) { char *c; if (strlen(*p)+1 >= arg_key_size) continue; /* Pad password if necessary */ - if (!(c = new(char, arg_key_size))) + c = new(char, arg_key_size); + if (!c) return log_oom(); strncpy(c, *p, arg_key_size); @@ -407,14 +412,19 @@ static int get_password(const char *vol, const char *src, usec_t until, bool acc *p = c; } + *ret = passwords; + passwords = NULL; + return 0; } -static int attach_tcrypt(struct crypt_device *cd, - const char *name, - const char *key_file, - char **passwords, - uint32_t flags) { +static int attach_tcrypt( + struct crypt_device *cd, + const char *name, + const char *key_file, + char **passwords, + uint32_t flags) { + int r = 0; _cleanup_free_ char *passphrase = NULL; struct crypt_params_tcrypt params = { @@ -524,8 +534,7 @@ static int attach_luks_or_plain(struct crypt_device *cd, * it just configures encryption * parameters when used for plain * mode. */ - r = crypt_format(cd, CRYPT_PLAIN, cipher, cipher_mode, - NULL, NULL, arg_keyfile_size, ¶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); @@ -541,9 +550,7 @@ static int attach_luks_or_plain(struct crypt_device *cd, crypt_get_device_name(cd)); if (key_file) { - r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, - key_file, arg_keyfile_size, - arg_keyfile_offset, flags); + r = crypt_activate_by_keyfile_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags); if (r < 0) { log_error_errno(r, "Failed to activate with key file '%s': %m", key_file); return -EAGAIN; @@ -635,7 +642,6 @@ int main(int argc, char *argv[]) { k = crypt_init(&cd, arg_header); } else k = crypt_init(&cd, argv[3]); - if (k) { log_error_errno(k, "crypt_init() failed: %m"); goto finish; @@ -673,7 +679,7 @@ int main(int argc, char *argv[]) { } for (tries = 0; arg_tries == 0 || tries < arg_tries; tries++) { - _cleanup_strv_free_ char **passwords = NULL; + _cleanup_strv_free_erase_ char **passwords = NULL; if (!key_file) { k = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords); diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c index 7bbec5467e..6861a592fe 100644 --- a/src/dbus1-generator/dbus1-generator.c +++ b/src/dbus1-generator/dbus1-generator.c @@ -19,14 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" +#include "bus-internal.h" +#include "bus-util.h" +#include "cgroup-util.h" #include "conf-parser.h" -#include "special.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" #include "mkdir.h" -#include "bus-util.h" -#include "bus-internal.h" +#include "special.h" #include "unit-name.h" -#include "cgroup-util.h" +#include "util.h" static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp"; @@ -223,8 +227,7 @@ static int parse_dbus_fragments(const char *path, const char *type) { if (errno == -ENOENT) return 0; - log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m"); - return -errno; + return log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m"); } r = 0; @@ -242,8 +245,7 @@ static int parse_dbus_fragments(const char *path, const char *type) { return r; fail: - log_error_errno(errno, "Failed to read D-Bus services directory: %m"); - return -errno; + return log_error_errno(errno, "Failed to read D-Bus services directory: %m"); } static int link_busnames_target(const char *units) { diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c index 8b29e8fd09..413cfd0388 100644 --- a/src/debug-generator/debug-generator.c +++ b/src/debug-generator/debug-generator.c @@ -19,11 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" -#include "mkdir.h" +#include "util.h" +static char *arg_default_unit = NULL; static const char *arg_dest = "/tmp"; static char **arg_mask = NULL; static char **arg_wants = NULL; @@ -76,6 +82,24 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { arg_debug_shell = r; } else arg_debug_shell = true; + } else if (streq(key, "systemd.unit")) { + + if (!value) + log_error("Missing argument for systemd.unit= kernel command line parameter."); + else { + r = free_and_strdup(&arg_default_unit, value); + if (r < 0) + return log_error_errno(r, "Failed to set default unit %s: %m", value); + } + } else if (!value) { + const char *target; + + target = runlevel_to_target(key); + if (target) { + r = free_and_strdup(&arg_default_unit, target); + if (r < 0) + return log_error_errno(r, "Failed to set default unit %s: %m", target); + } } return 0; @@ -114,7 +138,7 @@ static int generate_wants_symlinks(void) { STRV_FOREACH(u, arg_wants) { _cleanup_free_ char *p = NULL, *f = NULL; - p = strjoin(arg_dest, "/default.target.wants/", *u, NULL); + p = strjoin(arg_dest, "/", arg_default_unit, ".wants/", *u, NULL); if (!p) return log_oom(); @@ -150,6 +174,12 @@ int main(int argc, char *argv[]) { umask(0022); + r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); + if (r < 0) { + log_error_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET); + goto finish; + } + r = parse_proc_cmdline(parse_proc_cmdline_item); if (r < 0) log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); diff --git a/src/delta/delta.c b/src/delta/delta.c index 990130d00b..8bf678c28f 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -21,21 +21,28 @@ ***/ #include <errno.h> -#include <string.h> -#include <unistd.h> #include <getopt.h> +#include <string.h> #include <sys/prctl.h> +#include <unistd.h> +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "hashmap.h" -#include "util.h" -#include "path-util.h" +#include "locale-util.h" #include "log.h" #include "pager.h" -#include "build.h" -#include "strv.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" -#include "terminal-util.h" #include "signal-util.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "terminal-util.h" +#include "util.h" static const char prefixes[] = "/etc\0" @@ -312,8 +319,7 @@ static int enumerate_dir(Hashmap *top, Hashmap *bottom, Hashmap *drops, const ch if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open %s: %m", path); - return -errno; + return log_error_errno(errno, "Failed to open %s: %m", path); } for (;;) { @@ -544,9 +550,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c index 97ae569ca5..0a256c29be 100644 --- a/src/detect-virt/detect-virt.c +++ b/src/detect-virt/detect-virt.c @@ -19,20 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stdbool.h> #include <errno.h> #include <getopt.h> +#include <stdbool.h> +#include <stdlib.h> #include "util.h" #include "virt.h" -#include "build.h" static bool arg_quiet = false; static enum { ANY_VIRTUALIZATION, ONLY_VM, - ONLY_CONTAINER + ONLY_CONTAINER, + ONLY_CHROOT, } arg_mode = ANY_VIRTUALIZATION; static void help(void) { @@ -42,6 +42,7 @@ static void help(void) { " --version Show package version\n" " -c --container Only detect whether we are run in a container\n" " -v --vm Only detect whether we are run in a VM\n" + " -r --chroot Detect whether we are run in a chroot() environment\n" " -q --quiet Don't output anything, just set return value\n" , program_invocation_short_name); } @@ -56,7 +57,8 @@ static int parse_argv(int argc, char *argv[]) { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "container", no_argument, NULL, 'c' }, - { "vm", optional_argument, NULL, 'v' }, + { "vm", no_argument, NULL, 'v' }, + { "chroot", no_argument, NULL, 'r' }, { "quiet", no_argument, NULL, 'q' }, {} }; @@ -66,7 +68,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hqcvr", options, NULL)) >= 0) switch (c) { @@ -75,9 +77,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'q': arg_quiet = true; @@ -91,6 +91,10 @@ static int parse_argv(int argc, char *argv[]) { arg_mode = ONLY_VM; break; + case 'r': + arg_mode = ONLY_CHROOT; + break; + case '?': return -EINVAL; @@ -99,8 +103,7 @@ static int parse_argv(int argc, char *argv[]) { } if (optind < argc) { - log_error("%s takes no arguments.", - program_invocation_short_name); + log_error("%s takes no arguments.", program_invocation_short_name); return -EINVAL; } @@ -108,7 +111,7 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char *argv[]) { - int retval = EXIT_SUCCESS, r; + int r; /* This is mostly intended to be used for scripts which want * to detect whether we are being run in a virtualized @@ -126,7 +129,7 @@ int main(int argc, char *argv[]) { case ONLY_VM: r = detect_vm(); if (r < 0) { - log_error_errno(r, "Failed to check for vm: %m"); + log_error_errno(r, "Failed to check for VM: %m"); return EXIT_FAILURE; } @@ -141,6 +144,15 @@ int main(int argc, char *argv[]) { break; + case ONLY_CHROOT: + r = running_in_chroot(); + if (r < 0) { + log_error_errno(r, "Failed to check for chroot() environment: %m"); + return EXIT_FAILURE; + } + + return r ? EXIT_SUCCESS : EXIT_FAILURE; + case ANY_VIRTUALIZATION: default: r = detect_virtualization(); @@ -155,7 +167,5 @@ int main(int argc, char *argv[]) { if (!arg_quiet) puts(virtualization_to_string(r)); - retval = r != VIRTUALIZATION_NONE ? EXIT_SUCCESS : EXIT_FAILURE; - - return retval; + return r != VIRTUALIZATION_NONE ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/escape/escape.c b/src/escape/escape.c index 341453398d..e857affbc4 100644 --- a/src/escape/escape.c +++ b/src/escape/escape.c @@ -19,14 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <getopt.h> #include <stdio.h> #include <stdlib.h> -#include <getopt.h> +#include "alloc-util.h" #include "log.h" -#include "unit-name.h" -#include "build.h" +#include "string-util.h" #include "strv.h" +#include "unit-name.h" static enum { ACTION_ESCAPE, @@ -83,9 +84,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_SUFFIX: diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index e2a1c00a75..642d36912c 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -19,24 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - #include <fcntl.h> -#include <unistd.h> #include <getopt.h> #include <shadow.h> +#include <unistd.h> -#include "strv.h" -#include "fileio.h" +#include "alloc-util.h" +#include "ask-password-api.h" #include "copy.h" -#include "build.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" +#include "locale-util.h" #include "mkdir.h" -#include "time-util.h" +#include "parse-util.h" #include "path-util.h" #include "random-util.h" -#include "locale-util.h" -#include "ask-password-api.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" -#include "hostname-util.h" +#include "time-util.h" +#include "umask-util.h" +#include "user-util.h" static char *arg_root = NULL; static char *arg_locale = NULL; /* $LANG */ @@ -53,15 +58,6 @@ static bool arg_copy_locale = false; static bool arg_copy_timezone = false; static bool arg_copy_root_password = false; -static void clear_string(char *x) { - - if (!x) - return; - - /* A delicious drop of snake-oil! */ - memset(x, 'x', strlen(x)); -} - static bool press_any_key(void) { char k = 0; bool need_nl = true; @@ -466,9 +462,9 @@ static int prompt_root_password(void) { msg2 = strjoina(draw_special_char(DRAW_TRIANGULAR_BULLET), " Please enter new root password again: "); for (;;) { - _cleanup_free_ char *a = NULL, *b = NULL; + _cleanup_string_free_erase_ char *a = NULL, *b = NULL; - r = ask_password_tty(msg1, 0, false, NULL, &a); + r = ask_password_tty(msg1, NULL, 0, 0, NULL, &a); if (r < 0) return log_error_errno(r, "Failed to query root password: %m"); @@ -477,21 +473,15 @@ static int prompt_root_password(void) { break; } - r = ask_password_tty(msg2, 0, false, NULL, &b); - if (r < 0) { - log_error_errno(r, "Failed to query root password: %m"); - clear_string(a); - return r; - } + r = ask_password_tty(msg2, NULL, 0, 0, NULL, &b); + if (r < 0) + return log_error_errno(r, "Failed to query root password: %m"); if (!streq(a, b)) { log_error("Entered passwords did not match, please try again."); - clear_string(a); - clear_string(b); continue; } - clear_string(b); arg_root_password = a; a = NULL; break; @@ -550,7 +540,7 @@ static int process_root_password(void) { mkdir_parents(etc_shadow, 0755); - lock = take_password_lock(arg_root); + lock = take_etc_passwd_lock(arg_root); if (lock < 0) return lock; @@ -564,8 +554,7 @@ static int process_root_password(void) { if (!errno) errno = EIO; - log_error_errno(errno, "Failed to find shadow entry for root: %m"); - return -errno; + return log_error_errno(errno, "Failed to find shadow entry for root: %m"); } r = write_root_shadow(etc_shadow, p); @@ -600,10 +589,9 @@ static int process_root_password(void) { item.sp_pwdp = crypt(arg_root_password, salt); if (!item.sp_pwdp) { if (!errno) - errno = -EINVAL; + errno = EINVAL; - log_error_errno(errno, "Failed to encrypt password: %m"); - return -errno; + return log_error_errno(errno, "Failed to encrypt password: %m"); } item.sp_lstchg = (long) (now(CLOCK_REALTIME) / USEC_PER_DAY); @@ -704,21 +692,12 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_ROOT: - free(arg_root); - arg_root = path_make_absolute_cwd(optarg); - if (!arg_root) - return log_oom(); - - path_kill_slashes(arg_root); - - if (path_equal(arg_root, "/")) - arg_root = mfree(arg_root); - + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case ARG_LOCALE: @@ -886,7 +865,7 @@ finish: free(arg_locale_messages); free(arg_timezone); free(arg_hostname); - clear_string(arg_root_password); + string_erase(arg_root_password); free(arg_root_password); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index bd3051f30d..5b806a1e69 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -32,16 +32,22 @@ #include "sd-bus.h" #include "sd-device.h" -#include "util.h" -#include "process-util.h" -#include "signal-util.h" -#include "special.h" -#include "bus-util.h" -#include "bus-error.h" +#include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-error.h" +#include "bus-util.h" #include "device-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "parse-util.h" #include "path-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "signal-util.h" #include "socket-util.h" +#include "special.h" +#include "stdio-util.h" +#include "util.h" /* exit codes as defined in fsck(8) */ enum { @@ -60,14 +66,14 @@ static bool arg_force = false; static bool arg_show_progress = false; static const char *arg_repair = "-a"; -static void start_target(const char *target) { +static void start_target(const char *target, const char *mode) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; assert(target); - r = bus_open_system_systemd(&bus); + r = bus_connect_system_systemd(&bus); if (r < 0) { log_error_errno(r, "Failed to get D-Bus connection: %m"); return; @@ -83,7 +89,7 @@ static void start_target(const char *target) { "StartUnitReplace", &error, NULL, - "sss", "basic.target", target, "replace"); + "sss", "basic.target", target, mode); /* Don't print a warning if we aren't called during startup */ if (r < 0 && !sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_JOB)) @@ -366,12 +372,12 @@ int main(int argc, char *argv[]) { r = sd_device_get_property_value(dev, "ID_FS_TYPE", &type); if (r >= 0) { r = fsck_exists(type); - if (r == -ENOENT) { - log_info("fsck.%s doesn't exist, not checking file system on %s", type, device); - r = 0; + if (r < 0) + log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s, proceeding: %m", type, device); + else if (r == 0) { + log_info("fsck.%s doesn't exist, not checking file system on %s.", type, device); goto finish; - } else if (r < 0) - log_warning_errno(r, "Couldn't detect if fsck.%s may be used for %s: %m", type, device); + } } if (arg_show_progress) { @@ -463,10 +469,10 @@ int main(int argc, char *argv[]) { if (status.si_code == CLD_EXITED && (status.si_status & FSCK_SYSTEM_SHOULD_REBOOT) && root_directory) /* System should be rebooted. */ - start_target(SPECIAL_REBOOT_TARGET); + start_target(SPECIAL_REBOOT_TARGET, "replace-irreversibly"); else if (status.si_code == CLD_EXITED && (status.si_status & (FSCK_SYSTEM_SHOULD_REBOOT | FSCK_ERRORS_LEFT_UNCORRECTED))) /* Some other problem */ - start_target(SPECIAL_EMERGENCY_TARGET); + start_target(SPECIAL_EMERGENCY_TARGET, "replace"); else { log_warning("Ignoring error."); r = 0; diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 3f8ea5647c..f7c8d11ace 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -19,22 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <mntent.h> #include <errno.h> +#include <mntent.h> +#include <stdio.h> #include <string.h> #include <unistd.h> -#include "log.h" -#include "util.h" -#include "unit-name.h" -#include "path-util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "fstab-util.h" +#include "generator.h" +#include "log.h" +#include "mkdir.h" #include "mount-setup.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "special.h" -#include "mkdir.h" -#include "generator.h" +#include "stat-util.h" +#include "string-util.h" #include "strv.h" +#include "unit-name.h" +#include "util.h" #include "virt.h" static const char *arg_dest = "/tmp"; diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c index 9a4b038ef3..03df7365b5 100644 --- a/src/getty-generator/getty-generator.c +++ b/src/getty-generator/getty-generator.c @@ -19,20 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> -#include <unistd.h> #include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "log.h" -#include "util.h" #include "mkdir.h" -#include "unit-name.h" -#include "virt.h" -#include "fileio.h" #include "path-util.h" #include "process-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "unit-name.h" +#include "util.h" +#include "virt.h" static const char *arg_dest = "/tmp"; diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index bb821797f1..34852ce381 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -24,22 +24,32 @@ #include <sys/statfs.h> #include <blkid/blkid.h> -#include "sd-id128.h" #include "libudev.h" -#include "path-util.h" -#include "util.h" -#include "mkdir.h" +#include "sd-id128.h" + +#include "alloc-util.h" +#include "blkid-util.h" +#include "btrfs-util.h" +#include "dirent-util.h" +#include "efivars.h" +#include "fd-util.h" +#include "fileio.h" +#include "fstab-util.h" +#include "generator.h" +#include "gpt.h" #include "missing.h" -#include "udev-util.h" +#include "mkdir.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "special.h" +#include "stat-util.h" +#include "string-util.h" +#include "udev-util.h" #include "unit-name.h" +#include "util.h" #include "virt.h" -#include "generator.h" -#include "gpt.h" -#include "fileio.h" -#include "efivars.h" -#include "blkid-util.h" -#include "btrfs-util.h" static const char *arg_dest = "/tmp"; static bool arg_enabled = true; @@ -292,8 +302,7 @@ static int probe_and_add_mount( if (!b) { if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to allocate prober: %m"); - return -errno; + return log_error_errno(errno, "Failed to allocate prober: %m"); } blkid_probe_enable_superblocks(b, 1); @@ -465,6 +474,12 @@ static int add_boot(const char *what) { return 0; } + /* We create an .automount which is not overridden by the .mount from the fstab generator. */ + if (fstab_is_mount_point("/boot")) { + log_debug("/boot specified in fstab, ignoring."); + return 0; + } + if (path_is_busy("/boot")) { log_debug("/boot already populated, ignoring."); return 0; @@ -486,8 +501,7 @@ static int add_boot(const char *what) { if (!b) { if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to allocate prober: %m"); - return -errno; + return log_error_errno(errno, "Failed to allocate prober: %m"); } blkid_probe_enable_partitions(b, 1); @@ -864,7 +878,6 @@ static int get_block_device_harder(const char *path, dev_t *dev) { goto fallback; found = de; - break; } if (!found) diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index 9fb6233336..da719f2a30 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -19,14 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> +#include <stdio.h> +#include "alloc-util.h" +#include "fstab-util.h" #include "log.h" -#include "util.h" -#include "special.h" #include "mkdir.h" +#include "proc-cmdline.h" +#include "special.h" +#include "string-util.h" #include "unit-name.h" +#include "util.h" static const char *arg_dest = "/tmp"; static char *arg_resume_dev = NULL; diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index 1f3b169905..316a2803d3 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -23,9 +23,10 @@ #include <errno.h> #include <sys/stat.h> +#include "alloc-util.h" +#include "fileio.h" #include "log.h" #include "util.h" -#include "fileio.h" int main(int argc, char *argv[]) { struct stat st; diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index dcbad99ae9..bf09fb8fbb 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -19,21 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stdbool.h> #include <getopt.h> #include <locale.h> +#include <stdbool.h> +#include <stdlib.h> #include <string.h> #include "sd-bus.h" #include "sd-id128.h" -#include "hostname-util.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "architecture.h" #include "bus-error.h" -#include "util.h" +#include "bus-util.h" +#include "hostname-util.h" #include "spawn-polkit-agent.h" -#include "build.h" -#include "architecture.h" +#include "util.h" static bool arg_ask_password = true; static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; @@ -387,9 +388,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'H': arg_transport = BUS_TRANSPORT_REMOTE; @@ -519,7 +518,7 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - r = bus_open_transport(arg_transport, arg_host, false, &bus); + r = bus_connect_transport(arg_transport, arg_host, false, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index dd508aefb5..92061532b8 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -24,16 +24,20 @@ #include <unistd.h> #include <sys/utsname.h> -#include "util.h" -#include "strv.h" +#include "alloc-util.h" +#include "bus-util.h" #include "def.h" -#include "virt.h" #include "env-util.h" -#include "fileio-label.h" -#include "bus-util.h" #include "event-util.h" -#include "selinux-util.h" +#include "fileio-label.h" #include "hostname-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "selinux-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" +#include "virt.h" #define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:") diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 446de3a2fc..de59b797a6 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -17,21 +17,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <ctype.h> #include <getopt.h> +#include <stdlib.h> #include <string.h> -#include <ctype.h> -#include "util.h" -#include "strbuf.h" +#include "alloc-util.h" #include "conf-files.h" -#include "strv.h" -#include "mkdir.h" -#include "verbs.h" -#include "build.h" - +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "hwdb-internal.h" #include "hwdb-util.h" +#include "mkdir.h" +#include "strbuf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" +#include "verbs.h" /* * Generic udev properties, key/value database based on modalias strings. @@ -688,9 +691,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_USR: arg_hwdb_bin_dir = UDEVLIBEXECDIR; diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c index 18c42b8b6d..7b1ac134a0 100644 --- a/src/import/aufs-util.c +++ b/src/import/aufs-util.c @@ -21,8 +21,9 @@ #include <ftw.h> -#include "util.h" #include "rm-rf.h" +#include "string-util.h" +#include "util.h" #include "aufs-util.h" static int nftw_cb( diff --git a/src/import/curl-util.c b/src/import/curl-util.c index d390cfb1f3..4278466df1 100644 --- a/src/import/curl-util.c +++ b/src/import/curl-util.c @@ -19,7 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "curl-util.h" +#include "fd-util.h" +#include "string-util.h" static void curl_glue_check_finished(CurlGlue *g) { CURLMsg *msg; diff --git a/src/import/curl-util.h b/src/import/curl-util.h index c249069ffa..6a2aa81c76 100644 --- a/src/import/curl-util.h +++ b/src/import/curl-util.h @@ -24,9 +24,10 @@ #include <sys/types.h> #include <curl/curl.h> -#include "hashmap.h" #include "sd-event.h" +#include "hashmap.h" + typedef struct CurlGlue CurlGlue; struct CurlGlue { diff --git a/src/import/export-raw.c b/src/import/export-raw.c index 8f9c9bbc80..103d45bf21 100644 --- a/src/import/export-raw.c +++ b/src/import/export-raw.c @@ -24,12 +24,17 @@ #undef basename #include "sd-daemon.h" -#include "util.h" -#include "ratelimit.h" + +#include "alloc-util.h" #include "btrfs-util.h" #include "copy.h" -#include "import-common.h" #include "export-raw.h" +#include "fd-util.h" +#include "fileio.h" +#include "import-common.h" +#include "ratelimit.h" +#include "string-util.h" +#include "util.h" #define COPY_BUFFER_SIZE (16*1024) diff --git a/src/import/export-tar.c b/src/import/export-tar.c index 43fa9d1b03..2bbec661e6 100644 --- a/src/import/export-tar.c +++ b/src/import/export-tar.c @@ -19,15 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/sendfile.h> - #include "sd-daemon.h" -#include "util.h" -#include "ratelimit.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "import-common.h" #include "export-tar.h" +#include "fd-util.h" +#include "fileio.h" +#include "import-common.h" #include "process-util.h" +#include "ratelimit.h" +#include "string-util.h" +#include "util.h" #define COPY_BUFFER_SIZE (16*1024) @@ -78,7 +81,7 @@ TarExport *tar_export_unref(TarExport *e) { } if (e->temp_path) { - (void) btrfs_subvol_remove(e->temp_path, false); + (void) btrfs_subvol_remove(e->temp_path, BTRFS_REMOVE_QUOTA); free(e->temp_path); } @@ -283,7 +286,7 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */ BtrfsQuotaInfo q; - r = btrfs_subvol_get_quota_fd(sfd, &q); + r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q); if (r >= 0) e->quota_referenced = q.referenced; diff --git a/src/import/export.c b/src/import/export.c index b88d71fec6..2b33d778d3 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -22,15 +22,19 @@ #include <getopt.h> #include "sd-event.h" + +#include "alloc-util.h" #include "event-util.h" -#include "signal-util.h" +#include "export-raw.h" +#include "export-tar.h" +#include "fd-util.h" +#include "fs-util.h" #include "hostname-util.h" -#include "verbs.h" -#include "build.h" -#include "machine-image.h" #include "import-util.h" -#include "export-tar.h" -#include "export-raw.h" +#include "machine-image.h" +#include "signal-util.h" +#include "string-util.h" +#include "verbs.h" static ImportCompressType arg_compress = IMPORT_COMPRESS_UNKNOWN; @@ -260,9 +264,7 @@ static int parse_argv(int argc, char *argv[]) { return help(0, NULL, NULL); case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_FORMAT: if (streq(optarg, "uncompressed")) diff --git a/src/import/import-common.c b/src/import/import-common.c index d8a3bbc249..a8551ca9e8 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -19,15 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <sched.h> #include <sys/prctl.h> #include <sys/stat.h> #include <unistd.h> -#include "util.h" #include "btrfs-util.h" -#include "capability.h" -#include "signal-util.h" +#include "capability-util.h" +#include "fd-util.h" #include "import-common.h" +#include "signal-util.h" +#include "util.h" int import_make_read_only_fd(int fd) { int r; diff --git a/src/import/import-compress.c b/src/import/import-compress.c index d6b8133036..d4ff178f60 100644 --- a/src/import/import-compress.c +++ b/src/import/import-compress.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "import-compress.h" +#include "string-table.h" +#include "util.h" void import_compress_free(ImportCompress *c) { assert(c); diff --git a/src/import/import-raw.c b/src/import/import-raw.c index 5f7d25d063..7593f064fc 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -23,19 +23,27 @@ #include "sd-daemon.h" #include "sd-event.h" -#include "util.h" -#include "path-util.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "hostname-util.h" +#include "chattr-util.h" #include "copy.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "ratelimit.h" -#include "machine-pool.h" -#include "qcow2-util.h" -#include "import-compress.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" #include "import-common.h" +#include "import-compress.h" #include "import-raw.h" +#include "io-util.h" +#include "machine-pool.h" +#include "mkdir.h" +#include "path-util.h" +#include "qcow2-util.h" +#include "ratelimit.h" +#include "rm-rf.h" +#include "string-util.h" +#include "util.h" struct RawImport { sd_event *event; @@ -191,7 +199,7 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) { r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", t); + log_warning_errno(r, "Failed to set file attributes on %s: %m", t); log_info("Unpacking QCOW2 file."); @@ -279,7 +287,7 @@ static int raw_import_open_disk(RawImport *i) { r = chattr_fd(i->output_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path); + log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path); return 0; } diff --git a/src/import/import-tar.c b/src/import/import-tar.c index d2bfb30238..c7983c04be 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -23,20 +23,27 @@ #include "sd-daemon.h" #include "sd-event.h" -#include "util.h" -#include "path-util.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "hostname-util.h" #include "copy.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "ratelimit.h" -#include "machine-pool.h" -#include "qcow2-util.h" -#include "import-compress.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" #include "import-common.h" +#include "import-compress.h" #include "import-tar.h" +#include "io-util.h" +#include "machine-pool.h" +#include "mkdir.h" +#include "path-util.h" #include "process-util.h" +#include "qcow2-util.h" +#include "ratelimit.h" +#include "rm-rf.h" +#include "string-util.h" +#include "util.h" struct TarImport { sd_event *event; @@ -234,7 +241,9 @@ static int tar_import_fork_tar(TarImport *i) { if (mkdir(i->temp_path, 0755) < 0) return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path); } else if (r < 0) - return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path); + return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path); + else + (void) import_assign_pool_quota_and_warn(i->temp_path); i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (i->tar_fd < 0) diff --git a/src/import/import.c b/src/import/import.c index 929a840298..018b94d4c4 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -22,15 +22,19 @@ #include <getopt.h> #include "sd-event.h" + +#include "alloc-util.h" #include "event-util.h" -#include "verbs.h" -#include "build.h" -#include "signal-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "hostname-util.h" -#include "machine-image.h" -#include "import-util.h" -#include "import-tar.h" #include "import-raw.h" +#include "import-tar.h" +#include "import-util.h" +#include "machine-image.h" +#include "signal-util.h" +#include "string-util.h" +#include "verbs.h" static bool arg_force = false; static bool arg_read_only = false; @@ -280,9 +284,7 @@ static int parse_argv(int argc, char *argv[]) { return help(0, NULL, NULL); case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_FORCE: arg_force = true; diff --git a/src/import/importd.c b/src/import/importd.c index c90ada5da4..4228681cea 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -22,20 +22,28 @@ #include <sys/prctl.h> #include "sd-bus.h" -#include "util.h" -#include "strv.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-common-errors.h" -#include "socket-util.h" -#include "mkdir.h" +#include "bus-util.h" #include "def.h" -#include "missing.h" +#include "fd-util.h" +#include "hostname-util.h" +#include "import-util.h" #include "machine-pool.h" +#include "missing.h" +#include "mkdir.h" +#include "parse-util.h" #include "path-util.h" -#include "import-util.h" #include "process-util.h" #include "signal-util.h" -#include "hostname-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "strv.h" +#include "syslog-util.h" +#include "user-util.h" +#include "util.h" +#include "web-util.h" typedef struct Transfer Transfer; typedef struct Manager Manager; @@ -600,11 +608,11 @@ static int manager_on_notify(sd_event_source *s, int fd, uint32_t revents, void cmsg_close_all(&msghdr); - CMSG_FOREACH(cmsg, &msghdr) { - if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) - + CMSG_FOREACH(cmsg, &msghdr) + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDENTIALS && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) ucred = (struct ucred*) CMSG_DATA(cmsg); - } if (msghdr.msg_flags & MSG_TRUNC) { log_warning("Got overly long notification datagram, ignoring."); diff --git a/src/import/pull-common.c b/src/import/pull-common.c index 38201e46e1..d6567ba7ee 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -21,18 +21,28 @@ #include <sys/prctl.h> -#include "util.h" -#include "strv.h" -#include "copy.h" -#include "rm-rf.h" +#include "alloc-util.h" #include "btrfs-util.h" -#include "capability.h" -#include "pull-job.h" -#include "pull-common.h" +#include "capability-util.h" +#include "copy.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" +#include "io-util.h" +#include "path-util.h" #include "process-util.h" +#include "pull-common.h" +#include "pull-job.h" +#include "rm-rf.h" #include "signal-util.h" +#include "siphash24.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" +#include "web-util.h" #define FILENAME_ESCAPE "/.#\"\'" +#define HASH_URL_THRESHOLD_LENGTH (_POSIX_PATH_MAX - 16) int pull_find_old_etags( const char *url, @@ -136,7 +146,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char * if (force_local) (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - r = btrfs_subvol_snapshot(final, p, 0); + r = btrfs_subvol_snapshot(final, p, BTRFS_SNAPSHOT_QUOTA); if (r == -ENOTTY) { r = copy_tree(final, p, false); if (r < 0) @@ -149,8 +159,21 @@ int pull_make_local_copy(const char *final, const char *image_root, const char * return 0; } +static int hash_url(const char *url, char **ret) { + uint64_t h; + static const sd_id128_t k = SD_ID128_ARRAY(df,89,16,87,01,cc,42,30,98,ab,4a,19,a6,a5,63,4f); + + assert(url); + + siphash24((uint8_t *) &h, url, strlen(url), k.bytes); + if (asprintf(ret, "%"PRIx64, h) < 0) + return -ENOMEM; + + return 0; +} + int pull_make_path(const char *url, const char *etag, const char *image_root, const char *prefix, const char *suffix, char **ret) { - _cleanup_free_ char *escaped_url = NULL; + _cleanup_free_ char *escaped_url = NULL, *escaped_etag = NULL; char *path; assert(url); @@ -164,18 +187,35 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co return -ENOMEM; if (etag) { - _cleanup_free_ char *escaped_etag = NULL; - escaped_etag = xescape(etag, FILENAME_ESCAPE); if (!escaped_etag) return -ENOMEM; + } - path = strjoin(image_root, "/", strempty(prefix), escaped_url, ".", escaped_etag, strempty(suffix), NULL); - } else - path = strjoin(image_root, "/", strempty(prefix), escaped_url, strempty(suffix), NULL); + path = strjoin(image_root, "/", strempty(prefix), escaped_url, escaped_etag ? "." : "", + strempty(escaped_etag), strempty(suffix), NULL); if (!path) return -ENOMEM; + /* URLs might make the path longer than the maximum allowed length for a file name. + * When that happens, a URL hash is used instead. Paths returned by this function + * can be later used with tempfn_random() which adds 16 bytes to the resulting name. */ + if (strlen(path) >= HASH_URL_THRESHOLD_LENGTH) { + _cleanup_free_ char *hash = NULL; + int r; + + free(path); + + r = hash_url(url, &hash); + if (r < 0) + return r; + + path = strjoin(image_root, "/", strempty(prefix), hash, escaped_etag ? "." : "", + strempty(escaped_etag), strempty(suffix), NULL); + if (!path) + return -ENOMEM; + } + *ret = path; return 0; } @@ -334,9 +374,10 @@ int pull_verify(PullJob *main_job, log_info("SHA256 checksum of %s is valid.", main_job->url); - assert(!settings_job || settings_job->state == PULL_JOB_DONE); + assert(!settings_job || IN_SET(settings_job->state, PULL_JOB_DONE, PULL_JOB_FAILED)); if (settings_job && + settings_job->state == PULL_JOB_DONE && settings_job->error == 0 && !settings_job->etag_exists) { diff --git a/src/import/pull-dkr.c b/src/import/pull-dkr.c index 0dab184af1..831470ff13 100644 --- a/src/import/pull-dkr.c +++ b/src/import/pull-dkr.c @@ -23,22 +23,29 @@ #include <sys/prctl.h> #include "sd-daemon.h" -#include "json.h" -#include "strv.h" + +#include "alloc-util.h" +#include "aufs-util.h" #include "btrfs-util.h" -#include "utf8.h" +#include "curl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" +#include "import-common.h" +#include "import-util.h" +#include "json.h" #include "mkdir.h" -#include "rm-rf.h" #include "path-util.h" -#include "import-util.h" -#include "curl-util.h" -#include "aufs-util.h" -#include "pull-job.h" +#include "process-util.h" #include "pull-common.h" -#include "import-common.h" #include "pull-dkr.h" -#include "process-util.h" -#include "hostname-util.h" +#include "pull-job.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "web-util.h" typedef enum DkrProgress { DKR_SEARCHING, @@ -476,13 +483,13 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) { if (!i->final_path) { i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL); if (!i->final_path) - return log_oom(); + return -ENOMEM; } if (version == DKR_PULL_V2) { - r = path_get_parent(i->image_root, &p); - if (r < 0) - return r; + p = dirname_malloc(i->image_root); + if (!p) + return -ENOMEM; } r = pull_make_local_copy(i->final_path, p ?: i->image_root, i->local, i->force_local); @@ -490,10 +497,16 @@ static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) { return r; if (version == DKR_PULL_V2) { - char **k = NULL; + char **k; + STRV_FOREACH(k, i->ancestry) { - _cleanup_free_ char *d = strjoin(i->image_root, "/.dkr-", *k, NULL); - r = btrfs_subvol_remove(d, false); + _cleanup_free_ char *d; + + d = strjoin(i->image_root, "/.dkr-", *k, NULL); + if (!d) + return -ENOMEM; + + r = btrfs_subvol_remove(d, BTRFS_REMOVE_QUOTA); if (r < 0) return r; } @@ -531,12 +544,14 @@ static int dkr_pull_job_on_open_disk(PullJob *j) { const char *base_path; base_path = strjoina(i->image_root, "/.dkr-", base); - r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY); + r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_QUOTA); } else r = btrfs_subvol_make(i->temp_path); if (r < 0) return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path); + (void) import_assign_pool_quota_and_warn(i->temp_path); + j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (j->disk_fd < 0) return j->disk_fd; diff --git a/src/import/pull-job.c b/src/import/pull-job.c index 42939f2104..824fa246ec 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -21,9 +21,16 @@ #include <sys/xattr.h> -#include "strv.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "hexdecoct.h" +#include "io-util.h" #include "machine-pool.h" +#include "parse-util.h" #include "pull-job.h" +#include "string-util.h" +#include "strv.h" +#include "xattr-util.h" PullJob* pull_job_unref(PullJob *j) { if (!j) diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 0e77197e34..03bfb51756 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -19,28 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/xattr.h> -#include <linux/fs.h> #include <curl/curl.h> +#include <linux/fs.h> +#include <sys/xattr.h> #include "sd-daemon.h" -#include "utf8.h" -#include "strv.h" -#include "copy.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "util.h" +#include "chattr-util.h" +#include "copy.h" +#include "curl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" +#include "import-common.h" +#include "import-util.h" #include "macro.h" #include "mkdir.h" -#include "rm-rf.h" #include "path-util.h" -#include "hostname-util.h" -#include "import-util.h" -#include "import-common.h" -#include "curl-util.h" -#include "qcow2-util.h" -#include "pull-job.h" #include "pull-common.h" +#include "pull-job.h" #include "pull-raw.h" +#include "qcow2-util.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "util.h" +#include "web-util.h" typedef enum RawProgress { RAW_DOWNLOADING, @@ -236,7 +244,7 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) { r = chattr_fd(converted_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", t); + log_warning_errno(r, "Failed to set file attributes on %s: %m", t); log_info("Unpacking QCOW2 file."); @@ -312,7 +320,7 @@ static int raw_pull_make_local_copy(RawPull *i) { * writes. */ r = chattr_fd(dfd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", tp); + log_warning_errno(r, "Failed to set file attributes on %s: %m", tp); r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, true); if (r < 0) { @@ -327,8 +335,9 @@ static int raw_pull_make_local_copy(RawPull *i) { r = rename(tp, p); if (r < 0) { + r = log_error_errno(errno, "Failed to move writable image into place: %m"); unlink(tp); - return log_error_errno(errno, "Failed to move writable image into place: %m"); + return r; } log_info("Created new local image '%s'.", i->local); @@ -349,9 +358,9 @@ static int raw_pull_make_local_copy(RawPull *i) { if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); else if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings); - - log_info("Create new settings file '%s.nspawn'", i->local); + log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); + else + log_info("Created new settings file '%s.nspawn'", i->local); } return 0; @@ -503,7 +512,7 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) { r = chattr_fd(j->disk_fd, FS_NOCOW_FL, FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes on %s: %m", i->temp_path); + log_warning_errno(r, "Failed to set file attributes on %s: %m", i->temp_path); return 0; } diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 563765d83d..e7fcd293f1 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -23,23 +23,30 @@ #include <curl/curl.h> #include "sd-daemon.h" -#include "utf8.h" -#include "strv.h" -#include "copy.h" + +#include "alloc-util.h" #include "btrfs-util.h" -#include "util.h" +#include "copy.h" +#include "curl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-util.h" +#include "import-common.h" +#include "import-util.h" #include "macro.h" #include "mkdir.h" -#include "rm-rf.h" #include "path-util.h" #include "process-util.h" -#include "hostname-util.h" -#include "import-util.h" -#include "import-common.h" -#include "curl-util.h" -#include "pull-job.h" #include "pull-common.h" +#include "pull-job.h" #include "pull-tar.h" +#include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "util.h" +#include "web-util.h" typedef enum TarProgress { TAR_DOWNLOADING, @@ -247,9 +254,9 @@ static int tar_pull_make_local_copy(TarPull *i) { if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); else if (r < 0 && r != -ENOENT) - log_warning_errno(r, "Failed to copy settings files %s: %m", local_settings); - - log_info("Create new settings file '%s.nspawn'", i->local); + log_warning_errno(r, "Failed to copy settings files %s, ignoring: %m", local_settings); + else + log_info("Created new settings file '%s.nspawn'", i->local); } return 0; @@ -409,7 +416,9 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) { if (mkdir(i->temp_path, 0755) < 0) return log_error_errno(errno, "Failed to create directory %s: %m", i->temp_path); } else if (r < 0) - return log_error_errno(errno, "Failed to create subvolume %s: %m", i->temp_path); + return log_error_errno(r, "Failed to create subvolume %s: %m", i->temp_path); + else + (void) import_assign_pool_quota_and_warn(i->temp_path); j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (j->disk_fd < 0) diff --git a/src/import/pull.c b/src/import/pull.c index 98c22aeec9..39f5b2d8e4 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -22,16 +22,20 @@ #include <getopt.h> #include "sd-event.h" + +#include "alloc-util.h" #include "event-util.h" -#include "verbs.h" -#include "build.h" -#include "signal-util.h" #include "hostname-util.h" -#include "machine-image.h" #include "import-util.h" -#include "pull-tar.h" -#include "pull-raw.h" +#include "machine-image.h" +#include "parse-util.h" #include "pull-dkr.h" +#include "pull-raw.h" +#include "pull-tar.h" +#include "signal-util.h" +#include "string-util.h" +#include "verbs.h" +#include "web-util.h" static bool arg_force = false; static const char *arg_image_root = "/var/lib/machines"; @@ -381,9 +385,7 @@ static int parse_argv(int argc, char *argv[]) { return help(0, NULL, NULL); case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_FORCE: arg_force = true; diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c index fd3cf1b0e3..47dabaa86e 100644 --- a/src/import/qcow2-util.c +++ b/src/import/qcow2-util.c @@ -21,10 +21,11 @@ #include <zlib.h> -#include "util.h" -#include "sparse-endian.h" -#include "qcow2-util.h" +#include "alloc-util.h" #include "btrfs-util.h" +#include "qcow2-util.h" +#include "sparse-endian.h" +#include "util.h" #define QCOW2_MAGIC 0x514649fb diff --git a/src/import/test-qcow2.c b/src/import/test-qcow2.c index 9a6c3e8b35..4b60079619 100644 --- a/src/import/test-qcow2.c +++ b/src/import/test-qcow2.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "fd-util.h" #include "log.h" -#include "util.h" - #include "qcow2-util.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int sfd = -1, dfd = -1; diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index 6d08db74ef..d4f8673187 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -25,18 +25,20 @@ #include <sys/epoll.h> #include <ctype.h> -#include "sd-daemon.h" #include "sd-bus.h" +#include "sd-daemon.h" -#include "util.h" -#include "log.h" -#include "list.h" -#include "initreq.h" -#include "special.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" +#include "bus-util.h" #include "def.h" +#include "fd-util.h" #include "formats-util.h" +#include "initreq.h" +#include "list.h" +#include "log.h" +#include "special.h" +#include "util.h" #define SERVER_FD_MAX 16 #define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC)) @@ -210,8 +212,7 @@ static int fifo_process(Fifo *f) { if (errno == EAGAIN) return 0; - log_warning_errno(errno, "Failed to read from fifo: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read from fifo: %m"); } f->bytes_read += l; @@ -318,7 +319,7 @@ static int server_init(Server *s, unsigned n_sockets) { s->n_fifos ++; } - r = bus_open_system_systemd(&s->bus); + r = bus_connect_system_systemd(&s->bus); if (r < 0) { log_error_errno(r, "Failed to get D-Bus connection: %m"); r = -EIO; diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 4e5572db0b..6b93a758f6 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -19,30 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <string.h> -#include <unistd.h> #include <fcntl.h> #include <getopt.h> - -#include <microhttpd.h> - #ifdef HAVE_GNUTLS #include <gnutls/gnutls.h> #endif +#include <microhttpd.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> -#include "sd-journal.h" -#include "sd-daemon.h" #include "sd-bus.h" -#include "log.h" -#include "util.h" +#include "sd-daemon.h" +#include "sd-journal.h" + +#include "alloc-util.h" #include "bus-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "log.h" #include "logs-show.h" #include "microhttpd-util.h" -#include "build.h" -#include "fileio.h" +#include "parse-util.h" #include "sigbus.h" -#include "hostname-util.h" +#include "util.h" static char *arg_key_pem = NULL; static char *arg_cert_pem = NULL; @@ -909,9 +910,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_KEY: if (arg_key_pem) { @@ -1014,7 +1013,22 @@ int main(int argc, char *argv[]) { { MHD_OPTION_END, 0, NULL }, { MHD_OPTION_END, 0, NULL }}; int opts_pos = 2; - int flags = MHD_USE_THREAD_PER_CONNECTION|MHD_USE_POLL|MHD_USE_DEBUG; + + /* We force MHD_USE_PIPE_FOR_SHUTDOWN here, in order + * to make sure libmicrohttpd doesn't use shutdown() + * on our listening socket, which would break socket + * re-activation. See + * + * https://lists.gnu.org/archive/html/libmicrohttpd/2015-09/msg00014.html + * https://github.com/systemd/systemd/pull/1286 + */ + + int flags = + MHD_USE_DEBUG | + MHD_USE_DUAL_STACK | + MHD_USE_PIPE_FOR_SHUTDOWN | + MHD_USE_POLL | + MHD_USE_THREAD_PER_CONNECTION; if (n > 0) opts[opts_pos++] = (struct MHD_OptionItem) diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c index 2e0f78701a..3ff40228a0 100644 --- a/src/journal-remote/journal-remote-parse.c +++ b/src/journal-remote/journal-remote-parse.c @@ -19,8 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "fd-util.h" #include "journal-remote-parse.h" #include "journald-native.h" +#include "parse-util.h" +#include "string-util.h" #define LINE_CHUNK 8*1024u diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index 40f4ff8e58..d8250378b0 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "journal-remote.h" int iovw_put(struct iovec_wrapper *iovw, void* data, size_t len) { diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index d6ebca20ec..6eb0ee9d9e 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -21,31 +21,39 @@ #include <errno.h> #include <fcntl.h> +#include <getopt.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/prctl.h> #include <sys/socket.h> #include <unistd.h> -#include <getopt.h> - -#include "sd-daemon.h" -#include "signal-util.h" -#include "journal-file.h" -#include "journald-native.h" -#include "socket-util.h" -#include "build.h" -#include "macro.h" -#include "strv.h" -#include "fileio.h" -#include "conf-parser.h" #ifdef HAVE_GNUTLS #include <gnutls/gnutls.h> #endif -#include "journal-remote.h" +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "conf-parser.h" +#include "def.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "journal-file.h" #include "journal-remote-write.h" +#include "journal-remote.h" +#include "journald-native.h" +#include "macro.h" +#include "parse-util.h" +#include "signal-util.h" +#include "socket-util.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" #define REMOTE_JOURNAL_PATH "/var/log/journal/remote" @@ -138,7 +146,7 @@ static int spawn_curl(const char* url) { r = spawn_child("curl", argv); if (r < 0) - log_error_errno(errno, "Failed to spawn curl: %m"); + log_error_errno(r, "Failed to spawn curl: %m"); return r; } @@ -157,7 +165,7 @@ static int spawn_getter(const char *getter, const char *url) { r = spawn_child(words[0], words); if (r < 0) - log_error_errno(errno, "Failed to spawn getter %s: %m", getter); + log_error_errno(r, "Failed to spawn getter %s: %m", getter); return r; } @@ -641,16 +649,18 @@ static int setup_microhttpd_server(RemoteServer *s, { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free}, { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger}, { MHD_OPTION_LISTEN_SOCKET, fd}, + { MHD_OPTION_CONNECTION_MEMORY_LIMIT, DATA_SIZE_MAX}, { MHD_OPTION_END}, { MHD_OPTION_END}, { MHD_OPTION_END}, { MHD_OPTION_END}}; - int opts_pos = 3; + int opts_pos = 4; int flags = MHD_USE_DEBUG | - MHD_USE_PEDANTIC_CHECKS | + MHD_USE_DUAL_STACK | MHD_USE_EPOLL_LINUX_ONLY | - MHD_USE_DUAL_STACK; + MHD_USE_PEDANTIC_CHECKS | + MHD_USE_PIPE_FOR_SHUTDOWN; const union MHD_DaemonInfo *info; int r, epoll_fd; @@ -954,7 +964,7 @@ static int remoteserver_init(RemoteServer *s, } if (s->active == 0) { - log_error("Zarro sources specified"); + log_error("Zero sources specified"); return -EINVAL; } @@ -1259,9 +1269,7 @@ static int parse_argv(int argc, char *argv[]) { return 0 /* done */; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0 /* done */; + return version(); case ARG_URL: if (arg_url) { @@ -1409,18 +1417,21 @@ static int parse_argv(int argc, char *argv[]) { case ARG_GNUTLS_LOG: { #ifdef HAVE_GNUTLS - const char *word, *state; - size_t size; + const char* p = optarg; + for (;;) { + _cleanup_free_ char *word = NULL; - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { - char *cat; + r = extract_first_word(&p, &word, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse --gnutls-log= argument: %m"); - cat = strndup(word, size); - if (!cat) - return log_oom(); + if (r == 0) + break; - if (strv_consume(&arg_gnutls_log, cat) < 0) + if (strv_push(&arg_gnutls_log, word) < 0) return log_oom(); + + word = NULL; } break; #else diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index 6b3ad924a7..3ee6d32bf7 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -1,11 +1,33 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Zbigniew Jędrzejewski-Szmek + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + #include <stdbool.h> #include <curl/curl.h> -#include "util.h" +#include "alloc-util.h" +#include "journal-upload.h" #include "log.h" #include "utf8.h" -#include "journal-upload.h" +#include "util.h" /** * Write up to size bytes to buf. Return negative on error, and number of diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 311bd3fdda..42d14dc7c4 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -19,23 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <curl/curl.h> -#include <sys/stat.h> #include <fcntl.h> #include <getopt.h> +#include <stdio.h> +#include <sys/stat.h> #include "sd-daemon.h" -#include "log.h" -#include "util.h" -#include "build.h" + +#include "alloc-util.h" +#include "conf-parser.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" +#include "formats-util.h" +#include "glob-util.h" +#include "journal-upload.h" +#include "log.h" #include "mkdir.h" -#include "conf-parser.h" +#include "parse-util.h" #include "sigbus.h" -#include "formats-util.h" #include "signal-util.h" -#include "journal-upload.h" +#include "string-util.h" +#include "util.h" #define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-upload.pem" #define CERT_FILE CERTIFICATE_ROOT "/certs/journal-upload.pem" @@ -619,9 +625,7 @@ static int parse_argv(int argc, char *argv[]) { return 0 /* done */; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0 /* done */; + return version(); case 'u': if (arg_url) { diff --git a/src/journal-remote/log-generator.py b/src/journal-remote/log-generator.py index 9a8fb07c7f..fd6964e758 100755 --- a/src/journal-remote/log-generator.py +++ b/src/journal-remote/log-generator.py @@ -6,6 +6,8 @@ import argparse PARSER = argparse.ArgumentParser() PARSER.add_argument('n', type=int) PARSER.add_argument('--dots', action='store_true') +PARSER.add_argument('--data-size', type=int, default=4000) +PARSER.add_argument('--data-type', choices={'random', 'simple'}) OPTIONS = PARSER.parse_args() template = """\ @@ -38,10 +40,16 @@ facility = 6 src = open('/dev/urandom', 'rb') bytes = 0 +counter = 0 for i in range(OPTIONS.n): message = repr(src.read(2000)) - data = repr(src.read(4000)) + if OPTIONS.data_type == 'random': + data = repr(src.read(OPTIONS.data_size)) + else: + # keep the pattern non-repeating so we get a different blob every time + data = '{:0{}}'.format(counter, OPTIONS.data_size) + counter += 1 entry = template.format(m=m, realtime_ts=realtime_ts, diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index 8a11fba044..b2c398a845 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -24,17 +24,19 @@ #include <stdio.h> #include <string.h> -#include "microhttpd-util.h" -#include "log.h" -#include "macro.h" -#include "util.h" -#include "strv.h" - #ifdef HAVE_GNUTLS #include <gnutls/gnutls.h> #include <gnutls/x509.h> #endif +#include "alloc-util.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" +#include "microhttpd-util.h" + void microhttpd_logger(void *arg, const char *fmt, va_list ap) { char *f; diff --git a/src/journal/cat.c b/src/journal/cat.c index be2c2e3354..7fd4198df8 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -19,17 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <getopt.h> -#include <unistd.h> -#include <stdlib.h> #include <errno.h> #include <fcntl.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> -#include "systemd/sd-journal.h" +#include "sd-journal.h" +#include "fd-util.h" +#include "parse-util.h" +#include "string-util.h" +#include "syslog-util.h" #include "util.h" -#include "build.h" static char *arg_identifier = NULL; static int arg_priority = LOG_INFO; @@ -76,9 +79,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 't': free(arg_identifier); @@ -95,7 +96,7 @@ static int parse_argv(int argc, char *argv[]) { arg_priority = log_level_from_string(optarg); if (arg_priority < 0) { log_error("Failed to parse priority value."); - return arg_priority; + return -EINVAL; } break; @@ -103,10 +104,9 @@ static int parse_argv(int argc, char *argv[]) { int k; k = parse_boolean(optarg); - if (k < 0) { - log_error("Failed to parse level prefix value."); - return k; - } + if (k < 0) + return log_error_errno(k, "Failed to parse level prefix value."); + arg_level_prefix = k; break; } @@ -122,7 +122,8 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char *argv[]) { - int r, fd = -1, saved_stderr = -1; + _cleanup_close_ int fd = -1, saved_stderr = -1; + int r; log_parse_environment(); log_open(); @@ -133,8 +134,7 @@ int main(int argc, char *argv[]) { fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); if (fd < 0) { - log_error_errno(fd, "Failed to create stream fd: %m"); - r = fd; + r = log_error_errno(fd, "Failed to create stream fd: %m"); goto finish; } @@ -148,25 +148,20 @@ int main(int argc, char *argv[]) { if (fd >= 3) safe_close(fd); - fd = -1; if (argc <= optind) - execl("/bin/cat", "/bin/cat", NULL); + (void) execl("/bin/cat", "/bin/cat", NULL); else - execvp(argv[optind], argv + optind); - + (void) execvp(argv[optind], argv + optind); r = -errno; /* Let's try to restore a working stderr, so we can print the error message */ if (saved_stderr >= 0) - dup3(saved_stderr, STDERR_FILENO, 0); + (void) dup3(saved_stderr, STDERR_FILENO, 0); log_error_errno(r, "Failed to execute process: %m"); finish: - safe_close(fd); - safe_close(saved_stderr); - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/journal/catalog.c b/src/journal/catalog.c index a3e51e2f52..fcaa54aa0c 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -19,25 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> #include <fcntl.h> +#include <locale.h> #include <stdio.h> -#include <unistd.h> -#include <errno.h> #include <string.h> #include <sys/mman.h> -#include <locale.h> +#include <unistd.h> -#include "util.h" -#include "log.h" -#include "sparse-endian.h" #include "sd-id128.h" -#include "hashmap.h" -#include "strv.h" -#include "strbuf.h" + +#include "alloc-util.h" +#include "catalog.h" #include "conf-files.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "log.h" #include "mkdir.h" -#include "catalog.h" +#include "path-util.h" #include "siphash24.h" +#include "sparse-endian.h" +#include "strbuf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" const char * const catalog_file_dirs[] = { "/usr/local/lib/systemd/catalog/", @@ -62,21 +68,11 @@ typedef struct CatalogItem { le64_t offset; } CatalogItem; -static unsigned long catalog_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void catalog_hash_func(const void *p, struct siphash *state) { const CatalogItem *i = p; - uint64_t u; - size_t l, sz; - void *v; - l = strlen(i->language); - sz = sizeof(i->id) + l; - v = alloca(sz); - - memcpy(mempcpy(v, &i->id, sizeof(i->id)), i->language, l); - - siphash24((uint8_t*) &u, v, sz, hash_key); - - return (unsigned long) u; + siphash24_compress(&i->id, sizeof(i->id), state); + siphash24_compress(i->language, strlen(i->language), state); } static int catalog_compare_func(const void *a, const void *b) { @@ -212,7 +208,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { r = catalog_file_lang(path, &deflang); if (r < 0) - log_error_errno(errno, "Failed to determine language for file %s: %m", path); + log_error_errno(r, "Failed to determine language for file %s: %m", path); if (r == 1) log_debug("File %s has language %s.", path, deflang); @@ -225,8 +221,7 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { if (feof(f)) break; - log_error_errno(errno, "Failed to read file %s: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file %s: %m", path); } n++; @@ -323,8 +318,8 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { return 0; } -static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb, - CatalogItem *items, size_t n) { +static int64_t write_catalog(const char *database, struct strbuf *sb, + CatalogItem *items, size_t n) { CatalogHeader header; _cleanup_fclose_ FILE *w = NULL; int r; @@ -348,7 +343,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb, memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature)); header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8)); header.catalog_item_size = htole64(sizeof(CatalogItem)); - header.n_items = htole64(hashmap_size(h)); + header.n_items = htole64(n); r = -EIO; @@ -383,7 +378,7 @@ static long write_catalog(const char *database, Hashmap *h, struct strbuf *sb, goto error; } - return ftell(w); + return ftello(w); error: (void) unlink(p); @@ -399,7 +394,8 @@ int catalog_update(const char* database, const char* root, const char* const* di CatalogItem *i; Iterator j; unsigned n; - long r; + int r; + int64_t sz; h = hashmap_new(&catalog_hash_ops); sb = strbuf_new(); @@ -419,8 +415,7 @@ int catalog_update(const char* database, const char* root, const char* const* di log_debug("Reading file '%s'", *f); r = catalog_import_file(h, sb, *f); if (r < 0) { - log_error("Failed to import file '%s': %s.", - *f, strerror(-r)); + log_error_errno(r, "Failed to import file '%s': %m", *f); goto finish; } } @@ -450,18 +445,19 @@ int catalog_update(const char* database, const char* root, const char* const* di assert(n == hashmap_size(h)); qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func); - r = write_catalog(database, h, sb, items, n); - if (r < 0) - log_error_errno(r, "Failed to write %s: %m", database); - else - log_debug("%s: wrote %u items, with %zu bytes of strings, %ld total size.", - database, n, sb->len, r); + sz = write_catalog(database, sb, items, n); + if (sz < 0) + r = log_error_errno(sz, "Failed to write %s: %m", database); + else { + r = 0; + log_debug("%s: wrote %u items, with %zu bytes of strings, %"PRIi64" total size.", + database, n, sb->len, sz); + } finish: - if (sb) - strbuf_cleanup(sb); + strbuf_cleanup(sb); - return r < 0 ? r : 0; + return r; } static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) { @@ -676,8 +672,7 @@ int catalog_list_items(FILE *f, const char *database, bool oneline, char **items k = sd_id128_from_string(*item, &id); if (k < 0) { - log_error_errno(k, "Failed to parse id128 '%s': %m", - *item); + log_error_errno(k, "Failed to parse id128 '%s': %m", *item); if (r == 0) r = k; continue; @@ -685,9 +680,8 @@ int catalog_list_items(FILE *f, const char *database, bool oneline, char **items k = catalog_get(database, id, &msg); if (k < 0) { - log_full(k == -ENOENT ? LOG_NOTICE : LOG_ERR, - "Failed to retrieve catalog entry for '%s': %s", - *item, strerror(-k)); + log_full_errno(k == -ENOENT ? LOG_NOTICE : LOG_ERR, k, + "Failed to retrieve catalog entry for '%s': %m", *item); if (r == 0) r = k; continue; diff --git a/src/journal/compress.c b/src/journal/compress.c index c66043e503..e1ca0a8818 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -21,21 +21,33 @@ #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include <unistd.h> #ifdef HAVE_XZ -# include <lzma.h> +#include <lzma.h> #endif #ifdef HAVE_LZ4 -# include <lz4.h> +#include <lz4.h> +#include <lz4frame.h> #endif +#include "alloc-util.h" #include "compress.h" +#include "fd-util.h" +#include "io-util.h" +#include "journal-def.h" #include "macro.h" -#include "util.h" #include "sparse-endian.h" -#include "journal-def.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" + +#ifdef HAVE_LZ4 +DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionContext); +DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext); +#endif #define ALIGN_8(l) ALIGN_TO(l, sizeof(size_t)) @@ -50,10 +62,11 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ #ifdef HAVE_XZ static const lzma_options_lzma opt = { 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT, - LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4}; - static const lzma_filter filters[2] = { - {LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt}, - {LZMA_VLI_UNKNOWN, NULL} + LZMA_PB_DEFAULT, LZMA_MODE_FAST, 128, LZMA_MF_HC3, 4 + }; + static const lzma_filter filters[] = { + { LZMA_FILTER_LZMA2, (lzma_options_lzma*) &opt }, + { LZMA_VLI_UNKNOWN, NULL } }; lzma_ret ret; size_t out_pos = 0; @@ -416,81 +429,96 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { #endif } -#define LZ4_BUFSIZE (512*1024) +#define LZ4_BUFSIZE (512*1024u) int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { #ifdef HAVE_LZ4 + LZ4F_errorCode_t c; + _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL; + _cleanup_free_ char *buf = NULL; + char *src = NULL; + size_t size, n, total_in = 0, total_out = 0, offset = 0, frame_size; + struct stat st; + int r; + static const LZ4F_compressOptions_t options = { + .stableSrc = 1, + }; + static const LZ4F_preferences_t preferences = { + .frameInfo.blockSizeID = 5, + }; - _cleanup_free_ char *buf1 = NULL, *buf2 = NULL, *out = NULL; - char *buf; - LZ4_stream_t lz4_data = {}; - le32_t header; - size_t total_in = 0, total_out = sizeof(header); - ssize_t n; + c = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); + if (LZ4F_isError(c)) + return -ENOMEM; - assert(fdf >= 0); - assert(fdt >= 0); + if (fstat(fdf, &st) < 0) + return log_debug_errno(errno, "fstat() failed: %m"); - buf1 = malloc(LZ4_BUFSIZE); - buf2 = malloc(LZ4_BUFSIZE); - out = malloc(LZ4_COMPRESSBOUND(LZ4_BUFSIZE)); - if (!buf1 || !buf2 || !out) - return log_oom(); + frame_size = LZ4F_compressBound(LZ4_BUFSIZE, &preferences); + size = frame_size + 64*1024; /* add some space for header and trailer */ + buf = malloc(size); + if (!buf) + return -ENOMEM; - buf = buf1; - for (;;) { - size_t m; - int r; + n = offset = LZ4F_compressBegin(ctx, buf, size, &preferences); + if (LZ4F_isError(n)) + return -EINVAL; - m = LZ4_BUFSIZE; - if (max_bytes != (uint64_t) -1 && (uint64_t) m > (max_bytes - total_in)) - m = (size_t) (max_bytes - total_in); + src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdf, 0); + if (src == MAP_FAILED) + return -errno; - n = read(fdf, buf, m); - if (n < 0) - return -errno; - if (n == 0) - break; + log_debug("Buffer size is %zu bytes, header size %zu bytes.", size, n); - total_in += n; + while (total_in < (size_t) st.st_size) { + ssize_t k; - r = LZ4_compress_continue(&lz4_data, buf, out, n); - if (r == 0) { - log_error("LZ4 compression failed."); - return -EBADMSG; + k = MIN(LZ4_BUFSIZE, st.st_size - total_in); + n = LZ4F_compressUpdate(ctx, buf + offset, size - offset, + src + total_in, k, &options); + if (LZ4F_isError(n)) { + r = -ENOTRECOVERABLE; + goto cleanup; } - header = htole32(r); - errno = 0; - - n = write(fdt, &header, sizeof(header)); - if (n < 0) - return -errno; - if (n != sizeof(header)) - return errno ? -errno : -EIO; + total_in += k; + offset += n; + total_out += n; - n = loop_write(fdt, out, r, false); - if (n < 0) - return n; + if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { + log_debug("Compressed stream longer than %zd bytes", max_bytes); + return -EFBIG; + } - total_out += sizeof(header) + r; + if (size - offset < frame_size + 4) { + k = loop_write(fdt, buf, offset, false); + if (k < 0) { + r = k; + goto cleanup; + } + offset = 0; + } + } - buf = buf == buf1 ? buf2 : buf1; + n = LZ4F_compressEnd(ctx, buf + offset, size - offset, &options); + if (LZ4F_isError(n)) { + r = -ENOTRECOVERABLE; + goto cleanup; } - header = htole32(0); - n = write(fdt, &header, sizeof(header)); - if (n < 0) - return -errno; - if (n != sizeof(header)) - return errno ? -errno : -EIO; + offset += n; + total_out += n; + r = loop_write(fdt, buf, offset, false); + if (r < 0) + goto cleanup; log_debug("LZ4 compression finished (%zu -> %zu bytes, %.1f%%)", total_in, total_out, (double) total_out / total_in * 100); - - return 0; + cleanup: + munmap(src, st.st_size); + return r; #else return -EPROTONOSUPPORT; #endif @@ -510,7 +538,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { ret = lzma_stream_decoder(&s, UINT64_MAX, 0); if (ret != LZMA_OK) { - log_error("Failed to initialize XZ decoder: code %u", ret); + log_debug("Failed to initialize XZ decoder: code %u", ret); return -ENOMEM; } @@ -536,7 +564,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { ret = lzma_code(&s, action); if (ret != LZMA_OK && ret != LZMA_STREAM_END) { - log_error("Decompression failed: code %u", ret); + log_debug("Decompression failed: code %u", ret); return -EBADMSG; } @@ -566,14 +594,14 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { } } #else - log_error("Cannot decompress file. Compiled without XZ support."); + log_debug("Cannot decompress file. Compiled without XZ support."); return -EPROTONOSUPPORT; #endif } -int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { - #ifdef HAVE_LZ4 +static int decompress_stream_lz4_v1(int fdf, int fdt, uint64_t max_bytes) { + _cleanup_free_ char *buf = NULL, *out = NULL; size_t buf_size = 0; LZ4_streamDecode_t lz4_data = {}; @@ -585,7 +613,7 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { out = malloc(4*LZ4_BUFSIZE); if (!out) - return log_oom(); + return -ENOMEM; for (;;) { ssize_t m; @@ -606,22 +634,24 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { * not accept buffers compressed by newer binaries then. */ if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) { - log_error("Compressed stream block too big: %zd bytes", m); - return -EBADMSG; + log_debug("Compressed stream block too big: %zd bytes", m); + return -ENOBUFS; } total_in += sizeof(header) + m; if (!GREEDY_REALLOC(buf, buf_size, m)) - return log_oom(); + return -ENOMEM; r = loop_read_exact(fdf, buf, m, false); if (r < 0) return r; r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE); - if (r <= 0) - log_error("LZ4 decompression failed."); + if (r <= 0) { + log_debug("LZ4 decompression failed (legacy format)."); + return -EBADMSG; + } total_out += r; @@ -635,13 +665,80 @@ int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { return r; } - log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)", + log_debug("LZ4 decompression finished (legacy format, %zu -> %zu bytes, %.1f%%)", total_in, total_out, (double) total_out / total_in * 100); return 0; +} + +static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) { + size_t c; + _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL; + _cleanup_free_ char *buf = NULL; + char *src; + struct stat st; + int r = 0; + size_t total_in = 0, total_out = 0; + + c = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION); + if (LZ4F_isError(c)) + return -ENOMEM; + + if (fstat(in, &st) < 0) + return log_debug_errno(errno, "fstat() failed: %m"); + + buf = malloc(LZ4_BUFSIZE); + if (!buf) + return -ENOMEM; + + src = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in, 0); + if (src == MAP_FAILED) + return -errno; + + while (total_in < (size_t) st.st_size) { + size_t produced = LZ4_BUFSIZE; + size_t used = st.st_size - total_in; + + c = LZ4F_decompress(ctx, buf, &produced, src + total_in, &used, NULL); + if (LZ4F_isError(c)) { + r = -EBADMSG; + goto cleanup; + } + + total_in += used; + total_out += produced; + + if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { + log_debug("Decompressed stream longer than %zd bytes", max_bytes); + r = -EFBIG; + goto cleanup; + } + + r = loop_write(out, buf, produced, false); + if (r < 0) + goto cleanup; + } + + log_debug("LZ4 decompression finished (%zu -> %zu bytes, %.1f%%)", + total_in, total_out, + (double) total_out / total_in * 100); + cleanup: + munmap(src, st.st_size); + return r; +} +#endif + +int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { +#ifdef HAVE_LZ4 + int r; + + r = decompress_stream_lz4_v2(fdf, fdt, max_bytes); + if (r == -EBADMSG) + r = decompress_stream_lz4_v1(fdf, fdt, max_bytes); + return r; #else - log_error("Cannot decompress file. Compiled without LZ4 support."); + log_debug("Cannot decompress file. Compiled without LZ4 support."); return -EPROTONOSUPPORT; #endif } diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c index efe418615a..39bc2e4270 100644 --- a/src/journal/coredump-vacuum.c +++ b/src/journal/coredump-vacuum.c @@ -21,12 +21,16 @@ #include <sys/statvfs.h> -#include "util.h" -#include "time-util.h" +#include "alloc-util.h" +#include "coredump-vacuum.h" +#include "dirent-util.h" +#include "fd-util.h" #include "hashmap.h" #include "macro.h" - -#include "coredump-vacuum.h" +#include "string-util.h" +#include "time-util.h" +#include "user-util.h" +#include "util.h" #define DEFAULT_MAX_USE_LOWER (uint64_t) (1ULL*1024ULL*1024ULL) /* 1 MiB */ #define DEFAULT_MAX_USE_UPPER (uint64_t) (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ diff --git a/src/journal/coredump.c b/src/journal/coredump.c index e1e66b9826..4c83e311db 100644 --- a/src/journal/coredump.c +++ b/src/journal/coredump.c @@ -20,10 +20,10 @@ ***/ #include <errno.h> -#include <unistd.h> #include <stdio.h> #include <sys/prctl.h> #include <sys/xattr.h> +#include <unistd.h> #ifdef HAVE_ELFUTILS # include <dwarf.h> @@ -32,23 +32,34 @@ #include "sd-journal.h" #include "sd-login.h" -#include "log.h" -#include "util.h" -#include "fileio.h" -#include "strv.h" -#include "macro.h" -#include "mkdir.h" -#include "special.h" + +#include "acl-util.h" +#include "alloc-util.h" +#include "capability-util.h" #include "cgroup-util.h" +#include "compress.h" #include "conf-parser.h" #include "copy.h" -#include "stacktrace.h" -#include "compress.h" -#include "acl-util.h" -#include "capability.h" -#include "journald-native.h" #include "coredump-vacuum.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "io-util.h" +#include "journald-native.h" +#include "log.h" +#include "macro.h" +#include "mkdir.h" +#include "parse-util.h" #include "process-util.h" +#include "special.h" +#include "stacktrace.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" /* The maximum size up to which we process coredumps */ #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU)) @@ -128,6 +139,7 @@ static int fix_acl(int fd, uid_t uid) { _cleanup_(acl_freep) acl_t acl = NULL; acl_entry_t entry; acl_permset_t permset; + int r; assert(fd >= 0); @@ -149,11 +161,12 @@ static int fix_acl(int fd, uid_t uid) { } if (acl_get_permset(entry, &permset) < 0 || - acl_add_perm(permset, ACL_READ) < 0 || - calc_acl_mask_if_needed(&acl) < 0) { - log_warning_errno(errno, "Failed to patch ACL: %m"); - return -errno; - } + acl_add_perm(permset, ACL_READ) < 0) + return log_warning_errno(errno, "Failed to patch ACL: %m"); + + r = calc_acl_mask_if_needed(&acl); + if (r < 0) + return log_warning_errno(r, "Failed to patch ACL: %m"); if (acl_set_fd(fd, acl) < 0) return log_error_errno(errno, "Failed to apply ACL: %m"); diff --git a/src/journal/coredumpctl.c b/src/journal/coredumpctl.c index 6628e82421..1df28d774a 100644 --- a/src/journal/coredumpctl.c +++ b/src/journal/coredumpctl.c @@ -19,27 +19,33 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fcntl.h> +#include <getopt.h> #include <locale.h> #include <stdio.h> #include <string.h> -#include <getopt.h> -#include <fcntl.h> #include <unistd.h> #include "sd-journal.h" -#include "build.h" -#include "set.h" -#include "util.h" + +#include "alloc-util.h" +#include "compress.h" +#include "fd-util.h" +#include "fileio.h" +#include "journal-internal.h" #include "log.h" -#include "path-util.h" -#include "pager.h" #include "macro.h" -#include "journal-internal.h" -#include "compress.h" -#include "sigbus.h" +#include "pager.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" -#include "terminal-util.h" +#include "set.h" +#include "sigbus.h" #include "signal-util.h" +#include "string-util.h" +#include "terminal-util.h" +#include "user-util.h" +#include "util.h" static enum { ACTION_NONE, @@ -84,37 +90,35 @@ static Set *new_matches(void) { } static int add_match(Set *set, const char *match) { - int r = -ENOMEM; - unsigned pid; - const char* prefix; - char *pattern = NULL; _cleanup_free_ char *p = NULL; + char *pattern = NULL; + const char* prefix; + pid_t pid; + int r; if (strchr(match, '=')) prefix = ""; else if (strchr(match, '/')) { - p = path_make_absolute_cwd(match); - if (!p) + r = path_make_absolute_cwd(match, &p); + if (r < 0) goto fail; - match = p; prefix = "COREDUMP_EXE="; - } - else if (safe_atou(match, &pid) == 0) + } else if (parse_pid(match, &pid) >= 0) prefix = "COREDUMP_PID="; else prefix = "COREDUMP_COMM="; pattern = strjoin(prefix, match, NULL); - if (!pattern) + if (!pattern) { + r = -ENOMEM; goto fail; + } log_debug("Adding pattern: %s", pattern); r = set_consume(set, pattern); - if (r < 0) { - log_error_errno(r, "Failed to add pattern: %m"); + if (r < 0) goto fail; - } return 0; fail: @@ -175,9 +179,7 @@ static int parse_argv(int argc, char *argv[], Set *matches) { case ARG_VERSION: arg_action = ACTION_NONE; - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; @@ -615,7 +617,7 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) { fdt = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC); if (fdt < 0) - return log_error_errno(errno, "Failed to create temporary file: %m"); + return log_error_errno(fdt, "Failed to create temporary file: %m"); log_debug("Created temporary file %s", temp); fd = fdt; @@ -774,7 +776,7 @@ static int run_gdb(sd_journal *j) { r = wait_for_terminate(pid, &st); if (r < 0) { - log_error_errno(errno, "Failed to wait for gdb: %m"); + log_error_errno(r, "Failed to wait for gdb: %m"); goto finish; } diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h index 150d034828..5959b1fed2 100644 --- a/src/journal/fsprg.h +++ b/src/journal/fsprg.h @@ -29,6 +29,7 @@ #include <inttypes.h> #include "macro.h" +#include "util.h" #ifdef __cplusplus extern "C" { diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index cdc80e2d26..0c4ac5cdc3 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -22,10 +22,12 @@ #include <fcntl.h> #include <sys/mman.h> +#include "fd-util.h" +#include "fsprg.h" +#include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" -#include "journal-authenticate.h" -#include "fsprg.h" +#include "hexdecoct.h" static uint64_t journal_file_tag_seqnum(JournalFile *f) { uint64_t r; diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h index 39c9dd0dbf..c003ac05dd 100644 --- a/src/journal/journal-def.h +++ b/src/journal/journal-def.h @@ -21,11 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sparse-endian.h" - -#include "systemd/sd-id128.h" +#include "sd-id128.h" #include "macro.h" +#include "sparse-endian.h" /* * If you change this file you probably should also change its documentation: diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 73d3a4bb9d..f9ff9545dd 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -19,22 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/mman.h> #include <errno.h> -#include <sys/uio.h> -#include <unistd.h> -#include <sys/statvfs.h> #include <fcntl.h> -#include <stddef.h> #include <linux/fs.h> +#include <stddef.h> +#include <sys/mman.h> +#include <sys/statvfs.h> +#include <sys/uio.h> +#include <unistd.h> +#include "alloc-util.h" #include "btrfs-util.h" +#include "chattr-util.h" +#include "compress.h" +#include "fd-util.h" +#include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" -#include "journal-authenticate.h" #include "lookup3.h" -#include "compress.h" +#include "parse-util.h" #include "random-util.h" +#include "string-util.h" +#include "xattr-util.h" #define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem)) #define DEFAULT_FIELD_HASH_TABLE_SIZE (333ULL*sizeof(HashItem)) @@ -42,13 +48,16 @@ #define COMPRESSION_SIZE_THRESHOLD (512ULL) /* This is the minimum journal file size */ -#define JOURNAL_FILE_SIZE_MIN (4ULL*1024ULL*1024ULL) /* 4 MiB */ +#define JOURNAL_FILE_SIZE_MIN (512ULL*1024ULL) /* 512 KiB */ /* These are the lower and upper bounds if we deduce the max_use value * from the file system size */ #define DEFAULT_MAX_USE_LOWER (1ULL*1024ULL*1024ULL) /* 1 MiB */ #define DEFAULT_MAX_USE_UPPER (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ +/* This is the default minimal use limit, how much we'll use even if keep_free suggests otherwise. */ +#define DEFAULT_MIN_USE (1ULL*1024ULL*1024ULL) /* 1 MiB */ + /* This is the upper bound if we deduce max_size from max_use */ #define DEFAULT_MAX_SIZE_UPPER (128ULL*1024ULL*1024ULL) /* 128 MiB */ @@ -60,6 +69,9 @@ * size */ #define DEFAULT_KEEP_FREE (1024ULL*1024ULL) /* 1 MB */ +/* This is the default maximum number of journal files to keep around. */ +#define DEFAULT_N_MAX_FILES (100) + /* n_data was the first entry we added after the initial file format design */ #define HEADER_SIZE_MIN ALIGN64(offsetof(Header, n_data)) @@ -128,7 +140,7 @@ int journal_file_set_offline(JournalFile *f) { return 0; } -void journal_file_close(JournalFile *f) { +JournalFile* journal_file_close(JournalFile *f) { assert(f); #ifdef HAVE_GCRYPT @@ -179,6 +191,7 @@ void journal_file_close(JournalFile *f) { #endif free(f); + return NULL; } static int journal_file_init_header(JournalFile *f, JournalFile *template) { @@ -398,12 +411,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) if (fstatvfs(f->fd, &svfs) >= 0) { uint64_t available; - available = svfs.f_bfree * svfs.f_bsize; - - if (available >= f->metrics.keep_free) - available -= f->metrics.keep_free; - else - available = 0; + available = LESS_BY((uint64_t) svfs.f_bfree * (uint64_t) svfs.f_bsize, f->metrics.keep_free); if (new_size - old_size > available) return -E2BIG; @@ -604,10 +612,10 @@ static int journal_file_setup_data_hash_table(JournalFile *f) { assert(f); - /* We estimate that we need 1 hash table entry per 768 of - journal file and we want to make sure we never get beyond - 75% fill level. Calculate the hash table size for the - maximum file size based on these metrics. */ + /* We estimate that we need 1 hash table entry per 768 bytes + of journal file and we want to make sure we never get + beyond 75% fill level. Calculate the hash table size for + the maximum file size based on these metrics. */ s = (f->metrics.max_size * 4 / 768 / 3) * sizeof(HashItem); if (s < DEFAULT_DATA_HASH_TABLE_SIZE) @@ -1055,7 +1063,7 @@ static int journal_file_append_data( r = journal_file_find_data_object_with_hash(f, data, size, hash, &o, &p); if (r < 0) return r; - else if (r > 0) { + if (r > 0) { if (ret) *ret = o; @@ -1074,23 +1082,24 @@ static int journal_file_append_data( o->data.hash = htole64(hash); #if defined(HAVE_XZ) || defined(HAVE_LZ4) - if (f->compress_xz && - size >= COMPRESSION_SIZE_THRESHOLD) { + if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { size_t rsize = 0; compression = compress_blob(data, size, o->data.payload, &rsize); - if (compression) { + if (compression >= 0) { o->object.size = htole64(offsetof(Object, data.payload) + rsize); o->object.flags |= compression; log_debug("Compressed data object %"PRIu64" -> %zu using %s", size, rsize, object_compressed_to_string(compression)); - } + } else + /* Compression didn't work, we don't really care why, let's continue without compression */ + compression = 0; } #endif - if (!compression && size > 0) + if (compression == 0 && size > 0) memcpy(o->data.payload, data, size); r = journal_file_link_data(f, o, p, hash); @@ -2696,7 +2705,7 @@ int journal_file_open( } if (f->last_stat.st_size < (off_t) HEADER_SIZE_MIN) { - r = -EIO; + r = -ENODATA; goto fail; } @@ -2833,8 +2842,7 @@ int journal_file_open_reliably( size_t l; _cleanup_free_ char *p = NULL; - r = journal_file_open(fname, flags, mode, compress, seal, - metrics, mmap_cache, template, ret); + r = journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); if (!IN_SET(r, -EBADMSG, /* corrupted */ -ENODATA, /* truncated */ @@ -2864,8 +2872,7 @@ int journal_file_open_reliably( random_u64()) < 0) return -ENOMEM; - r = rename(fname, p); - if (r < 0) + if (rename(fname, p) < 0) return -errno; /* btrfs doesn't cope well with our write pattern and @@ -2874,10 +2881,9 @@ int journal_file_open_reliably( (void) chattr_path(p, false, FS_NOCOW_FL); (void) btrfs_defrag(p); - log_warning("File %s corrupted or uncleanly shut down, renaming and replacing.", fname); + log_warning_errno(r, "File %s corrupted or uncleanly shut down, renaming and replacing.", fname); - return journal_file_open(fname, flags, mode, compress, seal, - metrics, mmap_cache, template, ret); + return journal_file_open(fname, flags, mode, compress, seal, metrics, mmap_cache, template, ret); } int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p, uint64_t *seqnum, Object **ret, uint64_t *offset) { @@ -2964,16 +2970,35 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 return r; } +void journal_reset_metrics(JournalMetrics *m) { + assert(m); + + /* Set everything to "pick automatic values". */ + + *m = (JournalMetrics) { + .min_use = (uint64_t) -1, + .max_use = (uint64_t) -1, + .min_size = (uint64_t) -1, + .max_size = (uint64_t) -1, + .keep_free = (uint64_t) -1, + .n_max_files = (uint64_t) -1, + }; +} + void journal_default_metrics(JournalMetrics *m, int fd) { - uint64_t fs_size = 0; + char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX], e[FORMAT_BYTES_MAX]; struct statvfs ss; - char a[FORMAT_BYTES_MAX], b[FORMAT_BYTES_MAX], c[FORMAT_BYTES_MAX], d[FORMAT_BYTES_MAX]; + uint64_t fs_size; assert(m); assert(fd >= 0); if (fstatvfs(fd, &ss) >= 0) fs_size = ss.f_frsize * ss.f_blocks; + else { + log_debug_errno(errno, "Failed to detremine disk size: %m"); + fs_size = 0; + } if (m->max_use == (uint64_t) -1) { @@ -2990,10 +3015,16 @@ void journal_default_metrics(JournalMetrics *m, int fd) { } else { m->max_use = PAGE_ALIGN(m->max_use); - if (m->max_use < JOURNAL_FILE_SIZE_MIN*2) + if (m->max_use != 0 && m->max_use < JOURNAL_FILE_SIZE_MIN*2) m->max_use = JOURNAL_FILE_SIZE_MIN*2; } + if (m->min_use == (uint64_t) -1) + m->min_use = DEFAULT_MIN_USE; + + if (m->min_use > m->max_use) + m->min_use = m->max_use; + if (m->max_size == (uint64_t) -1) { m->max_size = PAGE_ALIGN(m->max_use / 8); /* 8 chunks */ @@ -3002,11 +3033,13 @@ void journal_default_metrics(JournalMetrics *m, int fd) { } else m->max_size = PAGE_ALIGN(m->max_size); - if (m->max_size < JOURNAL_FILE_SIZE_MIN) - m->max_size = JOURNAL_FILE_SIZE_MIN; + if (m->max_size != 0) { + if (m->max_size < JOURNAL_FILE_SIZE_MIN) + m->max_size = JOURNAL_FILE_SIZE_MIN; - if (m->max_size*2 > m->max_use) - m->max_use = m->max_size*2; + if (m->max_use != 0 && m->max_size*2 > m->max_use) + m->max_use = m->max_size*2; + } if (m->min_size == (uint64_t) -1) m->min_size = JOURNAL_FILE_SIZE_MIN; @@ -3016,7 +3049,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) { if (m->min_size < JOURNAL_FILE_SIZE_MIN) m->min_size = JOURNAL_FILE_SIZE_MIN; - if (m->min_size > m->max_size) + if (m->max_size != 0 && m->min_size > m->max_size) m->max_size = m->min_size; } @@ -3032,11 +3065,16 @@ void journal_default_metrics(JournalMetrics *m, int fd) { m->keep_free = DEFAULT_KEEP_FREE; } - log_debug("Fixed max_use=%s max_size=%s min_size=%s keep_free=%s", - format_bytes(a, sizeof(a), m->max_use), - format_bytes(b, sizeof(b), m->max_size), - format_bytes(c, sizeof(c), m->min_size), - format_bytes(d, sizeof(d), m->keep_free)); + if (m->n_max_files == (uint64_t) -1) + m->n_max_files = DEFAULT_N_MAX_FILES; + + log_debug("Fixed min_use=%s max_use=%s max_size=%s min_size=%s keep_free=%s n_max_files=%" PRIu64, + format_bytes(a, sizeof(a), m->min_use), + format_bytes(b, sizeof(b), m->max_use), + format_bytes(c, sizeof(c), m->max_size), + format_bytes(d, sizeof(d), m->min_size), + format_bytes(e, sizeof(e), m->keep_free), + m->n_max_files); } int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) { diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index e92b75eabe..898d12d992 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -36,11 +36,13 @@ #include "hashmap.h" typedef struct JournalMetrics { - uint64_t max_use; - uint64_t use; - uint64_t max_size; - uint64_t min_size; - uint64_t keep_free; + /* For all these: -1 means "pick automatically", and 0 means "no limit enforced" */ + uint64_t max_size; /* how large journal files grow at max */ + uint64_t min_size; /* how large journal files grow at least */ + uint64_t max_use; /* how much disk space to use in total at max, keep_free permitting */ + uint64_t min_use; /* how much disk space to use in total at least, even if keep_free says not to */ + uint64_t keep_free; /* how much to keep free on disk */ + uint64_t n_max_files; /* how many files to keep around at max */ } JournalMetrics; typedef enum direction { @@ -136,7 +138,7 @@ int journal_file_open( JournalFile **ret); int journal_file_set_offline(JournalFile *f); -void journal_file_close(JournalFile *j); +JournalFile* journal_file_close(JournalFile *j); int journal_file_open_reliably( const char *fname, @@ -223,6 +225,7 @@ int journal_file_rotate(JournalFile **f, bool compress, bool seal); void journal_file_post_change(JournalFile *f); +void journal_reset_metrics(JournalMetrics *m); void journal_default_metrics(JournalMetrics *m, int fd); int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to); @@ -232,3 +235,8 @@ bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec); int journal_file_map_data_hash_table(JournalFile *f); int journal_file_map_field_hash_table(JournalFile *f); + +static inline bool JOURNAL_FILE_COMPRESS(JournalFile *f) { + assert(f); + return f->compress_xz || f->compress_lz4; +} diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h index b51ecdb600..06847402e0 100644 --- a/src/journal/journal-internal.h +++ b/src/journal/journal-internal.h @@ -25,14 +25,14 @@ #include <inttypes.h> #include <stdbool.h> -#include "systemd/sd-id128.h" +#include "sd-id128.h" +#include "sd-journal.h" +#include "hashmap.h" #include "journal-def.h" +#include "journal-file.h" #include "list.h" -#include "hashmap.h" #include "set.h" -#include "journal-file.h" -#include "sd-journal.h" typedef struct Match Match; typedef struct Location Location; @@ -121,7 +121,7 @@ struct sd_journal { Hashmap *directories_by_path; Hashmap *directories_by_wd; - Set *errors; + Hashmap *errors; }; char *journal_make_match_string(sd_journal *j); diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h index 3ff6a3ad4a..7d14e8754b 100644 --- a/src/journal/journal-qrcode.h +++ b/src/journal/journal-qrcode.h @@ -21,8 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <stdio.h> -#include "systemd/sd-id128.h" +#include "sd-id128.h" int print_qr_code(FILE *f, const void *seed, size_t seed_size, uint64_t start, uint64_t interval, const char *hn, sd_id128_t machine); diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index 1e3a463504..fa5dee73c3 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -19,20 +19,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <sys/un.h> #include <errno.h> -#include <stddef.h> -#include <unistd.h> #include <fcntl.h> #include <printf.h> +#include <stddef.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <unistd.h> #define SD_JOURNAL_SUPPRESS_LOCATION #include "sd-journal.h" -#include "util.h" -#include "socket-util.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "io-util.h" #include "memfd-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "util.h" #define SNDBUF_SIZE (8*1024*1024) @@ -212,11 +219,6 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path), }; ssize_t k; - union { - struct cmsghdr cmsghdr; - uint8_t buf[CMSG_SPACE(sizeof(int))]; - } control; - struct cmsghdr *cmsg; bool have_syslog_identifier = false; bool seal = true; @@ -335,26 +337,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { return r; } - mh.msg_iov = NULL; - mh.msg_iovlen = 0; - - zero(control); - mh.msg_control = &control; - mh.msg_controllen = sizeof(control); - - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &buffer_fd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - k = sendmsg(fd, &mh, MSG_NOSIGNAL); - if (k < 0) - return -errno; - - return 0; + return send_one_fd(fd, buffer_fd, 0); } static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) { diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c index 17499bbc30..4b5fc76eb1 100644 --- a/src/journal/journal-vacuum.c +++ b/src/journal/journal-vacuum.c @@ -23,20 +23,27 @@ #include <sys/stat.h> #include <unistd.h> +#include "sd-id128.h" + +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "journal-def.h" #include "journal-file.h" #include "journal-vacuum.h" -#include "sd-id128.h" +#include "parse-util.h" +#include "string-util.h" #include "util.h" +#include "xattr-util.h" struct vacuum_info { uint64_t usage; char *filename; uint64_t realtime; + sd_id128_t seqnum_id; uint64_t seqnum; - bool have_seqnum; }; @@ -67,19 +74,18 @@ static int vacuum_compare(const void *_a, const void *_b) { } static void patch_realtime( - const char *dir, + int fd, const char *fn, const struct stat *st, unsigned long long *realtime) { - _cleanup_free_ char *path = NULL; usec_t x, crtime = 0; /* The timestamp was determined by the file name, but let's * see if the file might actually be older than the file name * suggested... */ - assert(dir); + assert(fd >= 0); assert(fn); assert(st); assert(realtime); @@ -101,14 +107,7 @@ static void patch_realtime( * unfortunately there's currently no sane API to query * it. Hence let's implement this manually... */ - /* Unfortunately there is is not fgetxattrat(), so we need to - * go via path here. :-( */ - - path = strjoin(dir, "/", fn, NULL); - if (!path) - return; - - if (path_getcrtime(path, &crtime) >= 0) { + if (fd_getcrtime_at(fd, fn, &crtime, 0) >= 0) { if (crtime < *realtime) *realtime = crtime; } @@ -120,9 +119,13 @@ static int journal_file_empty(int dir_fd, const char *name) { le64_t n_entries; ssize_t n; - fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); - if (fd < 0) - return -errno; + fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK|O_NOATIME); + if (fd < 0) { + /* Maybe failed due to O_NOATIME and lack of privileges? */ + fd = openat(dir_fd, name, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); + if (fd < 0) + return -errno; + } if (fstat(fd, &st) < 0) return -errno; @@ -144,22 +147,24 @@ static int journal_file_empty(int dir_fd, const char *name) { int journal_directory_vacuum( const char *directory, uint64_t max_use, + uint64_t n_max_files, usec_t max_retention_usec, usec_t *oldest_usec, bool verbose) { _cleanup_closedir_ DIR *d = NULL; - int r = 0; struct vacuum_info *list = NULL; - unsigned n_list = 0, i; + unsigned n_list = 0, i, n_active_files = 0; size_t n_allocated = 0; uint64_t sum = 0, freed = 0; usec_t retention_limit = 0; char sbytes[FORMAT_BYTES_MAX]; + struct dirent *de; + int r; assert(directory); - if (max_use <= 0 && max_retention_usec <= 0) + if (max_use <= 0 && max_retention_usec <= 0 && n_max_files <= 0) return 0; if (max_retention_usec > 0) { @@ -174,27 +179,20 @@ int journal_directory_vacuum( if (!d) return -errno; - for (;;) { - struct dirent *de; - size_t q; - struct stat st; - char *p; + FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) { + unsigned long long seqnum = 0, realtime; + _cleanup_free_ char *p = NULL; sd_id128_t seqnum_id; bool have_seqnum; + uint64_t size; + struct stat st; + size_t q; - errno = 0; - de = readdir(d); - if (!de && errno != 0) { - r = -errno; - goto finish; - } - - if (!de) - break; - - if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { + log_debug_errno(errno, "Failed to stat file %s while vacuuming, ignoring: %m", de->d_name); continue; + } if (!S_ISREG(st.st_mode)) continue; @@ -203,15 +201,20 @@ int journal_directory_vacuum( if (endswith(de->d_name, ".journal")) { - /* Vacuum archived files */ + /* Vacuum archived files. Active files are + * left around */ - if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) + if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) { + n_active_files++; continue; + } if (de->d_name[q-8-16-1] != '-' || de->d_name[q-8-16-1-16-1] != '-' || - de->d_name[q-8-16-1-16-1-32-1] != '@') + de->d_name[q-8-16-1-16-1-32-1] != '@') { + n_active_files++; continue; + } p = strdup(de->d_name); if (!p) { @@ -221,12 +224,12 @@ int journal_directory_vacuum( de->d_name[q-8-16-1-16-1] = 0; if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) { - free(p); + n_active_files++; continue; } if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) { - free(p); + n_active_files++; continue; } @@ -237,12 +240,16 @@ int journal_directory_vacuum( /* Vacuum corrupted files */ - if (q < 1 + 16 + 1 + 16 + 8 + 1) + if (q < 1 + 16 + 1 + 16 + 8 + 1) { + n_active_files ++; continue; + } if (de->d_name[q-1-8-16-1] != '-' || - de->d_name[q-1-8-16-1-16-1] != '@') + de->d_name[q-1-8-16-1-16-1] != '@') { + n_active_files ++; continue; + } p = strdup(de->d_name); if (!p) { @@ -251,55 +258,68 @@ int journal_directory_vacuum( } if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) { - free(p); + n_active_files ++; continue; } have_seqnum = false; - } else - /* We do not vacuum active files or unknown files! */ + } else { + /* We do not vacuum unknown files! */ + log_debug("Not vacuuming unknown file %s.", de->d_name); continue; + } - if (journal_file_empty(dirfd(d), p)) { - /* Always vacuum empty non-online files. */ + size = 512UL * (uint64_t) st.st_blocks; - uint64_t size = 512UL * (uint64_t) st.st_blocks; + r = journal_file_empty(dirfd(d), p); + if (r < 0) { + log_debug_errno(r, "Failed check if %s is empty, ignoring: %m", p); + continue; + } + if (r > 0) { + /* Always vacuum empty non-online files. */ if (unlinkat(dirfd(d), p, 0) >= 0) { - log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size)); + + log_full(verbose ? LOG_INFO : LOG_DEBUG, + "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size)); + freed += size; } else if (errno != ENOENT) log_warning_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory, p); - free(p); continue; } - patch_realtime(directory, p, &st, &realtime); + patch_realtime(dirfd(d), p, &st, &realtime); if (!GREEDY_REALLOC(list, n_allocated, n_list + 1)) { - free(p); r = -ENOMEM; goto finish; } list[n_list].filename = p; - list[n_list].usage = 512UL * (uint64_t) st.st_blocks; + list[n_list].usage = size; list[n_list].seqnum = seqnum; list[n_list].realtime = realtime; list[n_list].seqnum_id = seqnum_id; list[n_list].have_seqnum = have_seqnum; - - sum += list[n_list].usage; - n_list ++; + + p = NULL; + sum += size; } qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare); for (i = 0; i < n_list; i++) { + unsigned left; + + left = n_active_files + n_list - i; + if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) && - (max_use <= 0 || sum <= max_use)) + (max_use <= 0 || sum <= max_use) && + (n_max_files <= 0 || left <= n_max_files)) break; if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) { @@ -318,6 +338,8 @@ int journal_directory_vacuum( if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec)) *oldest_usec = list[i].realtime; + r = 0; + finish: for (i = 0; i < n_list; i++) free(list[i].filename); diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h index c45cc31d0e..49ab90af91 100644 --- a/src/journal/journal-vacuum.h +++ b/src/journal/journal-vacuum.h @@ -21,5 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> +#include <stdbool.h> -int journal_directory_vacuum(const char *directory, uint64_t max_use, usec_t max_retention_usec, usec_t *oldest_usec, bool vacuum); +#include "time-util.h" + +int journal_directory_vacuum(const char *directory, uint64_t max_use, uint64_t n_max_files, usec_t max_retention_usec, usec_t *oldest_usec, bool verbose); diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 32d59c716f..3676cb8788 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -24,15 +24,18 @@ #include <fcntl.h> #include <stddef.h> -#include "util.h" -#include "macro.h" +#include "alloc-util.h" +#include "compress.h" +#include "fd-util.h" +#include "fileio.h" +#include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" -#include "journal-authenticate.h" #include "journal-verify.h" #include "lookup3.h" -#include "compress.h" +#include "macro.h" #include "terminal-util.h" +#include "util.h" static void draw_progress(uint64_t p, usec_t *last_usec) { unsigned n, i, j, k; @@ -839,19 +842,19 @@ int journal_file_verify( data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (data_fd < 0) { - r = log_error_errno(errno, "Failed to create data file: %m"); + r = log_error_errno(data_fd, "Failed to create data file: %m"); goto fail; } entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_fd < 0) { - r = log_error_errno(errno, "Failed to create entry file: %m"); + r = log_error_errno(entry_fd, "Failed to create entry file: %m"); goto fail; } entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC); if (entry_array_fd < 0) { - r = log_error_errno(errno, + r = log_error_errno(entry_array_fd, "Failed to create entry array file: %m"); goto fail; } @@ -897,7 +900,7 @@ int journal_file_verify( r = journal_file_object_verify(f, p, o); if (r < 0) { - error(p, "Envalid object contents: %s", strerror(-r)); + error(p, "Invalid object contents: %s", strerror(-r)); goto fail; } diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index b38b151485..277adba904 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -19,48 +19,58 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <locale.h> +#include <errno.h> #include <fcntl.h> #include <fnmatch.h> -#include <errno.h> +#include <getopt.h> +#include <linux/fs.h> +#include <locale.h> +#include <poll.h> +#include <signal.h> #include <stddef.h> -#include <string.h> #include <stdio.h> -#include <unistd.h> #include <stdlib.h> -#include <getopt.h> -#include <signal.h> -#include <poll.h> -#include <sys/stat.h> +#include <string.h> #include <sys/inotify.h> -#include <linux/fs.h> +#include <sys/stat.h> +#include <unistd.h> -#include "sd-journal.h" #include "sd-bus.h" -#include "log.h" -#include "logs-show.h" -#include "util.h" +#include "sd-journal.h" + #include "acl-util.h" -#include "path-util.h" +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" +#include "catalog.h" +#include "chattr-util.h" +#include "fd-util.h" #include "fileio.h" -#include "build.h" -#include "pager.h" -#include "strv.h" -#include "set.h" -#include "sigbus.h" -#include "journal-internal.h" +#include "fs-util.h" +#include "fsprg.h" +#include "glob-util.h" +#include "hostname-util.h" +#include "io-util.h" #include "journal-def.h" -#include "journal-verify.h" +#include "journal-internal.h" #include "journal-qrcode.h" #include "journal-vacuum.h" -#include "fsprg.h" -#include "unit-name.h" -#include "catalog.h" +#include "journal-verify.h" +#include "locale-util.h" +#include "log.h" +#include "logs-show.h" #include "mkdir.h" -#include "bus-util.h" -#include "bus-error.h" +#include "pager.h" +#include "parse-util.h" +#include "path-util.h" +#include "rlimit-util.h" +#include "set.h" +#include "sigbus.h" +#include "strv.h" +#include "syslog-util.h" #include "terminal-util.h" -#include "hostname-util.h" +#include "unit-name.h" +#include "user-util.h" #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE) @@ -105,10 +115,11 @@ static const char *arg_field = NULL; static bool arg_catalog = false; static bool arg_reverse = false; static int arg_journal_type = 0; -static const char *arg_root = NULL; +static char *arg_root = NULL; static const char *arg_machine = NULL; -static uint64_t arg_vacuum_size = (uint64_t) -1; -static usec_t arg_vacuum_time = USEC_INFINITY; +static uint64_t arg_vacuum_size = 0; +static uint64_t arg_vacuum_n_files = 0; +static usec_t arg_vacuum_time = 0; static enum { ACTION_SHOW, @@ -122,6 +133,7 @@ static enum { ACTION_UPDATE_CATALOG, ACTION_LIST_BOOTS, ACTION_FLUSH, + ACTION_ROTATE, ACTION_VACUUM, } arg_action = ACTION_SHOW; @@ -193,8 +205,8 @@ static void help(void) { " --system Show the system journal\n" " --user Show the user journal for the current user\n" " -M --machine=CONTAINER Operate on local container\n" - " --since=DATE Show entries not older than the specified date\n" - " --until=DATE Show entries not newer than the specified date\n" + " -S --since=DATE Show entries not older than the specified date\n" + " -U --until=DATE Show entries not newer than the specified date\n" " -c --cursor=CURSOR Show entries starting at the specified cursor\n" " --after-cursor=CURSOR Show entries after the specified cursor\n" " --show-cursor Print the cursor after all the entries\n" @@ -217,7 +229,7 @@ static void help(void) { " -x --catalog Add message explanations where available\n" " --no-full Ellipsize fields\n" " -a --all Show all fields, including long and unprintable\n" - " -q --quiet Do not show privilege warning\n" + " -q --quiet Do not show info messages and privilege warning\n" " --no-pager Do not pipe output into a pager\n" " -m --merge Show entries from all available journals\n" " -D --directory=PATH Show journal files from directory\n" @@ -235,8 +247,10 @@ static void help(void) { " --new-id128 Generate a new 128-bit ID\n" " --disk-usage Show total disk usage of all journal files\n" " --vacuum-size=BYTES Reduce disk usage below specified size\n" - " --vacuum-time=TIME Remove journal files older than specified date\n" + " --vacuum-files=INT Leave only the specified number of journal files\n" + " --vacuum-time=TIME Remove journal files older than specified time\n" " --flush Flush all journal data from /run into /var\n" + " --rotate Request immediate rotation of the journal files\n" " --header Show journal header information\n" " --list-catalog Show all message IDs in the catalog\n" " --dump-catalog Show entries in the message catalog\n" @@ -267,8 +281,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERIFY, ARG_VERIFY_KEY, ARG_DISK_USAGE, - ARG_SINCE, - ARG_UNTIL, ARG_AFTER_CURSOR, ARG_SHOW_CURSOR, ARG_USER_UNIT, @@ -278,7 +290,9 @@ static int parse_argv(int argc, char *argv[]) { ARG_FORCE, ARG_UTC, ARG_FLUSH, + ARG_ROTATE, ARG_VACUUM_SIZE, + ARG_VACUUM_FILES, ARG_VACUUM_TIME, }; @@ -318,8 +332,8 @@ static int parse_argv(int argc, char *argv[]) { { "cursor", required_argument, NULL, 'c' }, { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR }, { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR }, - { "since", required_argument, NULL, ARG_SINCE }, - { "until", required_argument, NULL, ARG_UNTIL }, + { "since", required_argument, NULL, 'S' }, + { "until", required_argument, NULL, 'U' }, { "unit", required_argument, NULL, 'u' }, { "user-unit", required_argument, NULL, ARG_USER_UNIT }, { "field", required_argument, NULL, 'F' }, @@ -331,7 +345,9 @@ static int parse_argv(int argc, char *argv[]) { { "machine", required_argument, NULL, 'M' }, { "utc", no_argument, NULL, ARG_UTC }, { "flush", no_argument, NULL, ARG_FLUSH }, + { "rotate", no_argument, NULL, ARG_ROTATE }, { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE }, + { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES }, { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME }, {} }; @@ -341,7 +357,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:t:u:F:xrM:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0) switch (c) { @@ -350,9 +366,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; @@ -502,7 +516,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - arg_root = optarg; + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case 'c': @@ -539,6 +555,16 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_VACUUM; break; + case ARG_VACUUM_FILES: + r = safe_atou64(optarg, &arg_vacuum_n_files); + if (r < 0) { + log_error("Failed to parse vacuum files: %s", optarg); + return r; + } + + arg_action = ACTION_VACUUM; + break; + case ARG_VACUUM_TIME: r = parse_sec(optarg, &arg_vacuum_time); if (r < 0) { @@ -631,7 +657,7 @@ static int parse_argv(int argc, char *argv[]) { break; } - case ARG_SINCE: + case 'S': r = parse_timestamp(optarg, &arg_since); if (r < 0) { log_error("Failed to parse timestamp: %s", optarg); @@ -640,7 +666,7 @@ static int parse_argv(int argc, char *argv[]) { arg_since_set = true; break; - case ARG_UNTIL: + case 'U': r = parse_timestamp(optarg, &arg_until); if (r < 0) { log_error("Failed to parse timestamp: %s", optarg); @@ -699,6 +725,10 @@ static int parse_argv(int argc, char *argv[]) { arg_action = ACTION_FLUSH; break; + case ARG_ROTATE: + arg_action = ACTION_ROTATE; + break; + case '?': return -EINVAL; @@ -729,7 +759,7 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } - if (arg_action != ACTION_SHOW && optind < argc) { + if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) { log_error("Extraneous arguments starting with '%s'", argv[optind]); return -EINVAL; } @@ -1453,7 +1483,7 @@ static int setup_keys(void) { safe_close(fd); fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC); if (fd < 0) { - r = log_error_errno(errno, "Failed to open %s: %m", k); + r = log_error_errno(fd, "Failed to open %s: %m", k); goto finish; } @@ -1461,7 +1491,7 @@ static int setup_keys(void) { * writing and in-place updating */ r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL); if (r < 0) - log_warning_errno(errno, "Failed to set file attributes: %m"); + log_warning_errno(r, "Failed to set file attributes: %m"); zero(h); memcpy(h.signature, "KSHHRHLP", 8); @@ -1580,7 +1610,7 @@ static int verify(sd_journal *j) { /* If the key was invalid give up right-away. */ return k; } else if (k < 0) { - log_warning("FAIL: %s (%s)", f->path, strerror(-k)); + log_warning_errno(k, "FAIL: %s (%m)", f->path); r = k; } else { char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX]; @@ -1678,36 +1708,50 @@ static int access_check_var_log_journal(sd_journal *j) { static int access_check(sd_journal *j) { Iterator it; void *code; + char *path; int r = 0; assert(j); - if (set_isempty(j->errors)) { + if (hashmap_isempty(j->errors)) { if (ordered_hashmap_isempty(j->files)) log_notice("No journal files were found."); return 0; } - if (set_contains(j->errors, INT_TO_PTR(-EACCES))) { + if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) { (void) access_check_var_log_journal(j); if (ordered_hashmap_isempty(j->files)) r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions."); } - SET_FOREACH(code, j->errors, it) { + HASHMAP_FOREACH_KEY(path, code, j->errors, it) { int err; - err = -PTR_TO_INT(code); - assert(err > 0); + err = abs(PTR_TO_INT(code)); - if (err == EACCES) + switch (err) { + case EACCES: continue; - log_warning_errno(err, "Error was encountered while opening journal files: %m"); - if (r == 0) - r = -err; + case ENODATA: + log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path); + break; + + case EPROTONOSUPPORT: + log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path); + break; + + case EBADMSG: + log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path); + break; + + default: + log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path); + break; + } } return r; @@ -1725,7 +1769,7 @@ static int flush_to_var(void) { /* OK, let's actually do the full logic, send SIGUSR1 to the * daemon and set up inotify to wait for the flushed file to appear */ - r = bus_open_system_systemd(&bus); + r = bus_connect_system_systemd(&bus); if (r < 0) return log_error_errno(r, "Failed to get D-Bus connection: %m"); @@ -1772,6 +1816,30 @@ static int flush_to_var(void) { return 0; } +static int rotate(void) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + int r; + + r = bus_connect_system_systemd(&bus); + if (r < 0) + return log_error_errno(r, "Failed to get D-Bus connection: %m"); + + r = sd_bus_call_method( + bus, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "KillUnit", + &error, + NULL, + "ssi", "systemd-journald.service", "main", SIGUSR2); + if (r < 0) + return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r)); + + return 0; +} + int main(int argc, char *argv[]) { int r; _cleanup_journal_close_ sd_journal *j = NULL; @@ -1807,6 +1875,11 @@ int main(int argc, char *argv[]) { goto finish; } + if (arg_action == ACTION_ROTATE) { + r = rotate(); + goto finish; + } + if (arg_action == ACTION_SETUP_KEYS) { r = setup_keys(); goto finish; @@ -1831,6 +1904,7 @@ int main(int argc, char *argv[]) { } else { bool oneline = arg_action == ACTION_LIST_CATALOG; + pager_open_if_enabled(); if (optind < argc) r = catalog_list_items(stdout, database, oneline, argv + optind); @@ -1895,9 +1969,9 @@ int main(int argc, char *argv[]) { if (d->is_root) continue; - q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_time, NULL, true); + q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, true); if (q < 0) { - log_error_errno(q, "Failed to vacuum: %m"); + log_error_errno(q, "Failed to vacuum %s: %m", d->path); r = q; } } @@ -2200,5 +2274,7 @@ finish: strv_free(arg_system_units); strv_free(arg_user_units); + free(arg_root); + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index fe8ae194c9..3c13fe0d67 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -19,9 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "missing.h" -#include "journald-audit.h" +#include "alloc-util.h" #include "audit-type.h" +#include "fd-util.h" +#include "hexdecoct.h" +#include "io-util.h" +#include "journald-audit.h" +#include "missing.h" +#include "string-util.h" typedef struct MapField { const char *audit_field; diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c index 307bdc3949..89f3d4b42f 100644 --- a/src/journal/journald-console.c +++ b/src/journal/journald-console.c @@ -23,11 +23,16 @@ #include <fcntl.h> #include <sys/socket.h> +#include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" -#include "journald-server.h" -#include "journald-console.h" #include "formats-util.h" +#include "io-util.h" +#include "journald-console.h" +#include "journald-server.h" +#include "parse-util.h" #include "process-util.h" +#include "stdio-util.h" #include "terminal-util.h" static bool prefix_timestamp(void) { @@ -101,7 +106,7 @@ void server_forward_console( fd = open_terminal(tty, O_WRONLY|O_NOCTTY|O_CLOEXEC); if (fd < 0) { - log_debug_errno(errno, "Failed to open %s for logging: %m", tty); + log_debug_errno(fd, "Failed to open %s for logging: %m", tty); return; } diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf index bf7c773009..c154610c54 100644 --- a/src/journal/journald-gperf.gperf +++ b/src/journal/journald-gperf.gperf @@ -24,9 +24,11 @@ Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_li Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use) Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size) Journal.SystemKeepFree, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.keep_free) +Journal.SystemMaxFiles, config_parse_uint64, 0, offsetof(Server, system_metrics.n_max_files) Journal.RuntimeMaxUse, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.max_use) Journal.RuntimeMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.max_size) Journal.RuntimeKeepFree, config_parse_iec_uint64, 0, offsetof(Server, runtime_metrics.keep_free) +Journal.RuntimeMaxFiles, config_parse_uint64, 0, offsetof(Server, runtime_metrics.n_max_files) Journal.MaxRetentionSec, config_parse_sec, 0, offsetof(Server, max_retention_usec) Journal.MaxFileSec, config_parse_sec, 0, offsetof(Server, max_file_usec) Journal.ForwardToSyslog, config_parse_bool, 0, offsetof(Server, forward_to_syslog) diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index 51fe3aa50a..e048e04716 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -19,20 +19,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <sys/epoll.h> #include <fcntl.h> +#include <sys/epoll.h> #include <sys/mman.h> #include <sys/socket.h> +#include <unistd.h> -#include "systemd/sd-messages.h" -#include <libudev.h> +#include "libudev.h" +#include "sd-messages.h" -#include "journald-server.h" +#include "escape.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" #include "journald-kmsg.h" +#include "journald-server.h" #include "journald-syslog.h" -#include "formats-util.h" +#include "parse-util.h" #include "process-util.h" +#include "stdio-util.h" +#include "string-util.h" void server_forward_kmsg( Server *s, @@ -341,8 +347,7 @@ static int server_read_dev_kmsg(Server *s) { if (errno == EAGAIN || errno == EINTR || errno == EPIPE) return 0; - log_error_errno(errno, "Failed to read from kernel: %m"); - return -errno; + return log_error_errno(errno, "Failed to read from kernel: %m"); } dev_kmsg_record(s, buffer, l); @@ -436,6 +441,7 @@ fail: int server_open_kernel_seqnum(Server *s) { _cleanup_close_ int fd; uint64_t *p; + int r; assert(s); @@ -449,8 +455,9 @@ int server_open_kernel_seqnum(Server *s) { return 0; } - if (posix_fallocate(fd, 0, sizeof(uint64_t)) < 0) { - log_error_errno(errno, "Failed to allocate sequential number file, ignoring: %m"); + r = posix_fallocate(fd, 0, sizeof(uint64_t)); + if (r != 0) { + log_error_errno(r, "Failed to allocate sequential number file, ignoring: %m"); return 0; } diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 3e8a7a05f6..1e3774dafb 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -19,21 +19,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <stddef.h> #include <sys/epoll.h> #include <sys/mman.h> +#include <unistd.h> -#include "socket-util.h" -#include "path-util.h" -#include "selinux-util.h" -#include "journald-server.h" -#include "journald-native.h" -#include "journald-kmsg.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "io-util.h" #include "journald-console.h" +#include "journald-kmsg.h" +#include "journald-native.h" +#include "journald-server.h" #include "journald-syslog.h" #include "journald-wall.h" #include "memfd-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "string-util.h" bool valid_user_field(const char *p, size_t l, bool allow_protected) { const char *a; @@ -338,7 +344,7 @@ void server_process_native_file( r = readlink_malloc(sl, &k); if (r < 0) { - log_error_errno(errno, "readlink(%s) failed: %m", sl); + log_error_errno(r, "readlink(%s) failed: %m", sl); return; } @@ -407,7 +413,7 @@ void server_process_native_file( n = pread(fd, p, st.st_size, 0); if (n < 0) - log_error_errno(n, "Failed to read file, ignoring: %m"); + log_error_errno(errno, "Failed to read file, ignoring: %m"); else if (n > 0) server_process_native_message(s, p, n, ucred, tv, label, label_len); } diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c index 6f83035a4e..434ddc8ac9 100644 --- a/src/journal/journald-rate-limit.c +++ b/src/journal/journald-rate-limit.c @@ -19,14 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> +#include <string.h> -#include "journald-rate-limit.h" -#include "list.h" -#include "util.h" +#include "alloc-util.h" #include "hashmap.h" +#include "list.h" #include "random-util.h" +#include "string-util.h" +#include "util.h" +#include "journald-rate-limit.h" #define POOLS_MAX 5 #define BUCKETS_MAX 127 @@ -57,7 +59,7 @@ struct JournalRateLimitGroup { char *id; JournalRateLimitPool pools[POOLS_MAX]; - unsigned long hash; + uint64_t hash; LIST_FIELDS(JournalRateLimitGroup, bucket); LIST_FIELDS(JournalRateLimitGroup, lru); @@ -145,6 +147,7 @@ static void journal_rate_limit_vacuum(JournalRateLimit *r, usec_t ts) { static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, const char *id, usec_t ts) { JournalRateLimitGroup *g; + struct siphash state; assert(r); assert(id); @@ -157,7 +160,9 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, if (!g->id) goto fail; - g->hash = string_hash_func(g->id, r->hash_key); + siphash24_init(&state, r->hash_key); + string_hash_func(g->id, &state); + siphash24_finalize((uint8_t*)&g->hash, &state); journal_rate_limit_vacuum(r, ts); @@ -204,9 +209,10 @@ static unsigned burst_modulate(unsigned burst, uint64_t available) { } int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, uint64_t available) { - unsigned long h; + uint64_t h; JournalRateLimitGroup *g; JournalRateLimitPool *p; + struct siphash state; unsigned burst; usec_t ts; @@ -222,7 +228,9 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u ts = now(CLOCK_MONOTONIC); - h = string_hash_func(id, r->hash_key); + siphash24_init(&state, r->hash_key); + string_hash_func(id, &state); + siphash24_finalize((uint8_t*)&h, &state); g = r->buckets[h % BUCKETS_MAX]; LIST_FOREACH(bucket, g, g) diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index fa2e9b9825..7a70dcbc57 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -19,45 +19,55 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/signalfd.h> -#include <sys/ioctl.h> -#include <linux/sockios.h> -#include <sys/statvfs.h> -#include <sys/mman.h> - #ifdef HAVE_SELINUX #include <selinux/selinux.h> #endif +#include <sys/ioctl.h> +#include <sys/mman.h> +#include <sys/signalfd.h> +#include <sys/statvfs.h> +#include <linux/sockios.h> -#include <libudev.h> - +#include "libudev.h" +#include "sd-daemon.h" #include "sd-journal.h" #include "sd-messages.h" -#include "sd-daemon.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "hashmap.h" -#include "journal-file.h" -#include "socket-util.h" + +#include "acl-util.h" +#include "alloc-util.h" +#include "audit-util.h" #include "cgroup-util.h" -#include "missing.h" #include "conf-parser.h" -#include "selinux-util.h" -#include "acl-util.h" +#include "dirent-util.h" +#include "extract-word.h" +#include "fd-util.h" #include "formats-util.h" -#include "process-util.h" +#include "fs-util.h" +#include "hashmap.h" #include "hostname-util.h" -#include "signal-util.h" +#include "io-util.h" +#include "journal-authenticate.h" +#include "journal-file.h" #include "journal-internal.h" #include "journal-vacuum.h" -#include "journal-authenticate.h" -#include "journald-rate-limit.h" +#include "journald-audit.h" #include "journald-kmsg.h" -#include "journald-syslog.h" -#include "journald-stream.h" #include "journald-native.h" -#include "journald-audit.h" +#include "journald-rate-limit.h" #include "journald-server.h" +#include "journald-stream.h" +#include "journald-syslog.h" +#include "missing.h" +#include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "rm-rf.h" +#include "selinux-util.h" +#include "signal-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "string-util.h" #define USER_JOURNALS_MAX 1024 @@ -66,88 +76,63 @@ #define DEFAULT_RATE_LIMIT_BURST 1000 #define DEFAULT_MAX_FILE_USEC USEC_PER_MONTH -#define RECHECK_AVAILABLE_SPACE_USEC (30*USEC_PER_SEC) +#define RECHECK_SPACE_USEC (30*USEC_PER_SEC) -static const char* const storage_table[_STORAGE_MAX] = { - [STORAGE_AUTO] = "auto", - [STORAGE_VOLATILE] = "volatile", - [STORAGE_PERSISTENT] = "persistent", - [STORAGE_NONE] = "none" -}; - -DEFINE_STRING_TABLE_LOOKUP(storage, Storage); -DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting"); - -static const char* const split_mode_table[_SPLIT_MAX] = { - [SPLIT_LOGIN] = "login", - [SPLIT_UID] = "uid", - [SPLIT_NONE] = "none", -}; - -DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode); -DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting"); +#define NOTIFY_SNDBUF_SIZE (8*1024*1024) -static uint64_t available_space(Server *s, bool verbose) { - char ids[33]; - _cleanup_free_ char *p = NULL; - sd_id128_t machine; - struct statvfs ss; - uint64_t sum = 0, ss_avail = 0, avail = 0; - int r; +static int determine_space_for( + Server *s, + JournalMetrics *metrics, + const char *path, + const char *name, + bool verbose, + bool patch_min_use, + uint64_t *available, + uint64_t *limit) { + + uint64_t sum = 0, ss_avail, avail; _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + struct statvfs ss; + const char *p; usec_t ts; - const char *f; - JournalMetrics *m; - - ts = now(CLOCK_MONOTONIC); - if (s->cached_available_space_timestamp + RECHECK_AVAILABLE_SPACE_USEC > ts - && !verbose) - return s->cached_available_space; + assert(s); + assert(metrics); + assert(path); + assert(name); - r = sd_id128_get_machine(&machine); - if (r < 0) - return 0; + ts = now(CLOCK_MONOTONIC); - if (s->system_journal) { - f = "/var/log/journal/"; - m = &s->system_metrics; - } else { - f = "/run/log/journal/"; - m = &s->runtime_metrics; - } + if (!verbose && s->cached_space_timestamp + RECHECK_SPACE_USEC > ts) { - assert(m); + if (available) + *available = s->cached_space_available; + if (limit) + *limit = s->cached_space_limit; - p = strappend(f, sd_id128_to_string(machine, ids)); - if (!p) return 0; + } + p = strjoina(path, SERVER_MACHINE_ID(s)); d = opendir(p); if (!d) - return 0; + return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open %s: %m", p); if (fstatvfs(dirfd(d), &ss) < 0) - return 0; + return log_error_errno(errno, "Failed to fstatvfs(%s): %m", p); - for (;;) { + FOREACH_DIRENT_ALL(de, d, break) { struct stat st; - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return 0; - - if (!de) - break; if (!endswith(de->d_name, ".journal") && !endswith(de->d_name, ".journal~")) continue; - if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { + log_debug_errno(errno, "Failed to stat %s/%s, ignoring: %m", p, de->d_name); continue; + } if (!S_ISREG(st.st_mode)) continue; @@ -155,45 +140,72 @@ static uint64_t available_space(Server *s, bool verbose) { sum += (uint64_t) st.st_blocks * 512UL; } - ss_avail = ss.f_bsize * ss.f_bavail; - - /* If we reached a high mark, we will always allow this much - * again, unless usage goes above max_use. This watermark - * value is cached so that we don't give up space on pressure, - * but hover below the maximum usage. */ + /* If request, then let's bump the min_use limit to the + * current usage on disk. We do this when starting up and + * first opening the journal files. This way sudden spikes in + * disk usage will not cause journald to vacuum files without + * bounds. Note that this means that only a restart of + * journald will make it reset this value. */ - if (m->use < sum) - m->use = sum; + if (patch_min_use) + metrics->min_use = MAX(metrics->min_use, sum); - avail = LESS_BY(ss_avail, m->keep_free); + ss_avail = ss.f_bsize * ss.f_bavail; + avail = LESS_BY(ss_avail, metrics->keep_free); - s->cached_available_space = LESS_BY(MIN(m->max_use, avail), sum); - s->cached_available_space_timestamp = ts; + s->cached_space_limit = MIN(MAX(sum + avail, metrics->min_use), metrics->max_use); + s->cached_space_available = LESS_BY(s->cached_space_limit, sum); + s->cached_space_timestamp = ts; if (verbose) { char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX], - fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX]; + fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX], fb6[FORMAT_BYTES_MAX]; server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE, - "%s is currently using %s.\n" + "%s (%s) is currently using %s.\n" "Maximum allowed usage is set to %s.\n" "Leaving at least %s free (of currently available %s of space).\n" - "Enforced usage limit is thus %s.", - s->system_journal ? "Permanent journal (/var/log/journal/)" : "Runtime journal (/run/log/journal/)", + "Enforced usage limit is thus %s, of which %s are still available.", + name, path, format_bytes(fb1, sizeof(fb1), sum), - format_bytes(fb2, sizeof(fb2), m->max_use), - format_bytes(fb3, sizeof(fb3), m->keep_free), + format_bytes(fb2, sizeof(fb2), metrics->max_use), + format_bytes(fb3, sizeof(fb3), metrics->keep_free), format_bytes(fb4, sizeof(fb4), ss_avail), - format_bytes(fb5, sizeof(fb5), s->cached_available_space + sum)); + format_bytes(fb5, sizeof(fb5), s->cached_space_limit), + format_bytes(fb6, sizeof(fb6), s->cached_space_available)); } - return s->cached_available_space; + if (available) + *available = s->cached_space_available; + if (limit) + *limit = s->cached_space_limit; + + return 1; +} + +static int determine_space(Server *s, bool verbose, bool patch_min_use, uint64_t *available, uint64_t *limit) { + JournalMetrics *metrics; + const char *path, *name; + + assert(s); + + if (s->system_journal) { + path = "/var/log/journal/"; + metrics = &s->system_metrics; + name = "System journal"; + } else { + path = "/run/log/journal/"; + metrics = &s->runtime_metrics; + name = "Runtime journal"; + } + + return determine_space_for(s, metrics, path, name, verbose, patch_min_use, available, limit); } void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { int r; #ifdef HAVE_ACL - acl_t acl; + _cleanup_(acl_freep) acl_t acl = NULL; acl_entry_t entry; acl_permset_t permset; #endif @@ -202,7 +214,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { r = fchmod(f->fd, 0640); if (r < 0) - log_warning_errno(r, "Failed to fix access mode on %s, ignoring: %m", f->path); + log_warning_errno(errno, "Failed to fix access mode on %s, ignoring: %m", f->path); #ifdef HAVE_ACL if (uid <= SYSTEM_UID_MAX) @@ -221,24 +233,27 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { acl_set_tag_type(entry, ACL_USER) < 0 || acl_set_qualifier(entry, &uid) < 0) { log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); - goto finish; + return; } } /* We do not recalculate the mask unconditionally here, * so that the fchmod() mask above stays intact. */ if (acl_get_permset(entry, &permset) < 0 || - acl_add_perm(permset, ACL_READ) < 0 || - calc_acl_mask_if_needed(&acl) < 0) { + acl_add_perm(permset, ACL_READ) < 0) { log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); - goto finish; + return; + } + + r = calc_acl_mask_if_needed(&acl); + if (r < 0) { + log_warning_errno(r, "Failed to patch ACL on %s, ignoring: %m", f->path); + return; } if (acl_set_fd(f->fd, acl) < 0) log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path); -finish: - acl_free(acl); #endif } @@ -328,8 +343,8 @@ void server_rotate(Server *s) { log_debug("Rotating..."); - do_rotate(s, &s->runtime_journal, "runtime", false, 0); - do_rotate(s, &s->system_journal, "system", s->seal, 0); + (void) do_rotate(s, &s->runtime_journal, "runtime", false, 0); + (void) do_rotate(s, &s->system_journal, "system", s->seal, 0); ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { r = do_rotate(s, &f, "user", s->seal, PTR_TO_UINT32(k)); @@ -350,13 +365,13 @@ void server_sync(Server *s) { if (s->system_journal) { r = journal_file_set_offline(s->system_journal); if (r < 0) - log_error_errno(r, "Failed to sync system journal: %m"); + log_warning_errno(r, "Failed to sync system journal, ignoring: %m"); } ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { r = journal_file_set_offline(f); if (r < 0) - log_error_errno(r, "Failed to sync user journal: %m"); + log_warning_errno(r, "Failed to sync user journal, ignoring: %m"); } if (s->sync_event_source) { @@ -370,43 +385,50 @@ void server_sync(Server *s) { static void do_vacuum( Server *s, - const char *id, JournalFile *f, - const char* path, - JournalMetrics *metrics) { + JournalMetrics *metrics, + const char *path, + const char *name, + bool verbose, + bool patch_min_use) { const char *p; + uint64_t limit; int r; + assert(s); + assert(metrics); + assert(path); + assert(name); + if (!f) return; - p = strjoina(path, id); - r = journal_directory_vacuum(p, metrics->max_use, s->max_retention_usec, &s->oldest_file_usec, false); + p = strjoina(path, SERVER_MACHINE_ID(s)); + + limit = metrics->max_use; + (void) determine_space_for(s, metrics, path, name, verbose, patch_min_use, NULL, &limit); + + r = journal_directory_vacuum(p, limit, metrics->n_max_files, s->max_retention_usec, &s->oldest_file_usec, verbose); if (r < 0 && r != -ENOENT) - log_error_errno(r, "Failed to vacuum %s: %m", p); + log_warning_errno(r, "Failed to vacuum %s, ignoring: %m", p); } -void server_vacuum(Server *s) { - char ids[33]; - sd_id128_t machine; - int r; +int server_vacuum(Server *s, bool verbose, bool patch_min_use) { + assert(s); log_debug("Vacuuming..."); s->oldest_file_usec = 0; - r = sd_id128_get_machine(&machine); - if (r < 0) { - log_error_errno(r, "Failed to get machine ID: %m"); - return; - } - sd_id128_to_string(machine, ids); + do_vacuum(s, s->system_journal, &s->system_metrics, "/var/log/journal/", "System journal", verbose, patch_min_use); + do_vacuum(s, s->runtime_journal, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", verbose, patch_min_use); - do_vacuum(s, ids, s->system_journal, "/var/log/journal/", &s->system_metrics); - do_vacuum(s, ids, s->runtime_journal, "/run/log/journal/", &s->runtime_metrics); + s->cached_space_limit = 0; + s->cached_space_available = 0; + s->cached_space_timestamp = 0; - s->cached_available_space_timestamp = 0; + return 0; } static void server_cache_machine_id(Server *s) { @@ -504,7 +526,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned if (journal_file_rotate_suggested(f, s->max_file_usec)) { log_debug("%s: Journal header limits reached or header out-of-date, rotating.", f->path); server_rotate(s); - server_vacuum(s); + server_vacuum(s, false, false); vacuumed = true; f = find_journal(s, uid); @@ -524,7 +546,7 @@ static void write_to_journal(Server *s, uid_t uid, struct iovec *iovec, unsigned } server_rotate(s); - server_vacuum(s); + server_vacuum(s, false, false); f = find_journal(s, uid); if (!f) @@ -825,7 +847,7 @@ static void dispatch_message_real( void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) { char mid[11 + 32 + 1]; char buffer[16 + LINE_MAX + 1]; - struct iovec iovec[N_IOVEC_META_FIELDS + 4]; + struct iovec iovec[N_IOVEC_META_FIELDS + 6]; int n = 0; va_list ap; struct ucred ucred = {}; @@ -833,6 +855,9 @@ void server_driver_message(Server *s, sd_id128_t message_id, const char *format, assert(s); assert(format); + IOVEC_SET_STRING(iovec[n++], "SYSLOG_FACILITY=3"); + IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=systemd-journald"); + IOVEC_SET_STRING(iovec[n++], "PRIORITY=6"); IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver"); @@ -866,6 +891,7 @@ void server_dispatch_message( int rl, r; _cleanup_free_ char *path = NULL; + uint64_t available = 0; char *c; assert(s); @@ -905,9 +931,8 @@ void server_dispatch_message( } } - rl = journal_rate_limit_test(s->rate_limit, path, - priority & LOG_PRIMASK, available_space(s, false)); - + (void) determine_space(s, false, false, &available, NULL); + rl = journal_rate_limit_test(s->rate_limit, path, priority & LOG_PRIMASK, available); if (rl == 0) return; @@ -922,16 +947,8 @@ finish: static int system_journal_open(Server *s, bool flush_requested) { - int r; - char *fn; - sd_id128_t machine; - char ids[33]; - - r = sd_id128_get_machine(&machine); - if (r < 0) - return log_error_errno(r, "Failed to get machine id: %m"); - - sd_id128_to_string(machine, ids); + const char *fn; + int r = 0; if (!s->system_journal && (s->storage == STORAGE_PERSISTENT || s->storage == STORAGE_AUTO) && @@ -947,15 +964,15 @@ static int system_journal_open(Server *s, bool flush_requested) { if (s->storage == STORAGE_PERSISTENT) (void) mkdir_p("/var/log/journal/", 0755); - fn = strjoina("/var/log/journal/", ids); + fn = strjoina("/var/log/journal/", SERVER_MACHINE_ID(s)); (void) mkdir(fn, 0755); fn = strjoina(fn, "/system.journal"); r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal); - - if (r >= 0) + if (r >= 0) { server_fix_perms(s, s->system_journal, 0); - else if (r < 0) { + (void) determine_space_for(s, &s->system_metrics, "/var/log/journal/", "System journal", true, true, NULL, NULL); + } else if (r < 0) { if (r != -ENOENT && r != -EROFS) log_warning_errno(r, "Failed to open system journal: %m"); @@ -966,9 +983,7 @@ static int system_journal_open(Server *s, bool flush_requested) { if (!s->runtime_journal && (s->storage != STORAGE_NONE)) { - fn = strjoin("/run/log/journal/", ids, "/system.journal", NULL); - if (!fn) - return -ENOMEM; + fn = strjoina("/run/log/journal/", SERVER_MACHINE_ID(s), "/system.journal"); if (s->system_journal) { @@ -977,8 +992,6 @@ static int system_journal_open(Server *s, bool flush_requested) { * it into the system journal */ r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); - free(fn); - if (r < 0) { if (r != -ENOENT) log_warning_errno(r, "Failed to open runtime journal: %m"); @@ -996,18 +1009,16 @@ static int system_journal_open(Server *s, bool flush_requested) { (void) mkdir_parents(fn, 0750); r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); - free(fn); - if (r < 0) return log_error_errno(r, "Failed to open runtime journal: %m"); } - if (s->runtime_journal) + if (s->runtime_journal) { server_fix_perms(s, s->runtime_journal, 0); + (void) determine_space_for(s, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", true, true, NULL, NULL); + } } - available_space(s, true); - return r; } @@ -1028,7 +1039,7 @@ int server_flush_to_var(Server *s) { if (!s->runtime_journal) return 0; - system_journal_open(s, true); + (void) system_journal_open(s, true); if (!s->system_journal) return 0; @@ -1072,7 +1083,7 @@ int server_flush_to_var(Server *s) { } server_rotate(s); - server_vacuum(s); + server_vacuum(s, false, false); if (!s->system_journal) { log_notice("Didn't flush runtime journal since rotation of system journal wasn't successful."); @@ -1088,11 +1099,12 @@ int server_flush_to_var(Server *s) { } } + r = 0; + finish: journal_file_post_change(s->system_journal); - journal_file_close(s->runtime_journal); - s->runtime_journal = NULL; + s->runtime_journal = journal_file_close(s->runtime_journal); if (r >= 0) (void) rm_rf("/run/log/journal", REMOVE_ROOT); @@ -1235,9 +1247,9 @@ static int dispatch_sigusr1(sd_event_source *es, const struct signalfd_siginfo * server_flush_to_var(s); server_sync(s); - server_vacuum(s); + server_vacuum(s, false, false); - touch("/run/systemd/journal/flushed"); + (void) touch("/run/systemd/journal/flushed"); return 0; } @@ -1249,7 +1261,7 @@ static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo * log_info("Received request to rotate journal from PID %"PRIu32, si->ssi_pid); server_rotate(s); - server_vacuum(s); + server_vacuum(s, true, true); return 0; } @@ -1293,8 +1305,7 @@ static int setup_signals(Server *s) { static int server_parse_proc_cmdline(Server *s) { _cleanup_free_ char *line = NULL; - const char *w, *state; - size_t l; + const char *p; int r; r = proc_cmdline(&line); @@ -1303,12 +1314,16 @@ static int server_parse_proc_cmdline(Server *s) { return 0; } - FOREACH_WORD_QUOTED(w, l, line, state) { + p = line; + for(;;) { _cleanup_free_ char *word; - word = strndup(w, l); - if (!word) - return -ENOMEM; + r = extract_first_word(&p, &word, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse journald syntax \"%s\": %m", line); + + if (r == 0) + break; if (startswith(word, "systemd.journald.forward_to_syslog=")) { r = parse_boolean(word + 35); @@ -1337,8 +1352,8 @@ static int server_parse_proc_cmdline(Server *s) { } else if (startswith(word, "systemd.journald")) log_warning("Invalid systemd.journald parameter. Ignoring."); } - /* do not warn about state here, since probably systemd already did */ + /* do not warn about state here, since probably systemd already did */ return 0; } @@ -1434,8 +1449,7 @@ static int server_open_hostname(Server *s) { /* kernels prior to 3.2 don't support polling this file. Ignore * the failure. */ if (r == -EPERM) { - log_warning("Failed to register hostname fd in event loop: %s. Ignoring.", - strerror(-r)); + log_warning_errno(r, "Failed to register hostname fd in event loop, ignoring: %m"); s->hostname_fd = safe_close(s->hostname_fd); return 0; } @@ -1450,17 +1464,189 @@ static int server_open_hostname(Server *s) { return 0; } +static int dispatch_notify_event(sd_event_source *es, int fd, uint32_t revents, void *userdata) { + Server *s = userdata; + int r; + + assert(s); + assert(s->notify_event_source == es); + assert(s->notify_fd == fd); + + if (revents != EPOLLOUT) { + log_error("Invalid events on notify file descriptor."); + return -EINVAL; + } + + /* The $NOTIFY_SOCKET is writable again, now send exactly one + * message on it. Either it's the wtachdog event, the initial + * READY=1 event or an stdout stream event. If there's nothing + * to write anymore, turn our event source off. The next time + * there's something to send it will be turned on again. */ + + if (!s->sent_notify_ready) { + static const char p[] = + "READY=1\n" + "STATUS=Processing requests..."; + ssize_t l; + + l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); + if (l < 0) { + if (errno == EAGAIN) + return 0; + + return log_error_errno(errno, "Failed to send READY=1 notification message: %m"); + } + + s->sent_notify_ready = true; + log_debug("Sent READY=1 notification."); + + } else if (s->send_watchdog) { + + static const char p[] = + "WATCHDOG=1"; + + ssize_t l; + + l = send(s->notify_fd, p, strlen(p), MSG_DONTWAIT); + if (l < 0) { + if (errno == EAGAIN) + return 0; + + return log_error_errno(errno, "Failed to send WATCHDOG=1 notification message: %m"); + } + + s->send_watchdog = false; + log_debug("Sent WATCHDOG=1 notification."); + + } else if (s->stdout_streams_notify_queue) + /* Dispatch one stream notification event */ + stdout_stream_send_notify(s->stdout_streams_notify_queue); + + /* Leave us enabled if there's still more to to do. */ + if (s->send_watchdog || s->stdout_streams_notify_queue) + return 0; + + /* There was nothing to do anymore, let's turn ourselves off. */ + r = sd_event_source_set_enabled(es, SD_EVENT_OFF); + if (r < 0) + return log_error_errno(r, "Failed to turn off notify event source: %m"); + + return 0; +} + +static int dispatch_watchdog(sd_event_source *es, uint64_t usec, void *userdata) { + Server *s = userdata; + int r; + + assert(s); + + s->send_watchdog = true; + + r = sd_event_source_set_enabled(s->notify_event_source, SD_EVENT_ON); + if (r < 0) + log_warning_errno(r, "Failed to turn on notify event source: %m"); + + r = sd_event_source_set_time(s->watchdog_event_source, usec + s->watchdog_usec / 2); + if (r < 0) + return log_error_errno(r, "Failed to restart watchdog event source: %m"); + + r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ON); + if (r < 0) + return log_error_errno(r, "Failed to enable watchdog event source: %m"); + + return 0; +} + +static int server_connect_notify(Server *s) { + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + }; + const char *e; + int r; + + assert(s); + assert(s->notify_fd < 0); + assert(!s->notify_event_source); + + /* + So here's the problem: we'd like to send notification + messages to PID 1, but we cannot do that via sd_notify(), + since that's synchronous, and we might end up blocking on + it. Specifically: given that PID 1 might block on + dbus-daemon during IPC, and dbus-daemon is logging to us, + and might hence block on us, we might end up in a deadlock + if we block on sending PID 1 notification messages -- by + generating a full blocking circle. To avoid this, let's + create a non-blocking socket, and connect it to the + notification socket, and then wait for POLLOUT before we + send anything. This should efficiently avoid any deadlocks, + as we'll never block on PID 1, hence PID 1 can safely block + on dbus-daemon which can safely block on us again. + + Don't think that this issue is real? It is, see: + https://github.com/systemd/systemd/issues/1505 + */ + + e = getenv("NOTIFY_SOCKET"); + if (!e) + return 0; + + if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { + log_error("NOTIFY_SOCKET set to an invalid value: %s", e); + return -EINVAL; + } + + if (strlen(e) > sizeof(sa.un.sun_path)) { + log_error("NOTIFY_SOCKET path too long: %s", e); + return -EINVAL; + } + + s->notify_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (s->notify_fd < 0) + return log_error_errno(errno, "Failed to create notify socket: %m"); + + (void) fd_inc_sndbuf(s->notify_fd, NOTIFY_SNDBUF_SIZE); + + strncpy(sa.un.sun_path, e, sizeof(sa.un.sun_path)); + if (sa.un.sun_path[0] == '@') + sa.un.sun_path[0] = 0; + + r = connect(s->notify_fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(e)); + if (r < 0) + return log_error_errno(errno, "Failed to connect to notify socket: %m"); + + r = sd_event_add_io(s->event, &s->notify_event_source, s->notify_fd, EPOLLOUT, dispatch_notify_event, s); + if (r < 0) + return log_error_errno(r, "Failed to watch notification socket: %m"); + + if (sd_watchdog_enabled(false, &s->watchdog_usec) > 0) { + s->send_watchdog = true; + + r = sd_event_add_time(s->event, &s->watchdog_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + s->watchdog_usec/2, s->watchdog_usec*3/4, dispatch_watchdog, s); + if (r < 0) + return log_error_errno(r, "Failed to add watchdog time event: %m"); + } + + /* This should fire pretty soon, which we'll use to send the + * READY=1 event. */ + + return 0; +} + int server_init(Server *s) { _cleanup_fdset_free_ FDSet *fds = NULL; int n, r, fd; + bool no_sockets; assert(s); zero(*s); - s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = -1; + s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1; s->compress = true; s->seal = true; + s->watchdog_usec = USEC_INFINITY; + s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC; s->sync_scheduled = false; @@ -1477,18 +1663,19 @@ int server_init(Server *s) { s->max_level_console = LOG_INFO; s->max_level_wall = LOG_EMERG; - memset(&s->system_metrics, 0xFF, sizeof(s->system_metrics)); - memset(&s->runtime_metrics, 0xFF, sizeof(s->runtime_metrics)); + journal_reset_metrics(&s->system_metrics); + journal_reset_metrics(&s->runtime_metrics); server_parse_config_file(s); server_parse_proc_cmdline(s); + if (!!s->rate_limit_interval ^ !!s->rate_limit_burst) { log_debug("Setting both rate limit interval and burst from "USEC_FMT",%u to 0,0", s->rate_limit_interval, s->rate_limit_burst); s->rate_limit_interval = s->rate_limit_burst = 0; } - mkdir_p("/run/systemd/journal", 0755); + (void) mkdir_p("/run/systemd/journal", 0755); s->user_journals = ordered_hashmap_new(NULL); if (!s->user_journals) @@ -1502,8 +1689,6 @@ int server_init(Server *s) { if (r < 0) return log_error_errno(r, "Failed to create event loop: %m"); - sd_event_set_watchdog(s->event, true); - n = sd_listen_fds(true); if (n < 0) return log_error_errno(n, "Failed to read listening file descriptors from environment: %m"); @@ -1561,30 +1746,44 @@ int server_init(Server *s) { } } - r = server_open_stdout_socket(s, fds); - if (r < 0) - return r; + /* Try to restore streams, but don't bother if this fails */ + (void) server_restore_streams(s, fds); if (fdset_size(fds) > 0) { log_warning("%u unknown file descriptors passed, closing.", fdset_size(fds)); fds = fdset_free(fds); } + no_sockets = s->native_fd < 0 && s->stdout_fd < 0 && s->syslog_fd < 0 && s->audit_fd < 0; + + /* always open stdout, syslog, native, and kmsg sockets */ + + /* systemd-journald.socket: /run/systemd/journal/stdout */ + r = server_open_stdout_socket(s); + if (r < 0) + return r; + + /* systemd-journald-dev-log.socket: /run/systemd/journal/dev-log */ r = server_open_syslog_socket(s); if (r < 0) return r; + /* systemd-journald.socket: /run/systemd/journal/socket */ r = server_open_native_socket(s); if (r < 0) return r; + /* /dev/ksmg */ r = server_open_dev_kmsg(s); if (r < 0) return r; - r = server_open_audit(s); - if (r < 0) - return r; + /* Unless we got *some* sockets and not audit, open audit socket */ + if (s->audit_fd >= 0 || no_sockets) { + r = server_open_audit(s); + if (r < 0) + return r; + } r = server_open_kernel_seqnum(s); if (r < 0) @@ -1614,11 +1813,9 @@ int server_init(Server *s) { server_cache_boot_id(s); server_cache_machine_id(s); - r = system_journal_open(s, false); - if (r < 0) - return r; + (void) server_connect_notify(s); - return 0; + return system_journal_open(s, false); } void server_maybe_append_tags(Server *s) { @@ -1666,6 +1863,8 @@ void server_done(Server *s) { sd_event_source_unref(s->sigterm_event_source); sd_event_source_unref(s->sigint_event_source); sd_event_source_unref(s->hostname_event_source); + sd_event_source_unref(s->notify_event_source); + sd_event_source_unref(s->watchdog_event_source); sd_event_unref(s->event); safe_close(s->syslog_fd); @@ -1674,6 +1873,7 @@ void server_done(Server *s) { safe_close(s->dev_kmsg_fd); safe_close(s->audit_fd); safe_close(s->hostname_fd); + safe_close(s->notify_fd); if (s->rate_limit) journal_rate_limit_free(s->rate_limit); @@ -1691,3 +1891,22 @@ void server_done(Server *s) { udev_unref(s->udev); } + +static const char* const storage_table[_STORAGE_MAX] = { + [STORAGE_AUTO] = "auto", + [STORAGE_VOLATILE] = "volatile", + [STORAGE_PERSISTENT] = "persistent", + [STORAGE_NONE] = "none" +}; + +DEFINE_STRING_TABLE_LOOKUP(storage, Storage); +DEFINE_CONFIG_PARSE_ENUM(config_parse_storage, storage, Storage, "Failed to parse storage setting"); + +static const char* const split_mode_table[_SPLIT_MAX] = { + [SPLIT_LOGIN] = "login", + [SPLIT_UID] = "uid", + [SPLIT_NONE] = "none", +}; + +DEFINE_STRING_TABLE_LOOKUP(split_mode, SplitMode); +DEFINE_CONFIG_PARSE_ENUM(config_parse_split_mode, split_mode, SplitMode, "Failed to parse split mode setting"); diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index d954c5190d..03a61bd2ed 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -25,10 +25,13 @@ #include <sys/types.h> #include "sd-event.h" -#include "journal-file.h" + +typedef struct Server Server; + #include "hashmap.h" -#include "audit.h" +#include "journal-file.h" #include "journald-rate-limit.h" +#include "journald-stream.h" #include "list.h" typedef enum Storage { @@ -48,15 +51,14 @@ typedef enum SplitMode { _SPLIT_INVALID = -1 } SplitMode; -typedef struct StdoutStream StdoutStream; - -typedef struct Server { +struct Server { int syslog_fd; int native_fd; int stdout_fd; int dev_kmsg_fd; int audit_fd; int hostname_fd; + int notify_fd; sd_event *event; @@ -71,6 +73,8 @@ typedef struct Server { sd_event_source *sigterm_event_source; sd_event_source *sigint_event_source; sd_event_source *hostname_event_source; + sd_event_source *notify_event_source; + sd_event_source *watchdog_event_source; JournalFile *runtime_journal; JournalFile *system_journal; @@ -100,8 +104,9 @@ typedef struct Server { unsigned n_forward_syslog_missed; usec_t last_warn_forward_syslog_missed; - uint64_t cached_available_space; - usec_t cached_available_space_timestamp; + uint64_t cached_space_available; + uint64_t cached_space_limit; + usec_t cached_space_timestamp; uint64_t var_available_timestamp; @@ -110,6 +115,7 @@ typedef struct Server { usec_t oldest_file_usec; LIST_HEAD(StdoutStream, stdout_streams); + LIST_HEAD(StdoutStream, stdout_streams_notify_queue); unsigned n_stdout_streams; char *tty_path; @@ -125,13 +131,14 @@ typedef struct Server { MMapCache *mmap; - bool dev_kmsg_readable; + struct udev *udev; uint64_t *kernel_seqnum; + bool dev_kmsg_readable:1; - struct udev *udev; - - bool sync_scheduled; + bool send_watchdog:1; + bool sent_notify_ready:1; + bool sync_scheduled:1; char machine_id_field[sizeof("_MACHINE_ID=") + 32]; char boot_id_field[sizeof("_BOOT_ID=") + 32]; @@ -139,7 +146,11 @@ typedef struct Server { /* Cached cgroup root, so that we don't have to query that all the time */ char *cgroup_root; -} Server; + + usec_t watchdog_usec; +}; + +#define SERVER_MACHINE_ID(s) ((s)->machine_id_field + strlen("_MACHINE_ID=")) #define N_IOVEC_META_FIELDS 20 #define N_IOVEC_KERNEL_FIELDS 64 @@ -166,7 +177,7 @@ void server_fix_perms(Server *s, JournalFile *f, uid_t uid); int server_init(Server *s); void server_done(Server *s); void server_sync(Server *s); -void server_vacuum(Server *s); +int server_vacuum(Server *s, bool verbose, bool patch_min_use); void server_rotate(Server *s); int server_schedule_sync(Server *s, int priority); int server_flush_to_var(Server *s); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 69e2d41863..fb800782fb 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -19,25 +19,35 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <stddef.h> +#include <unistd.h> #ifdef HAVE_SELINUX #include <selinux/selinux.h> #endif -#include "sd-event.h" #include "sd-daemon.h" -#include "socket-util.h" -#include "selinux-util.h" -#include "mkdir.h" +#include "sd-event.h" + +#include "alloc-util.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" +#include "journald-console.h" +#include "journald-kmsg.h" #include "journald-server.h" #include "journald-stream.h" #include "journald-syslog.h" -#include "journald-kmsg.h" -#include "journald-console.h" #include "journald-wall.h" +#include "mkdir.h" +#include "parse-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "syslog-util.h" #define STDOUT_STREAMS_MAX 4096 @@ -69,6 +79,7 @@ struct StdoutStream { bool forward_to_console:1; bool fdstore:1; + bool in_notify_queue:1; char buffer[LINE_MAX+1]; size_t length; @@ -78,6 +89,7 @@ struct StdoutStream { char *state_file; LIST_FIELDS(StdoutStream, stdout_stream); + LIST_FIELDS(StdoutStream, stdout_stream_notify_queue); }; void stdout_stream_free(StdoutStream *s) { @@ -88,6 +100,9 @@ void stdout_stream_free(StdoutStream *s) { assert(s->server->n_stdout_streams > 0); s->server->n_stdout_streams --; LIST_REMOVE(stdout_stream, s->server->stdout_streams, s); + + if (s->in_notify_queue) + LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); } if (s->event_source) { @@ -111,7 +126,7 @@ static void stdout_stream_destroy(StdoutStream *s) { return; if (s->state_file) - unlink(s->state_file); + (void) unlink(s->state_file); stdout_stream_free(s); } @@ -190,11 +205,15 @@ static int stdout_stream_save(StdoutStream *s) { goto fail; } - /* Store the connection fd in PID 1, so that we get it passed - * in again on next start */ - if (!s->fdstore) { - sd_pid_notify_with_fds(0, false, "FDSTORE=1", &s->fd, 1); - s->fdstore = true; + if (!s->fdstore && !s->in_notify_queue) { + LIST_PREPEND(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); + s->in_notify_queue = true; + + if (s->server->notify_event_source) { + r = sd_event_source_set_enabled(s->server->notify_event_source, SD_EVENT_ON); + if (r < 0) + log_warning_errno(r, "Failed to enable notify event source: %m"); + } } return 0; @@ -519,8 +538,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent if (errno == EAGAIN) return 0; - log_error_errno(errno, "Failed to accept stdout connection: %m"); - return -errno; + return log_error_errno(errno, "Failed to accept stdout connection: %m"); } if (s->n_stdout_streams >= STDOUT_STREAMS_MAX) { @@ -627,7 +645,7 @@ static int stdout_stream_restore(Server *s, const char *fname, int fd) { return 0; } -static int server_restore_streams(Server *s, FDSet *fds) { +int server_restore_streams(Server *s, FDSet *fds) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r; @@ -681,7 +699,7 @@ fail: return log_error_errno(errno, "Failed to read streams directory: %m"); } -int server_open_stdout_socket(Server *s, FDSet *fds) { +int server_open_stdout_socket(Server *s) { int r; assert(s); @@ -717,8 +735,52 @@ int server_open_stdout_socket(Server *s, FDSet *fds) { if (r < 0) return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m"); - /* Try to restore streams, but don't bother if this fails */ - (void) server_restore_streams(s, fds); - return 0; } + +void stdout_stream_send_notify(StdoutStream *s) { + struct iovec iovec = { + .iov_base = (char*) "FDSTORE=1", + .iov_len = strlen("FDSTORE=1"), + }; + struct msghdr msghdr = { + .msg_iov = &iovec, + .msg_iovlen = 1, + }; + struct cmsghdr *cmsg; + ssize_t l; + + assert(s); + assert(!s->fdstore); + assert(s->in_notify_queue); + assert(s->server); + assert(s->server->notify_fd >= 0); + + /* Store the connection fd in PID 1, so that we get it passed + * in again on next start */ + + msghdr.msg_controllen = CMSG_SPACE(sizeof(int)); + msghdr.msg_control = alloca0(msghdr.msg_controllen); + + cmsg = CMSG_FIRSTHDR(&msghdr); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + + memcpy(CMSG_DATA(cmsg), &s->fd, sizeof(int)); + + l = sendmsg(s->server->notify_fd, &msghdr, MSG_DONTWAIT|MSG_NOSIGNAL); + if (l < 0) { + if (errno == EAGAIN) + return; + + log_error_errno(errno, "Failed to send stream file descriptor to service manager: %m"); + } else { + log_debug("Successfully sent stream file descriptor to service manager."); + s->fdstore = 1; + } + + LIST_REMOVE(stdout_stream_notify_queue, s->server->stdout_streams_notify_queue, s); + s->in_notify_queue = false; + +} diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h index 94bf955d78..e3497f0ded 100644 --- a/src/journal/journald-stream.h +++ b/src/journal/journald-stream.h @@ -21,9 +21,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +typedef struct StdoutStream StdoutStream; + #include "fdset.h" #include "journald-server.h" -int server_open_stdout_socket(Server *s, FDSet *fds); +int server_open_stdout_socket(Server *s); +int server_restore_streams(Server *s, FDSet *fds); void stdout_stream_free(StdoutStream *s); +void stdout_stream_send_notify(StdoutStream *s); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index ffba451955..f3ac1a7ae0 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -19,20 +19,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <stddef.h> #include <sys/epoll.h> +#include <unistd.h> -#include "systemd/sd-messages.h" -#include "socket-util.h" -#include "selinux-util.h" +#include "sd-messages.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" +#include "io-util.h" +#include "journald-console.h" +#include "journald-kmsg.h" #include "journald-server.h" #include "journald-syslog.h" -#include "journald-kmsg.h" -#include "journald-console.h" #include "journald-wall.h" -#include "formats-util.h" #include "process-util.h" +#include "selinux-util.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "syslog-util.h" /* Warn once every 30s if we missed syslog message */ #define WARN_FORWARD_SYSLOG_MISSED_USEC (30 * USEC_PER_SEC) diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c index 7863766ae7..69540f1141 100644 --- a/src/journal/journald-wall.c +++ b/src/journal/journald-wall.c @@ -19,11 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "utmp-wtmp.h" -#include "journald-server.h" -#include "journald-wall.h" +#include "alloc-util.h" #include "formats-util.h" +#include "journald-server.h" #include "process-util.h" +#include "string-util.h" +#include "utmp-wtmp.h" +#include "journald-wall.h" void server_forward_wall( Server *s, diff --git a/src/journal/journald.c b/src/journal/journald.c index b2624c6d28..b137e3c7be 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -21,8 +21,8 @@ #include <unistd.h> -#include "systemd/sd-messages.h" -#include "systemd/sd-daemon.h" +#include "sd-messages.h" +#include "sd-daemon.h" #include "journal-authenticate.h" #include "journald-server.h" @@ -54,17 +54,13 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - server_vacuum(&server); + server_vacuum(&server, false, false); server_flush_to_var(&server); server_flush_dev_kmsg(&server); log_debug("systemd-journald running as pid "PID_FMT, getpid()); server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started"); - sd_notify(false, - "READY=1\n" - "STATUS=Processing requests..."); - for (;;) { usec_t t = USEC_INFINITY, n; @@ -82,7 +78,7 @@ int main(int argc, char *argv[]) { if (server.oldest_file_usec + server.max_retention_usec < n) { log_info("Retention time reached."); server_rotate(&server); - server_vacuum(&server); + server_vacuum(&server, false, false); continue; } @@ -117,10 +113,6 @@ int main(int argc, char *argv[]) { server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped"); finish: - sd_notify(false, - "STOPPING=1\n" - "STATUS=Shutting down..."); - server_done(&server); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/journal/journald.conf b/src/journal/journald.conf index 47eefe91c1..7beb96c671 100644 --- a/src/journal/journald.conf +++ b/src/journal/journald.conf @@ -22,9 +22,11 @@ #SystemMaxUse= #SystemKeepFree= #SystemMaxFileSize= +#SystemMaxFiles=100 #RuntimeMaxUse= #RuntimeKeepFree= #RuntimeMaxFileSize= +#RuntimeMaxFiles=100 #MaxRetentionSec= #MaxFileSec=1month #ForwardToSyslog=no diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 22f75540b8..3cb1dfa986 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -23,6 +23,7 @@ #include <stdlib.h> #include <sys/mman.h> +#include "alloc-util.h" #include "hashmap.h" #include "list.h" #include "log.h" diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 13fa9b52fc..5cde7f17f7 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -21,29 +21,38 @@ #include <errno.h> #include <fcntl.h> +#include <linux/magic.h> +#include <poll.h> #include <stddef.h> -#include <unistd.h> #include <sys/inotify.h> -#include <poll.h> #include <sys/vfs.h> -#include <linux/magic.h> +#include <unistd.h> #include "sd-journal.h" + +#include "alloc-util.h" +#include "catalog.h" +#include "compress.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "fs-util.h" +#include "hashmap.h" +#include "hostname-util.h" +#include "io-util.h" #include "journal-def.h" #include "journal-file.h" -#include "hashmap.h" +#include "journal-internal.h" #include "list.h" -#include "strv.h" -#include "path-util.h" #include "lookup3.h" -#include "compress.h" -#include "journal-internal.h" #include "missing.h" -#include "catalog.h" +#include "path-util.h" #include "replace-var.h" -#include "fileio.h" -#include "formats-util.h" -#include "hostname-util.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" #define JOURNAL_FILES_MAX 7168 @@ -64,19 +73,46 @@ static bool journal_pid_changed(sd_journal *j) { return j->original_pid != getpid(); } -/* We return an error here only if we didn't manage to - memorize the real error. */ -static int set_put_error(sd_journal *j, int r) { +static int journal_put_error(sd_journal *j, int r, const char *path) { + char *copy; int k; + /* Memorize an error we encountered, and store which + * file/directory it was generated from. Note that we store + * only *one* path per error code, as the error code is the + * key into the hashmap, and the path is the value. This means + * we keep track only of all error kinds, but not of all error + * locations. This has the benefit that the hashmap cannot + * grow beyond bounds. + * + * We return an error here only if we didn't manage to + * memorize the real error. */ + if (r >= 0) return r; - k = set_ensure_allocated(&j->errors, NULL); + k = hashmap_ensure_allocated(&j->errors, NULL); if (k < 0) return k; - return set_put(j->errors, INT_TO_PTR(r)); + if (path) { + copy = strdup(path); + if (!copy) + return -ENOMEM; + } else + copy = NULL; + + k = hashmap_put(j->errors, INT_TO_PTR(r), copy); + if (k < 0) { + free(copy); + + if (k == -EEXIST) + return 0; + + return k; + } + + return 0; } static void detach_location(sd_journal *j) { @@ -1016,8 +1052,6 @@ _public_ int sd_journal_seek_cursor(sd_journal *j, const char *cursor) { _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { int r; - const char *word, *state; - size_t l; Object *o; assert_return(j, -EINVAL); @@ -1031,20 +1065,23 @@ _public_ int sd_journal_test_cursor(sd_journal *j, const char *cursor) { if (r < 0) return r; - FOREACH_WORD_SEPARATOR(word, l, cursor, ";", state) { + for(;;) { _cleanup_free_ char *item = NULL; - sd_id128_t id; unsigned long long ll; + sd_id128_t id; int k = 0; - if (l < 2 || word[1] != '=') - return -EINVAL; + r = extract_first_word(&cursor, &item, ";", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; - item = strndup(word, l); - if (!item) - return -ENOMEM; + if (r == 0) + break; - switch (word[0]) { + if (strlen(item) < 2 || item[1] != '=') + return -EINVAL; + + switch (item[0]) { case 's': k = sd_id128_from_string(item+2, &id); @@ -1173,6 +1210,8 @@ static bool file_has_type_prefix(const char *prefix, const char *filename) { } static bool file_type_wanted(int flags, const char *filename) { + assert(filename); + if (!endswith(filename, ".journal") && !endswith(filename, ".journal~")) return false; @@ -1197,7 +1236,7 @@ static bool file_type_wanted(int flags, const char *filename) { static int add_any_file(sd_journal *j, const char *path) { JournalFile *f = NULL; - int r; + int r, k; assert(j); assert(path); @@ -1206,20 +1245,23 @@ static int add_any_file(sd_journal *j, const char *path) { return 0; if (ordered_hashmap_size(j->files) >= JOURNAL_FILES_MAX) { - log_warning("Too many open journal files, not adding %s.", path); - return set_put_error(j, -ETOOMANYREFS); + log_debug("Too many open journal files, not adding %s.", path); + r = -ETOOMANYREFS; + goto fail; } r = journal_file_open(path, O_RDONLY, 0, false, false, NULL, j->mmap, NULL, &f); - if (r < 0) - return r; + if (r < 0) { + log_debug_errno(r, "Failed to open journal file %s: %m", path); + goto fail; + } /* journal_file_dump(f); */ r = ordered_hashmap_put(j->files, f->path, f); if (r < 0) { journal_file_close(f); - return r; + goto fail; } log_debug("File %s added.", f->path); @@ -1229,11 +1271,17 @@ static int add_any_file(sd_journal *j, const char *path) { j->current_invalidate_counter ++; return 0; + +fail: + k = journal_put_error(j, r, path); + if (k < 0) + return k; + + return r; } static int add_file(sd_journal *j, const char *prefix, const char *filename) { - _cleanup_free_ char *path = NULL; - int r; + const char *path; assert(j); assert(prefix); @@ -1243,34 +1291,24 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { !file_type_wanted(j->flags, filename)) return 0; - path = strjoin(prefix, "/", filename, NULL); - if (!path) - return -ENOMEM; - - r = add_any_file(j, path); - if (r == -ENOENT) - return 0; - return r; + path = strjoina(prefix, "/", filename); + return add_any_file(j, path); } -static int remove_file(sd_journal *j, const char *prefix, const char *filename) { - _cleanup_free_ char *path; +static void remove_file(sd_journal *j, const char *prefix, const char *filename) { + const char *path; JournalFile *f; assert(j); assert(prefix); assert(filename); - path = strjoin(prefix, "/", filename, NULL); - if (!path) - return -ENOMEM; - + path = strjoina(prefix, "/", filename); f = ordered_hashmap_get(j->files, path); if (!f) - return 0; + return; remove_file_real(j, f); - return 0; } static void remove_file_real(sd_journal *j, JournalFile *f) { @@ -1299,12 +1337,27 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { j->current_invalidate_counter ++; } +static int dirname_is_machine_id(const char *fn) { + sd_id128_t id, machine; + int r; + + r = sd_id128_get_machine(&machine); + if (r < 0) + return r; + + r = sd_id128_from_string(fn, &id); + if (r < 0) + return r; + + return sd_id128_equal(id, machine); +} + static int add_directory(sd_journal *j, const char *prefix, const char *dirname) { _cleanup_free_ char *path = NULL; - int r; _cleanup_closedir_ DIR *d = NULL; - sd_id128_t id, mid; + struct dirent *de = NULL; Directory *m; + int r, k; assert(j); assert(prefix); @@ -1313,35 +1366,36 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) log_debug("Considering %s/%s.", prefix, dirname); if ((j->flags & SD_JOURNAL_LOCAL_ONLY) && - (sd_id128_from_string(dirname, &id) < 0 || - sd_id128_get_machine(&mid) < 0 || - !(sd_id128_equal(id, mid) || path_startswith(prefix, "/run")))) + !(dirname_is_machine_id(dirname) > 0 || path_startswith(prefix, "/run"))) return 0; path = strjoin(prefix, "/", dirname, NULL); - if (!path) - return -ENOMEM; + if (!path) { + r = -ENOMEM; + goto fail; + } d = opendir(path); if (!d) { - log_debug_errno(errno, "Failed to open %s: %m", path); - if (errno == ENOENT) - return 0; - return -errno; + r = log_debug_errno(errno, "Failed to open directory %s: %m", path); + goto fail; } m = hashmap_get(j->directories_by_path, path); if (!m) { m = new0(Directory, 1); - if (!m) - return -ENOMEM; + if (!m) { + r = -ENOMEM; + goto fail; + } m->is_root = false; m->path = path; if (hashmap_put(j->directories_by_path, m->path, m) < 0) { free(m); - return -ENOMEM; + r = -ENOMEM; + goto fail; } path = NULL; /* avoid freeing in cleanup */ @@ -1363,41 +1417,30 @@ static int add_directory(sd_journal *j, const char *prefix, const char *dirname) inotify_rm_watch(j->inotify_fd, m->wd); } - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) { - r = -errno; - log_debug_errno(errno, "Failed to read directory %s: %m", m->path); - return r; - } - if (!de) - break; + FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { if (dirent_is_file_with_suffix(de, ".journal") || - dirent_is_file_with_suffix(de, ".journal~")) { - r = add_file(j, m->path, de->d_name); - if (r < 0) { - log_debug_errno(r, "Failed to add file %s/%s: %m", - m->path, de->d_name); - r = set_put_error(j, r); - if (r < 0) - return r; - } - } + dirent_is_file_with_suffix(de, ".journal~")) + (void) add_file(j, m->path, de->d_name); } check_network(j, dirfd(d)); return 0; + +fail: + k = journal_put_error(j, r, path ?: dirname); + if (k < 0) + return k; + + return r; } -static int add_root_directory(sd_journal *j, const char *p) { +static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) { _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; Directory *m; - int r; + int r, k; assert(j); assert(p); @@ -1410,26 +1453,35 @@ static int add_root_directory(sd_journal *j, const char *p) { p = strjoina(j->prefix, p); d = opendir(p); - if (!d) - return -errno; + if (!d) { + if (errno == ENOENT && missing_ok) + return 0; + + r = log_debug_errno(errno, "Failed to open root directory %s: %m", p); + goto fail; + } m = hashmap_get(j->directories_by_path, p); if (!m) { m = new0(Directory, 1); - if (!m) - return -ENOMEM; + if (!m) { + r = -ENOMEM; + goto fail; + } m->is_root = true; m->path = strdup(p); if (!m->path) { free(m); - return -ENOMEM; + r = -ENOMEM; + goto fail; } if (hashmap_put(j->directories_by_path, m->path, m) < 0) { free(m->path); free(m); - return -ENOMEM; + r = -ENOMEM; + goto fail; } j->current_invalidate_counter ++; @@ -1452,42 +1504,27 @@ static int add_root_directory(sd_journal *j, const char *p) { if (j->no_new_files) return 0; - for (;;) { - struct dirent *de; + FOREACH_DIRENT_ALL(de, d, return log_debug_errno(errno, "Failed to read directory %s: %m", m->path)) { sd_id128_t id; - errno = 0; - de = readdir(d); - if (!de && errno != 0) { - r = -errno; - log_debug_errno(errno, "Failed to read directory %s: %m", m->path); - return r; - } - if (!de) - break; - if (dirent_is_file_with_suffix(de, ".journal") || - dirent_is_file_with_suffix(de, ".journal~")) { - r = add_file(j, m->path, de->d_name); - if (r < 0) { - log_debug_errno(r, "Failed to add file %s/%s: %m", - m->path, de->d_name); - r = set_put_error(j, r); - if (r < 0) - return r; - } - } else if ((de->d_type == DT_DIR || de->d_type == DT_LNK || de->d_type == DT_UNKNOWN) && - sd_id128_from_string(de->d_name, &id) >= 0) { - - r = add_directory(j, m->path, de->d_name); - if (r < 0) - log_debug_errno(r, "Failed to add directory %s/%s: %m", m->path, de->d_name); - } + dirent_is_file_with_suffix(de, ".journal~")) + (void) add_file(j, m->path, de->d_name); + else if (IN_SET(de->d_type, DT_DIR, DT_LNK, DT_UNKNOWN) && + sd_id128_from_string(de->d_name, &id) >= 0) + (void) add_directory(j, m->path, de->d_name); } check_network(j, dirfd(d)); return 0; + +fail: + k = journal_put_error(j, r, p); + if (k < 0) + return k; + + return r; } static void remove_directory(sd_journal *j, Directory *d) { @@ -1512,8 +1549,8 @@ static void remove_directory(sd_journal *j, Directory *d) { } static int add_search_paths(sd_journal *j) { - int r; - const char search_paths[] = + + static const char search_paths[] = "/run/log/journal\0" "/var/log/journal\0"; const char *p; @@ -1523,14 +1560,8 @@ static int add_search_paths(sd_journal *j) { /* We ignore most errors here, since the idea is to only open * what's actually accessible, and ignore the rest. */ - NULSTR_FOREACH(p, search_paths) { - r = add_root_directory(j, p); - if (r < 0 && r != -ENOENT) { - r = set_put_error(j, r); - if (r < 0) - return r; - } - } + NULSTR_FOREACH(p, search_paths) + (void) add_root_directory(j, p, true); return 0; } @@ -1554,17 +1585,14 @@ static int add_current_paths(sd_journal *j) { if (!dir) return -ENOMEM; - r = add_root_directory(j, dir); - if (r < 0) { - set_put_error(j, r); + r = add_root_directory(j, dir, true); + if (r < 0) return r; - } } return 0; } - static int allocate_inotify(sd_journal *j) { assert(j); @@ -1692,11 +1720,9 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f if (!j) return -ENOMEM; - r = add_root_directory(j, path); - if (r < 0) { - set_put_error(j, r); + r = add_root_directory(j, path, false); + if (r < 0) goto fail; - } *ret = j; return 0; @@ -1721,10 +1747,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla STRV_FOREACH(path, paths) { r = add_any_file(j, *path); - if (r < 0) { - log_error_errno(r, "Failed to open %s: %m", *path); + if (r < 0) goto fail; - } } j->no_new_files = true; @@ -1741,6 +1765,7 @@ fail: _public_ void sd_journal_close(sd_journal *j) { Directory *d; JournalFile *f; + char *p; if (!j) return; @@ -1768,10 +1793,13 @@ _public_ void sd_journal_close(sd_journal *j) { mmap_cache_unref(j->mmap); } + while ((p = hashmap_steal_first(j->errors))) + free(p); + hashmap_free(j->errors); + free(j->path); free(j->prefix); free(j->unique_field); - set_free(j->errors); free(j); } @@ -2064,7 +2092,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) { if (j->no_new_files) r = add_current_paths(j); else if (j->path) - r = add_root_directory(j, j->path); + r = add_root_directory(j, j->path, true); else r = add_search_paths(j); if (r < 0) @@ -2111,7 +2139,6 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { static void process_inotify_event(sd_journal *j, struct inotify_event *e) { Directory *d; - int r; assert(j); assert(e); @@ -2127,20 +2154,10 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { /* Event for a journal file */ - if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { - r = add_file(j, d->path, e->name); - if (r < 0) { - log_debug_errno(r, "Failed to add file %s/%s: %m", - d->path, e->name); - set_put_error(j, r); - } - - } else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) { - - r = remove_file(j, d->path, e->name); - if (r < 0) - log_debug_errno(r, "Failed to remove file %s/%s: %m", d->path, e->name); - } + if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) + (void) add_file(j, d->path, e->name); + else if (e->mask & (IN_DELETE|IN_MOVED_FROM|IN_UNMOUNT)) + remove_file(j, d->path, e->name); } else if (!d->is_root && e->len == 0) { @@ -2153,11 +2170,8 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { /* Event for root directory */ - if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) { - r = add_directory(j, d->path, e->name); - if (r < 0) - log_debug_errno(r, "Failed to add directory %s/%s: %m", d->path, e->name); - } + if (e->mask & (IN_CREATE|IN_MOVED_TO|IN_MODIFY|IN_ATTRIB)) + (void) add_directory(j, d->path, e->name); } return; @@ -2166,7 +2180,7 @@ static void process_inotify_event(sd_journal *j, struct inotify_event *e) { if (e->mask & IN_IGNORED) return; - log_warning("Unknown inotify event."); + log_debug("Unknown inotify event."); } static int determine_change(sd_journal *j) { diff --git a/src/journal/stacktrace.c b/src/journal/stacktrace.c index 98a54ff269..4305462f80 100644 --- a/src/journal/stacktrace.c +++ b/src/journal/stacktrace.c @@ -22,10 +22,13 @@ #include <dwarf.h> #include <elfutils/libdwfl.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" #include "macro.h" #include "stacktrace.h" -#include "formats-util.h" +#include "string-util.h" +#include "util.h" #define FRAMES_MAX 64 #define THREADS_MAX 64 diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c index dbfdea609d..aea8fd15e6 100644 --- a/src/journal/test-catalog.c +++ b/src/journal/test-catalog.c @@ -25,11 +25,16 @@ #include <errno.h> #include <fcntl.h> -#include "util.h" -#include "log.h" -#include "macro.h" #include "sd-messages.h" + +#include "alloc-util.h" #include "catalog.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" +#include "macro.h" +#include "string-util.h" +#include "util.h" static const char *catalog_dirs[] = { CATALOG_DIR, diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c index c8e5b76c6c..93ea9c6318 100644 --- a/src/journal/test-compress-benchmark.c +++ b/src/journal/test-compress-benchmark.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + /*** This file is part of systemd @@ -17,30 +19,73 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "compress.h" -#include "util.h" #include "macro.h" +#include "parse-util.h" +#include "random-util.h" +#include "string-util.h" +#include "util.h" typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, size_t *dst_size); typedef int (decompress_t)(const void *src, uint64_t src_size, void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max); +static usec_t arg_duration = 2 * USEC_PER_SEC; +static size_t arg_start; + #define MAX_SIZE (1024*1024LU) +#define PRIME 1048571 /* A prime close enough to one megabyte that mod 4 == 3 */ + +static size_t _permute(size_t x) { + size_t residue; + + if (x >= PRIME) + return x; + + residue = x*x % PRIME; + if (x <= PRIME / 2) + return residue; + else + return PRIME - residue; +} + +static size_t permute(size_t x) { + return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345); +} -static char* make_buf(size_t count) { +static char* make_buf(size_t count, const char *type) { char *buf; size_t i; buf = malloc(count); assert_se(buf); - for (i = 0; i < count; i++) - buf[i] = 'a' + i % ('z' - 'a' + 1); + if (streq(type, "zeros")) + memzero(buf, count); + else if (streq(type, "simple")) + for (i = 0; i < count; i++) + buf[i] = 'a' + i % ('z' - 'a' + 1); + else if (streq(type, "random")) { + size_t step = count / 10; + + random_bytes(buf, step); + memzero(buf + 1*step, step); + random_bytes(buf + 2*step, step); + memzero(buf + 3*step, step); + random_bytes(buf + 4*step, step); + memzero(buf + 5*step, step); + random_bytes(buf + 6*step, step); + memzero(buf + 7*step, step); + random_bytes(buf + 8*step, step); + memzero(buf + 9*step, step); + } else + assert_not_reached("here"); return buf; } -static void test_compress_decompress(const char* label, +static void test_compress_decompress(const char* label, const char* type, compress_t compress, decompress_t decompress) { usec_t n, n2 = 0; float dt; @@ -50,64 +95,85 @@ static void test_compress_decompress(const char* label, size_t buf2_allocated = 0; size_t skipped = 0, compressed = 0, total = 0; - text = make_buf(MAX_SIZE); + text = make_buf(MAX_SIZE, type); buf = calloc(MAX_SIZE + 1, 1); assert_se(text && buf); n = now(CLOCK_MONOTONIC); - for (size_t i = 1; i <= MAX_SIZE; i += (i < 2048 ? 1 : 217)) { - size_t j = 0, k = 0; + for (size_t i = 0; i <= MAX_SIZE; i++) { + size_t j = 0, k = 0, size; int r; - r = compress(text, i, buf, &j); + size = permute(i); + + log_debug("%s %zu %zu", type, i, size); + + memzero(buf, MIN(size + 1000, MAX_SIZE)); + + r = compress(text, size, buf, &j); /* assume compression must be successful except for small inputs */ - assert_se(r == 0 || (i < 2048 && r == -ENOBUFS)); + assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random")); + /* check for overwrites */ - assert_se(buf[i] == 0); + assert_se(buf[size] == 0); if (r != 0) { - skipped += i; + skipped += size; continue; } assert_se(j > 0); - if (j >= i) - log_error("%s \"compressed\" %zu -> %zu", label, i, j); + if (j >= size) + log_error("%s \"compressed\" %zu -> %zu", label, size, j); r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0); assert_se(r == 0); assert_se(buf2_allocated >= k); - assert_se(k == i); + assert_se(k == size); - assert_se(memcmp(text, buf2, i) == 0); + assert_se(memcmp(text, buf2, size) == 0); - total += i; + total += size; compressed += j; n2 = now(CLOCK_MONOTONIC); - if (n2 - n > 60 * USEC_PER_SEC) + if (n2 - n > arg_duration) break; } dt = (n2-n) / 1e6; - log_info("%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), " + log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), " "mean compresion %.2f%%, skipped %zu bytes", - label, total, dt, + label, type, total, dt, total / 1024. / 1024 / dt, 100 - compressed * 100. / total, skipped); } int main(int argc, char *argv[]) { + const char *i; - log_set_max_level(LOG_DEBUG); + log_set_max_level(LOG_INFO); + if (argc >= 2) { + unsigned x; + + assert_se(safe_atou(argv[1], &x) >= 0); + arg_duration = x * USEC_PER_SEC; + } + if (argc == 3) + (void) safe_atolu(argv[2], &arg_start); + else + arg_start = getpid(); + + NULSTR_FOREACH(i, "zeros\0simple\0random\0") { #ifdef HAVE_XZ - test_compress_decompress("XZ", compress_blob_xz, decompress_blob_xz); + test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz); #endif #ifdef HAVE_LZ4 - test_compress_decompress("LZ4", compress_blob_lz4, decompress_blob_lz4); + test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4); #endif + } return 0; } diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c index f17c00e60d..b9d90a8988 100644 --- a/src/journal/test-compress.c +++ b/src/journal/test-compress.c @@ -17,10 +17,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "compress.h" -#include "util.h" +#include "fd-util.h" +#include "fileio.h" #include "macro.h" #include "random-util.h" +#include "util.h" #ifdef HAVE_XZ # define XZ_OK 0 @@ -144,8 +147,8 @@ static void test_compress_stream(int compression, const char *srcfile) { _cleanup_close_ int src = -1, dst = -1, dst2 = -1; - char pattern[] = "/tmp/systemd-test.xz.XXXXXX", - pattern2[] = "/tmp/systemd-test.xz.XXXXXX"; + char pattern[] = "/tmp/systemd-test.compressed.XXXXXX", + pattern2[] = "/tmp/systemd-test.compressed.XXXXXX"; int r; _cleanup_free_ char *cmd = NULL, *cmd2; struct stat st = {}; @@ -185,7 +188,7 @@ static void test_compress_stream(int compression, assert_se(lseek(dst, 1, SEEK_SET) == 1); r = decompress(dst, dst2, st.st_size); - assert_se(r == -EBADMSG); + assert_se(r == -EBADMSG || r == 0); assert_se(lseek(dst, 0, SEEK_SET) == 0); assert_se(lseek(dst2, 0, SEEK_SET) == 0); @@ -236,8 +239,7 @@ int main(int argc, char *argv[]) { compress_blob_lz4, decompress_startswith_lz4, data, sizeof(data), true); - /* Produced stream is not compatible with lz4 binary, skip lz4cat check. */ - test_compress_stream(OBJECT_COMPRESSED_LZ4, NULL, + test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat", compress_stream_lz4, decompress_stream_lz4, argv[0]); #else log_info("/* LZ4 test skipped */"); diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c index cde2025ae9..040c7d58fb 100644 --- a/src/journal/test-journal-enum.c +++ b/src/journal/test-journal-enum.c @@ -21,8 +21,9 @@ #include <stdio.h> -#include "log.h" #include "sd-journal.h" + +#include "log.h" #include "macro.h" #include "journal-internal.h" diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c index 2d4f531e9b..03d1522e23 100644 --- a/src/journal/test-journal-flush.c +++ b/src/journal/test-journal-flush.c @@ -22,9 +22,12 @@ #include <fcntl.h> #include "sd-journal.h" -#include "macro.h" + +#include "alloc-util.h" #include "journal-file.h" #include "journal-internal.h" +#include "macro.h" +#include "string-util.h" int main(int argc, char *argv[]) { _cleanup_free_ char *fn = NULL; diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c index e6599f366d..142da85041 100644 --- a/src/journal/test-journal-init.c +++ b/src/journal/test-journal-init.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "systemd/sd-journal.h" +#include "sd-journal.h" #include "log.h" -#include "util.h" +#include "parse-util.h" #include "rm-rf.h" +#include "util.h" int main(int argc, char *argv[]) { sd_journal *j; diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index adefa1b026..4ad89fe4b6 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -24,11 +24,14 @@ #include <fcntl.h> #include "sd-journal.h" + +#include "alloc-util.h" #include "journal-file.h" #include "journal-vacuum.h" -#include "util.h" #include "log.h" +#include "parse-util.h" #include "rm-rf.h" +#include "util.h" /* This program tests skipping around in a multi-file journal. */ @@ -197,7 +200,7 @@ static void test_skip(void (*setup)(void)) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, NULL, true); + journal_directory_vacuum(".", 3000000, 0, 0, NULL, true); assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } @@ -282,7 +285,7 @@ static void test_sequence_numbers(void) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, NULL, true); + journal_directory_vacuum(".", 3000000, 0, 0, NULL, true); assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } diff --git a/src/journal/test-journal-match.c b/src/journal/test-journal-match.c index a3187053c9..abefedb992 100644 --- a/src/journal/test-journal-match.c +++ b/src/journal/test-journal-match.c @@ -21,11 +21,13 @@ #include <stdio.h> -#include "systemd/sd-journal.h" +#include "sd-journal.h" +#include "alloc-util.h" #include "journal-internal.h" -#include "util.h" #include "log.h" +#include "string-util.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_journal_close_ sd_journal*j; diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c index 81ca47ed8d..694376670d 100644 --- a/src/journal/test-journal-send.c +++ b/src/journal/test-journal-send.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "systemd/sd-journal.h" #include <stdlib.h> #include <unistd.h> +#include "sd-journal.h" + #include "log.h" int main(int argc, char *argv[]) { diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index b5ecf2f375..0cbef4b8c5 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -19,16 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <fcntl.h> +#include <unistd.h> #include "sd-journal.h" -#include "util.h" + +#include "alloc-util.h" +#include "journal-file.h" +#include "journal-internal.h" #include "log.h" #include "macro.h" +#include "parse-util.h" #include "rm-rf.h" -#include "journal-file.h" -#include "journal-internal.h" +#include "util.h" #define N_ENTRIES 200 diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c index c99ca0654b..1784187fe9 100644 --- a/src/journal/test-journal-syslog.c +++ b/src/journal/test-journal-syslog.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "journald-syslog.h" #include "macro.h" +#include "string-util.h" static void test_syslog_parse_identifier(const char* str, const char *ident, const char*pid, int ret) { diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index d89123dc64..887a83efe1 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -23,12 +23,13 @@ #include <unistd.h> #include <fcntl.h> -#include "util.h" -#include "log.h" -#include "rm-rf.h" +#include "fd-util.h" #include "journal-file.h" #include "journal-verify.h" +#include "log.h" +#include "rm-rf.h" #include "terminal-util.h" +#include "util.h" #define N_ENTRIES 6000 #define RANDOM_RANGE 77 diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index caaab258c9..01d4bc968a 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -116,7 +116,7 @@ static void test_non_empty(void) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, NULL, true); + journal_directory_vacuum(".", 3000000, 0, 0, NULL, true); assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } @@ -155,7 +155,7 @@ static void test_empty(void) { if (arg_keep) log_info("Not removing %s", t); else { - journal_directory_vacuum(".", 3000000, 0, NULL, true); + journal_directory_vacuum(".", 3000000, 0, 0, NULL, true); assert_se(rm_rf(t, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c index 3258b22702..fdd48e531c 100644 --- a/src/journal/test-mmap-cache.c +++ b/src/journal/test-mmap-cache.c @@ -19,14 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fcntl.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> -#include <fcntl.h> +#include "fd-util.h" +#include "fileio.h" #include "macro.h" -#include "util.h" #include "mmap-cache.h" +#include "util.h" int main(int argc, char *argv[]) { int x, y, z, r; diff --git a/src/libsystemd-network/arp-util.c b/src/libsystemd-network/arp-util.c index 2f5b9b3731..4660c7ea09 100644 --- a/src/libsystemd-network/arp-util.c +++ b/src/libsystemd-network/arp-util.c @@ -21,8 +21,9 @@ #include <linux/filter.h> #include <arpa/inet.h> -#include "util.h" #include "arp-util.h" +#include "fd-util.h" +#include "util.h" int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) { struct sock_filter filter[] = { diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 7d9cad2a70..51ee7bcce4 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -19,18 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "sd-id128.h" #include "libudev.h" -#include "udev-util.h" - -#include "virt.h" -#include "sparse-endian.h" -#include "siphash24.h" +#include "sd-id128.h" -#include "dhcp6-protocol.h" #include "dhcp-identifier.h" +#include "dhcp6-protocol.h" #include "network-internal.h" +#include "siphash24.h" +#include "sparse-endian.h" +#include "udev-util.h" +#include "virt.h" #define SYSTEMD_PEN 43793 #define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) @@ -58,7 +56,6 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { return 0; } - int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { /* name is a pointer to memory in the udev_device struct, so must have the same scope */ diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 95117915f4..2291736f8b 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -21,11 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-id128.h" #include "macro.h" #include "sparse-endian.h" #include "unaligned.h" -#include "sd-id128.h" /* RFC 3315 section 9.1: * A DUID can be no more than 128 octets long (not including the type code). diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index df6f882af5..a5daaa543a 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -22,15 +22,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdint.h> #include <linux/if_packet.h> -#include <net/if_arp.h> #include <net/ethernet.h> - -#include "socket-util.h" +#include <net/if_arp.h> +#include <stdint.h> #include "sd-dhcp-client.h" + #include "dhcp-protocol.h" +#include "socket-util.h" int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, diff --git a/src/libsystemd-network/dhcp-network.c b/src/libsystemd-network/dhcp-network.c index 7f10838de1..fac25e0fa2 100644 --- a/src/libsystemd-network/dhcp-network.c +++ b/src/libsystemd-network/dhcp-network.c @@ -18,18 +18,18 @@ ***/ #include <errno.h> -#include <sys/socket.h> -#include <string.h> -#include <linux/if_packet.h> -#include <linux/if_infiniband.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <stdio.h> +#include <string.h> +#include <sys/socket.h> #include <linux/filter.h> - -#include "socket-util.h" +#include <linux/if_infiniband.h> +#include <linux/if_packet.h> #include "dhcp-internal.h" +#include "fd-util.h" +#include "socket-util.h" static int _bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, const uint8_t *mac_addr, diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 5dc3c7aa26..3b88b93d9a 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -96,5 +96,5 @@ int dhcp_server_send_packet(sd_dhcp_server *server, DHCPRequest *req, DHCPPacket *packet, int type, size_t optoffset); -unsigned long client_id_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]); +void client_id_hash_func(const void *p, struct siphash *state); int client_id_compare_func(const void *_a, const void *_b); diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 83e8192f58..ecc220f2f6 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -24,10 +24,11 @@ #include <net/ethernet.h> #include <netinet/in.h> -#include "sparse-endian.h" #include "sd-event.h" + #include "list.h" #include "macro.h" +#include "sparse-endian.h" typedef struct DHCP6Address DHCP6Address; @@ -58,9 +59,6 @@ typedef struct DHCP6IA DHCP6IA; #define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) -int dhcp_network_icmp6_bind_router_solicitation(int index); -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr); - int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia); diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index 187975364b..318ee9c4b4 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -18,116 +18,19 @@ ***/ #include <errno.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <string.h> -#include <linux/if_packet.h> +#include <netinet/in.h> +#include <netinet/ip6.h> #include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> -#include <netinet/ip6.h> -#include <netinet/icmp6.h> -#include <netinet/in.h> - -#include "socket-util.h" +#include <linux/if_packet.h> #include "dhcp6-internal.h" #include "dhcp6-protocol.h" - -#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } } - -#define IN6ADDR_ALL_NODES_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } - -int dhcp_network_icmp6_bind_router_solicitation(int index) { - struct icmp6_filter filter = { }; - struct ipv6_mreq mreq = { - .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, - .ipv6mr_interface = index, - }; - _cleanup_close_ int s = -1; - int r, zero = 0, hops = 255; - - s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_ICMPV6); - if (s < 0) - return -errno; - - ICMP6_FILTER_SETBLOCKALL(&filter); - ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); - r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, - sizeof(filter)); - if (r < 0) - return -errno; - - /* RFC 3315, section 6.7, bullet point 2 may indicate that an - IPV6_PKTINFO socket option also applies for ICMPv6 multicast. - Empirical experiments indicates otherwise and therefore an - IPV6_MULTICAST_IF socket option is used here instead */ - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, - sizeof(index)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, - sizeof(zero)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, - sizeof(hops)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)); - if (r < 0) - return -errno; - - r = s; - s = -1; - return r; -} - -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { - struct sockaddr_in6 dst = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, - }; - struct { - struct nd_router_solicit rs; - struct nd_opt_hdr rs_opt; - struct ether_addr rs_opt_mac; - } _packed_ rs = { - .rs.nd_rs_type = ND_ROUTER_SOLICIT, - }; - struct iovec iov[1] = { - { &rs, }, - }; - struct msghdr msg = { - .msg_name = &dst, - .msg_namelen = sizeof(dst), - .msg_iov = iov, - .msg_iovlen = 1, - }; - int r; - - if (ether_addr) { - memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN); - rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; - rs.rs_opt.nd_opt_len = 1; - iov[0].iov_len = sizeof(rs); - } else - iov[0].iov_len = sizeof(rs.rs); - - r = sendmsg(s, &msg, 0); - if (r < 0) - return -errno; - - return 0; -} +#include "fd-util.h" +#include "socket-util.h" int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { struct in6_pktinfo pktinfo = { diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index f41bebced0..0f46df6a1b 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -23,14 +23,14 @@ #include <errno.h> #include <string.h> -#include "sparse-endian.h" -#include "unaligned.h" -#include "util.h" -#include "strv.h" - +#include "alloc-util.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" #include "dns-domain.h" +#include "sparse-endian.h" +#include "strv.h" +#include "unaligned.h" +#include "util.h" #define DHCP6_OPTION_IA_NA_LEN 12 #define DHCP6_OPTION_IA_TA_LEN 4 @@ -344,7 +344,7 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * int r; assert_return(optlen > 1, -ENODATA); - assert_return(optval[optlen] == '\0', -EINVAL); + assert_return(optval[optlen - 1] == '\0', -EINVAL); while (pos < optlen) { _cleanup_free_ char *ret = NULL; diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c new file mode 100644 index 0000000000..91308bf6c3 --- /dev/null +++ b/src/libsystemd-network/icmp6-util.c @@ -0,0 +1,129 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <errno.h> +#include <netinet/icmp6.h> +#include <netinet/in.h> +#include <netinet/ip6.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> +#include <linux/if_packet.h> + +#include "fd-util.h" +#include "icmp6-util.h" +#include "socket-util.h" + +#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ + { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } } + +#define IN6ADDR_ALL_NODES_MULTICAST_INIT \ + { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } + +int icmp6_bind_router_solicitation(int index) { + struct icmp6_filter filter = { }; + struct ipv6_mreq mreq = { + .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, + .ipv6mr_interface = index, + }; + _cleanup_close_ int s = -1; + int r, zero = 0, hops = 255; + + s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, + IPPROTO_ICMPV6); + if (s < 0) + return -errno; + + ICMP6_FILTER_SETBLOCKALL(&filter); + ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); + r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, + sizeof(filter)); + if (r < 0) + return -errno; + + /* RFC 3315, section 6.7, bullet point 2 may indicate that an + IPV6_PKTINFO socket option also applies for ICMPv6 multicast. + Empirical experiments indicates otherwise and therefore an + IPV6_MULTICAST_IF socket option is used here instead */ + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, + sizeof(index)); + if (r < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, + sizeof(zero)); + if (r < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, + sizeof(hops)); + if (r < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, + sizeof(mreq)); + if (r < 0) + return -errno; + + r = s; + s = -1; + return r; +} + +int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { + struct sockaddr_in6 dst = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, + }; + struct { + struct nd_router_solicit rs; + struct nd_opt_hdr rs_opt; + struct ether_addr rs_opt_mac; + } _packed_ rs = { + .rs.nd_rs_type = ND_ROUTER_SOLICIT, + }; + struct iovec iov[1] = { + { &rs, }, + }; + struct msghdr msg = { + .msg_name = &dst, + .msg_namelen = sizeof(dst), + .msg_iov = iov, + .msg_iovlen = 1, + }; + int r; + + if (ether_addr) { + memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN); + rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; + rs.rs_opt.nd_opt_len = 1; + iov[0].iov_len = sizeof(rs); + } else + iov[0].iov_len = sizeof(rs.rs); + + r = sendmsg(s, &msg, 0); + if (r < 0) + return -errno; + + return 0; +} diff --git a/src/libsystemd-network/icmp6-util.h b/src/libsystemd-network/icmp6-util.h new file mode 100644 index 0000000000..4eb17e152e --- /dev/null +++ b/src/libsystemd-network/icmp6-util.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <net/ethernet.h> + +int icmp6_bind_router_solicitation(int index); +int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr); diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c index 3c04898e92..583be2f55d 100644 --- a/src/libsystemd-network/lldp-internal.c +++ b/src/libsystemd-network/lldp-internal.c @@ -20,6 +20,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-lldp.h" + +#include "alloc-util.h" #include "lldp-internal.h" /* We store maximum 1K chassis entries */ @@ -28,207 +31,6 @@ /* Maximum Ports can be attached to any chassis */ #define LLDP_MIB_MAX_PORT_PER_CHASSIS 32 -int lldp_read_chassis_id(tlv_packet *tlv, - uint8_t *type, - uint16_t *length, - uint8_t **data) { - uint8_t subtype; - int r; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID); - if (r < 0) - goto out2; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out1; - - switch (subtype) { - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out1; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out1: - (void) lldp_tlv_packet_exit_container(tlv); - - out2: - return r; -} - -int lldp_read_port_id(tlv_packet *tlv, - uint8_t *type, - uint16_t *length, - uint8_t **data) { - uint8_t subtype; - char *s; - int r; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID); - if (r < 0) - goto out2; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out1; - - switch (subtype) { - case LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out1; - - *data = (uint8_t *) s; - - break; - case LLDP_PORT_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out1; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out1: - (void) lldp_tlv_packet_exit_container(tlv); - - out2: - return r; -} - -int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl) { - int r; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_TTL); - if (r < 0) - goto out; - - r = tlv_packet_read_u16(tlv, ttl); - - (void) lldp_tlv_packet_exit_container(tlv); - - out: - return r; -} - -int lldp_read_system_name(tlv_packet *tlv, - uint16_t *length, - char **data) { - char *s; - int r; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_NAME); - if (r < 0) - return r; - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (char *) s; - - out: - (void) lldp_tlv_packet_exit_container(tlv); - - return r; -} - -int lldp_read_system_description(tlv_packet *tlv, - uint16_t *length, - char **data) { - char *s; - int r; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION); - if (r < 0) - return r; - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (char *) s; - - out: - (void) lldp_tlv_packet_exit_container(tlv); - - return r; -} - -int lldp_read_port_description(tlv_packet *tlv, - uint16_t *length, - char **data) { - char *s; - int r; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_DESCRIPTION); - if (r < 0) - return r; - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (char *) s; - - out: - (void) lldp_tlv_packet_exit_container(tlv); - - return r; -} - -int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data) { - int r; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, data); - if (r < 0) - goto out; - - return 0; - out: - - (void) lldp_tlv_packet_exit_container(tlv); - - return r; -} - /* 10.5.5.2.2 mibUpdateObjects () * The mibUpdateObjects () procedure updates the MIB objects corresponding to * the TLVs contained in the received LLDPDU for the LLDP remote system @@ -244,7 +46,7 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { assert_return(c, -EINVAL); assert_return(tlv, -EINVAL); - r = lldp_read_port_id(tlv, &type, &length, &data); + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); if (r < 0) return r; @@ -253,13 +55,13 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) { - r = lldp_read_ttl(tlv, &ttl); + r = sd_lldp_packet_read_ttl(tlv, &ttl); if (r < 0) return r; p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - tlv_packet_free(p->packet); + sd_lldp_packet_unref(p->packet); p->packet = tlv; prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); @@ -281,7 +83,7 @@ int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) { assert_return(c, -EINVAL); assert_return(tlv, -EINVAL); - r = lldp_read_port_id(tlv, &type, &length, &data); + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); if (r < 0) return r; @@ -312,11 +114,11 @@ int lldp_mib_add_objects(Prioq *by_expiry, assert_return(neighbour_mib, -EINVAL); assert_return(tlv, -EINVAL); - r = lldp_read_chassis_id(tlv, &subtype, &length, &data); + r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length); if (r < 0) goto drop; - r = lldp_read_ttl(tlv, &ttl); + r = sd_lldp_packet_read_ttl(tlv, &ttl); if (r < 0) goto drop; @@ -401,7 +203,7 @@ int lldp_mib_add_objects(Prioq *by_expiry, return 0; drop: - tlv_packet_free(tlv); + sd_lldp_packet_unref(tlv); if (new_chassis) hashmap_remove(neighbour_mib, &c->chassis_id); @@ -435,7 +237,7 @@ void lldp_neighbour_port_free(lldp_neighbour_port *p) { if(!p) return; - tlv_packet_free(p->packet); + sd_lldp_packet_unref(p->packet); free(p->data); free(p); @@ -452,11 +254,11 @@ int lldp_neighbour_port_new(lldp_chassis *c, assert(tlv); - r = lldp_read_port_id(tlv, &type, &length, &data); + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); if (r < 0) return r; - r = lldp_read_ttl(tlv, &ttl); + r = sd_lldp_packet_read_ttl(tlv, &ttl); if (r < 0) return r; @@ -505,7 +307,7 @@ int lldp_chassis_new(tlv_packet *tlv, assert(tlv); - r = lldp_read_chassis_id(tlv, &type, &length, &data); + r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length); if (r < 0) return r; @@ -531,3 +333,30 @@ int lldp_chassis_new(tlv_packet *tlv, return 0; } + +int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_lldp_packet_unref_ tlv_packet *packet = NULL; + tlv_packet *p; + uint16_t length; + int r; + + assert(fd); + assert(userdata); + + r = tlv_packet_new(&packet); + if (r < 0) + return r; + + length = read(fd, &packet->pdu, sizeof(packet->pdu)); + + /* Silently drop the packet */ + if ((size_t) length > ETHER_MAX_LEN) + return 0; + + packet->userdata = userdata; + + p = packet; + packet = NULL; + + return lldp_handle_packet(p, (uint16_t) length); +} diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index f4eadbb87e..5d19fa0fea 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -22,9 +22,11 @@ #pragma once -#include "log.h" +#include "sd-event.h" + #include "list.h" #include "lldp-tlv.h" +#include "log.h" #include "prioq.h" typedef struct lldp_neighbour_port lldp_neighbour_port; @@ -86,13 +88,6 @@ int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv); int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv); int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv); -int lldp_read_chassis_id(tlv_packet *tlv, uint8_t *type, uint16_t *length, uint8_t **data); -int lldp_read_port_id(tlv_packet *tlv, uint8_t *type, uint16_t *length, uint8_t **data); -int lldp_read_ttl(tlv_packet *tlv, uint16_t *ttl); -int lldp_read_system_name(tlv_packet *tlv, uint16_t *length, char **data); -int lldp_read_system_description(tlv_packet *tlv, uint16_t *length, char **data); -int lldp_read_system_capability(tlv_packet *tlv, uint16_t *data); -int lldp_read_port_description(tlv_packet *tlv, uint16_t *length, char **data); - int lldp_handle_packet(tlv_packet *m, uint16_t length); +int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata); #define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 664d2f7867..f483cd9c8e 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -23,10 +23,11 @@ #include <linux/filter.h> #include <linux/if_ether.h> -#include "socket-util.h" -#include "lldp-tlv.h" -#include "lldp-network.h" +#include "fd-util.h" #include "lldp-internal.h" +#include "lldp-network.h" +#include "lldp-tlv.h" +#include "socket-util.h" int lldp_network_bind_raw_socket(int ifindex) { typedef struct LLDPFrame { @@ -82,30 +83,3 @@ int lldp_network_bind_raw_socket(int ifindex) { return r; } - -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_tlv_packet_free_ tlv_packet *packet = NULL; - tlv_packet *p; - uint16_t length; - int r; - - assert(fd); - assert(userdata); - - r = tlv_packet_new(&packet); - if (r < 0) - return r; - - length = read(fd, &packet->pdu, sizeof(packet->pdu)); - - /* Silently drop the packet */ - if ((size_t) length > ETHER_MAX_LEN) - return 0; - - packet->userdata = userdata; - - p = packet; - packet = NULL; - - return lldp_handle_packet(p, (uint16_t) length); -} diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h index b7f8d3bf80..74ee13a414 100644 --- a/src/libsystemd-network/lldp-network.h +++ b/src/libsystemd-network/lldp-network.h @@ -25,4 +25,3 @@ #include "sd-event.h" int lldp_network_bind_raw_socket(int ifindex); -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata); diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c index aa6a3b9224..97b6b485d2 100644 --- a/src/libsystemd-network/lldp-port.c +++ b/src/libsystemd-network/lldp-port.c @@ -20,9 +20,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "async.h" #include "lldp-port.h" #include "lldp-network.h" +#include "lldp-internal.h" int lldp_port_start(lldp_port *p) { int r; @@ -38,19 +40,19 @@ int lldp_port_start(lldp_port *p) { r = sd_event_add_io(p->event, &p->lldp_port_rx, p->rawfd, EPOLLIN, lldp_receive_packet, p); if (r < 0) { - log_debug("Failed to allocate event source: %s", strerror(-r)); - return r; + log_debug_errno(r, "Failed to allocate event source: %m"); + goto fail; } r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority); if (r < 0) { - log_debug("Failed to set event priority: %s", strerror(-r)); + log_debug_errno(r, "Failed to set event priority: %m"); goto fail; } r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx"); if (r < 0) { - log_debug("Failed to set event name: %s", strerror(-r)); + log_debug_errno(r, "Failed to set event name: %m"); goto fail; } diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index 0cea5b10a6..a539b5dfea 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -23,8 +23,9 @@ #include <net/ethernet.h> #include <arpa/inet.h> -#include "macro.h" +#include "alloc-util.h" #include "lldp-tlv.h" +#include "macro.h" int tlv_section_new(tlv_section **ret) { tlv_section *s; @@ -54,22 +55,41 @@ int tlv_packet_new(tlv_packet **ret) { return -ENOMEM; LIST_HEAD_INIT(m->sections); + m->n_ref = 1; *ret = m; return 0; } -void tlv_packet_free(tlv_packet *m) { +tlv_packet *sd_lldp_packet_ref(tlv_packet *m) { + + if (!m) + return NULL; + + assert(m->n_ref > 0); + m->n_ref++; + + return m; +} + +tlv_packet *sd_lldp_packet_unref(tlv_packet *m) { tlv_section *s, *n; if (!m) - return; + return NULL; + + assert(m->n_ref > 0); + m->n_ref--; + + if (m->n_ref > 0) + return m; LIST_FOREACH_SAFE(section, s, n, m->sections) tlv_section_free(s); free(m); + return NULL; } int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) { @@ -221,9 +241,9 @@ int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { return r; *data = (char *) val; - *data_length = m->container->length; + *data_length = m->container->data + m->container->length - m->container->read_pos; - m->container->read_pos += m->container->length; + m->container->read_pos += *data_length; return 0; } @@ -239,9 +259,9 @@ int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) return r; *data = (uint8_t *) val; - *data_length = m->container->length; + *data_length = m->container->data + m->container->length - m->container->read_pos; - m->container->read_pos += m->container->length; + m->container->read_pos += *data_length; return 0; } @@ -258,7 +278,7 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { p = m->pdu; - /* extract ethernet herader */ + /* extract Ethernet header */ memcpy(&m->mac, p, ETH_ALEN); p += sizeof(struct ether_header); @@ -278,6 +298,17 @@ int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { } p += 2; + + if (section->type == LLDP_TYPE_PRIVATE && + section->length >= LLDP_OUI_LEN + 1) { + section->oui = p; + p += LLDP_OUI_LEN; + section->subtype = *p++; + + section->length -= LLDP_OUI_LEN + 1; + l += LLDP_OUI_LEN + 1; + } + section->data = p; LIST_FIND_TAIL(section, m->sections, tail); @@ -294,6 +325,7 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { tlv_section *s; assert_return(m, -EINVAL); + assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL); LIST_FOREACH(section, s, m->sections) if (s->type == type) @@ -305,7 +337,35 @@ int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { m->container->read_pos = s->data; if (!m->container->read_pos) { - m->container = 0; + m->container = NULL; + return -1; + } + + return 0; +} + +int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) { + tlv_section *s; + + assert_return(m, -EINVAL); + assert_return(oui, -EINVAL); + + LIST_FOREACH(section, s, m->sections) { + if (s->type == LLDP_TYPE_PRIVATE && + s->oui && + s->subtype == subtype && + !memcmp(s->oui, oui, LLDP_OUI_LEN)) + break; + } + + if (!s) + return -1; + + m->container = s; + + m->container->read_pos = s->data; + if (!m->container->read_pos) { + m->container = NULL; return -1; } @@ -319,3 +379,270 @@ int lldp_tlv_packet_exit_container(tlv_packet *m) { return 0; } + +static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, type); + if (r < 0) + goto out; + + r = tlv_packet_read_u16(tlv, value); + r2 = lldp_tlv_packet_exit_container(tlv); + + out: + return r < 0 ? r : r2; +} + +static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) { + char *s; + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, type); + if (r < 0) + return r; + + r = tlv_packet_read_string(tlv, &s, length); + if (r < 0) + goto out; + + *data = (char *) s; + + out: + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, + uint8_t *type, + uint8_t **data, + uint16_t *length) { + uint8_t subtype; + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID); + if (r < 0) + goto out2; + + r = tlv_packet_read_u8(tlv, &subtype); + if (r < 0) + goto out1; + + switch (subtype) { + case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + + r = tlv_packet_read_bytes(tlv, data, length); + if (r < 0) + goto out1; + + break; + default: + r = -EOPNOTSUPP; + break; + } + + *type = subtype; + + out1: + r2 = lldp_tlv_packet_exit_container(tlv); + + out2: + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_port_id(tlv_packet *tlv, + uint8_t *type, + uint8_t **data, + uint16_t *length) { + uint8_t subtype; + char *s; + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID); + if (r < 0) + goto out2; + + r = tlv_packet_read_u8(tlv, &subtype); + if (r < 0) + goto out1; + + switch (subtype) { + case LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + + r = tlv_packet_read_string(tlv, &s, length); + if (r < 0) + goto out1; + + *data = (uint8_t *) s; + + break; + case LLDP_PORT_SUBTYPE_MAC_ADDRESS: + + r = tlv_packet_read_bytes(tlv, data, length); + if (r < 0) + goto out1; + + break; + default: + r = -EOPNOTSUPP; + break; + } + + *type = subtype; + + out1: + r2 = lldp_tlv_packet_exit_container(tlv); + + out2: + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) { + return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl); +} + +int sd_lldp_packet_read_system_name(tlv_packet *tlv, + char **data, + uint16_t *length) { + return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length); +} + +int sd_lldp_packet_read_system_description(tlv_packet *tlv, + char **data, + uint16_t *length) { + return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length); +} + +int sd_lldp_packet_read_port_description(tlv_packet *tlv, + char **data, + uint16_t *length) { + return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length); +} + +int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { + return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data); +} + +int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID); + if (r < 0) + goto out; + + r = tlv_packet_read_u16(tlv, id); + r2 = lldp_tlv_packet_exit_container(tlv); + + out: + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID); + if (r < 0) + goto out; + + r = tlv_packet_read_u8(tlv, flags); + if (r >= 0) + r = tlv_packet_read_u16(tlv, id); + + r2 = lldp_tlv_packet_exit_container(tlv); + + out: + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) { + int r, r2; + uint8_t len = 0; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME); + if (r < 0) + goto out; + + r = tlv_packet_read_u16(tlv, vlan_id); + if (r >= 0) + r = tlv_packet_read_u8(tlv, &len); + if (r >= 0) + r = tlv_packet_read_string(tlv, name, length); + + if (r >= 0 && len < *length) + *length = len; + + r2 = lldp_tlv_packet_exit_container(tlv); + + out: + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID); + if (r < 0) + goto out; + + r = tlv_packet_read_u16(tlv, id); + r2 = lldp_tlv_packet_exit_container(tlv); + + out: + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION); + if (r < 0) + goto out; + + r = tlv_packet_read_u8(tlv, status); + if (r >= 0) + r = tlv_packet_read_u32(tlv, id); + + r2 = lldp_tlv_packet_exit_container(tlv); + + out: + return r < 0 ? r : r2; +} + +int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) { + assert_return(tlv, -EINVAL); + assert_return(dest, -EINVAL); + + /* 802.1AB-2009, Table 7-1 */ + if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE; + else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE; + else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE; + else + return -EINVAL; + + return 0; +} diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index ce3334e115..ca1da113d5 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -28,12 +28,18 @@ #include "lldp.h" #include "list.h" -typedef struct tlv_packet tlv_packet; -typedef struct tlv_section tlv_section; +#include "sd-lldp.h" -struct tlv_section { +typedef struct sd_lldp_packet tlv_packet; +typedef struct sd_lldp_section tlv_section; + +#define LLDP_OUI_LEN 3 + +struct sd_lldp_section { uint16_t type; uint16_t length; + uint8_t *oui; + uint8_t subtype; uint8_t *read_pos; uint8_t *data; @@ -41,10 +47,16 @@ struct tlv_section { LIST_FIELDS(tlv_section, section); }; +#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } +#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } +#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 } + int tlv_section_new(tlv_section **ret); void tlv_section_free(tlv_section *ret); -struct tlv_packet { +struct sd_lldp_packet { + unsigned n_ref; + uint16_t type; uint16_t length; usec_t ts; @@ -61,10 +73,9 @@ struct tlv_packet { }; int tlv_packet_new(tlv_packet **ret); -void tlv_packet_free(tlv_packet *m); -DEFINE_TRIVIAL_CLEANUP_FUNC(tlv_packet*, tlv_packet_free); -#define _cleanup_tlv_packet_free_ _cleanup_(tlv_packet_freep) +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp_packet*, sd_lldp_packet_unref); +#define _cleanup_lldp_packet_unref_ _cleanup_(sd_lldp_packet_unrefp) int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); int lldp_tlv_packet_close_container(tlv_packet *m); @@ -76,6 +87,7 @@ int tlv_packet_append_u32(tlv_packet *m, uint32_t data); int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size); int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type); +int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype); int lldp_tlv_packet_exit_container(tlv_packet *m); int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length); diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index 5e4b283e26..19e5cc5f41 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -113,3 +113,16 @@ typedef enum LLDPMedCapability { LLDP_MED_CAPABILITY_MAX, LLDP_MED_CAPABILITY_INVALID = -1, } LLDPMedCapability; + +#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } +#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } + +enum { + LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1, + LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2, + LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3, + LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4, + LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5, + LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6, + LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7, +}; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index fab4ddbde4..52d76e443e 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -19,20 +19,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/ether.h> -#include <linux/if.h> #include <arpa/inet.h> +#include <linux/if.h> +#include <netinet/ether.h> -#include "strv.h" -#include "siphash24.h" +#include "sd-ndisc.h" + +#include "alloc-util.h" +#include "condition.h" +#include "conf-parser.h" #include "dhcp-lease-internal.h" #include "log.h" +#include "network-internal.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "siphash24.h" +#include "string-util.h" +#include "strv.h" #include "utf8.h" #include "util.h" -#include "conf-parser.h" -#include "condition.h" -#include "network-internal.h" -#include "sd-icmp6-nd.h" const char *net_get_name(struct udev_device *device) { const char *name, *field; @@ -196,8 +201,7 @@ int config_parse_ifname(const char *unit, return log_oom(); if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); return 0; } @@ -240,8 +244,7 @@ int config_parse_ifnames(const char *unit, return log_oom(); if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); free(n); return 0; } @@ -278,8 +281,7 @@ int config_parse_ifalias(const char *unit, return log_oom(); if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); return 0; } @@ -324,8 +326,7 @@ int config_parse_hwaddr(const char *unit, &n->ether_addr_octet[4], &n->ether_addr_octet[5]); if (r != 6) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Not a valid MAC address, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue); free(n); return 0; } @@ -394,8 +395,8 @@ void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, assert(size); for (i = 0; i < size; i++) - fprintf(f, SD_ICMP6_ND_ADDRESS_FORMAT_STR"%s", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addresses[i]), + fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s", + SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]), (i < (size - 1)) ? " ": ""); } diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 141b836a0d..137537253a 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -17,24 +17,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> -#include <string.h> -#include <stdio.h> #include <net/ethernet.h> #include <net/if_arp.h> -#include <linux/if_infiniband.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> +#include <linux/if_infiniband.h> -#include "util.h" -#include "random-util.h" -#include "async.h" +#include "sd-dhcp-client.h" -#include "dhcp-protocol.h" +#include "alloc-util.h" +#include "async.h" +#include "dhcp-identifier.h" #include "dhcp-internal.h" #include "dhcp-lease-internal.h" -#include "dhcp-identifier.h" -#include "sd-dhcp-client.h" +#include "dhcp-protocol.h" +#include "random-util.h" +#include "string-util.h" +#include "util.h" #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) @@ -1265,8 +1267,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - lifetime_timeout - time_now, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); /* don't arm earlier timeouts if this has already expired */ if (lifetime_timeout <= time_now) @@ -1292,8 +1293,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - t2_timeout - time_now, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); /* don't arm earlier timeout if this has already expired */ if (t2_timeout <= time_now) @@ -1318,8 +1318,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - t1_timeout - time_now, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); return 0; } @@ -1518,7 +1517,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd, expected_hlen = ETH_ALEN; expected_chaddr = (const struct ether_addr *) &client->mac_addr; } else { - /* Non-ethernet links expect zero chaddr */ + /* Non-Ethernet links expect zero chaddr */ expected_hlen = 0; expected_chaddr = &zero_mac; } diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index aa07846693..8befedc500 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -18,21 +18,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <arpa/inet.h> #include <errno.h> -#include <string.h> #include <stdio.h> -#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sd-dhcp-lease.h" +#include "alloc-util.h" +#include "dhcp-lease-internal.h" +#include "dhcp-protocol.h" +#include "dns-domain.h" +#include "fd-util.h" #include "fileio.h" -#include "unaligned.h" -#include "in-addr-util.h" +#include "hexdecoct.h" #include "hostname-util.h" -#include "dns-domain.h" +#include "in-addr-util.h" #include "network-internal.h" -#include "dhcp-protocol.h" -#include "dhcp-lease-internal.h" -#include "sd-dhcp-lease.h" +#include "parse-util.h" +#include "string-util.h" +#include "unaligned.h" int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { assert_return(lease, -EINVAL); @@ -314,10 +320,14 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { else { char *string; - if (memchr(option, 0, len)) + /* + * One trailing NUL byte is OK, we don't mind. See: + * https://github.com/systemd/systemd/issues/1337 + */ + if (memchr(option, 0, len - 1)) return -EINVAL; - string = strndup((const char *)option, len); + string = strndup((const char *) option, len); if (!string) return -ENOMEM; @@ -941,19 +951,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (address) { r = inet_pton(AF_INET, address, &lease->address); if (r <= 0) - log_debug_errno(errno, "Failed to parse address %s, ignoring: %m", address); + log_debug("Failed to parse address %s, ignoring.", address); } if (router) { r = inet_pton(AF_INET, router, &lease->router); if (r <= 0) - log_debug_errno(errno, "Failed to parse router %s, ignoring: %m", router); + log_debug("Failed to parse router %s, ignoring.", router); } if (netmask) { r = inet_pton(AF_INET, netmask, &lease->subnet_mask); if (r <= 0) - log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", netmask); + log_debug("Failed to parse netmask %s, ignoring.", netmask); else lease->have_subnet_mask = true; } @@ -961,19 +971,19 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (server_address) { r = inet_pton(AF_INET, server_address, &lease->server_address); if (r <= 0) - log_debug_errno(errno, "Failed to parse netmask %s, ignoring: %m", server_address); + log_debug("Failed to parse server address %s, ignoring.", server_address); } if (next_server) { r = inet_pton(AF_INET, next_server, &lease->next_server); if (r <= 0) - log_debug_errno(errno, "Failed to parse next server %s, ignoring: %m", next_server); + log_debug("Failed to parse next server %s, ignoring.", next_server); } if (broadcast) { r = inet_pton(AF_INET, broadcast, &lease->broadcast); if (r <= 0) - log_debug_errno(errno, "Failed to parse broadcast address %s, ignoring: %m", broadcast); + log_debug("Failed to parse broadcast address %s, ignoring.", broadcast); else lease->have_broadcast = true; } diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 1f167485e3..8d0d9955c3 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -22,12 +22,15 @@ #include <sys/ioctl.h> -#include "in-addr-util.h" -#include "siphash24.h" - #include "sd-dhcp-server.h" -#include "dhcp-server-internal.h" + +#include "alloc-util.h" #include "dhcp-internal.h" +#include "dhcp-server-internal.h" +#include "fd-util.h" +#include "in-addr-util.h" +#include "siphash24.h" +#include "string-util.h" #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) @@ -93,7 +96,7 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres return 0; } -bool sd_dhcp_server_is_running(sd_dhcp_server *server) { +int sd_dhcp_server_is_running(sd_dhcp_server *server) { assert_return(server, false); return !!server->receive_message; @@ -110,18 +113,15 @@ sd_dhcp_server *sd_dhcp_server_ref(sd_dhcp_server *server) { return server; } -unsigned long client_id_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; +void client_id_hash_func(const void *p, struct siphash *state) { const DHCPClientId *id = p; assert(id); assert(id->length); assert(id->data); - siphash24((uint8_t*) &u, id->data, id->length, hash_key); - - return (unsigned long) u; + siphash24_compress(&id->length, sizeof(id->length), state); + siphash24_compress(id->data, id->length, state); } int client_id_compare_func(const void *_a, const void *_b) { @@ -743,13 +743,18 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, if (existing_lease) address = existing_lease->address; else { + struct siphash state; + uint64_t hash; uint32_t next_offer; /* even with no persistence of leases, we try to offer the same client the same IP address. we do this by using the hash of the client id as the offset into the pool of leases when finding the next free one */ - next_offer = client_id_hash_func(&req->client_id, HASH_KEY.bytes) % server->pool_size; + siphash24_init(&state, HASH_KEY.bytes); + client_id_hash_func(&req->client_id, &state); + siphash24_finalize((uint8_t*)&hash, &state); + next_offer = hash % server->pool_size; for (i = 0; i < server->pool_size; i++) { if (!server->bound_leases[next_offer]) { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index acb31a16c2..e29de60d24 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -24,17 +24,18 @@ #include <sys/ioctl.h> #include <linux/if_infiniband.h> -#include "udev.h" -#include "udev-util.h" -#include "util.h" -#include "random-util.h" - -#include "network-internal.h" #include "sd-dhcp6-client.h" -#include "dhcp6-protocol.h" + +#include "alloc-util.h" +#include "dhcp-identifier.h" #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" -#include "dhcp-identifier.h" +#include "dhcp6-protocol.h" +#include "fd-util.h" +#include "network-internal.h" +#include "random-util.h" +#include "string-table.h" +#include "util.h" #define MAX_MAC_ADDR_LEN INFINIBAND_ALEN @@ -208,9 +209,8 @@ int sd_dhcp6_client_set_duid( return 0; } -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enabled) { +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) { assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); client->information_request = enabled; @@ -218,7 +218,7 @@ int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, bool enable return 0; } -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, bool *enabled) { +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) { assert_return(client, -EINVAL); assert_return(enabled, -EINVAL); @@ -595,8 +595,7 @@ static int client_timeout_resend(sd_event_source *s, uint64_t usec, } log_dhcp6_client(client, "Next retransmission in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - client->retransmit_time, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC)); r = sd_event_add_time(client->event, &client->timeout_resend, clock_boottime_or_monotonic(), @@ -1048,9 +1047,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC); log_dhcp6_client(client, "T1 expires in %s", - format_timespan(time_string, - FORMAT_TIMESPAN_MAX, - timeout, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); r = sd_event_add_time(client->event, &client->lease->ia.timeout_t1, @@ -1072,9 +1069,7 @@ static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); log_dhcp6_client(client, "T2 expires in %s", - format_timespan(time_string, - FORMAT_TIMESPAN_MAX, - timeout, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); r = sd_event_add_time(client->event, &client->lease->ia.timeout_t2, diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index f34af6eaba..3f32ba35e7 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -22,11 +22,11 @@ #include <errno.h> -#include "strv.h" -#include "util.h" - +#include "alloc-util.h" #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" +#include "strv.h" +#include "util.h" int dhcp6_lease_clear_timers(DHCP6IA *ia) { assert_return(ia, -EINVAL); diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 95b96bfd52..5340fdc0c1 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -24,17 +24,19 @@ #include <stdlib.h> #include <string.h> +#include "sd-ipv4acd.h" + +#include "alloc-util.h" +#include "arp-util.h" #include "event-util.h" +#include "fd-util.h" #include "in-addr-util.h" #include "list.h" -#include "refcnt.h" #include "random-util.h" +#include "refcnt.h" #include "siphash24.h" #include "util.h" -#include "arp-util.h" -#include "sd-ipv4acd.h" - /* Constants from the RFC */ #define PROBE_WAIT 1 #define PROBE_NUM 3 @@ -468,7 +470,7 @@ int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){ return 0; } -bool sd_ipv4acd_is_running(sd_ipv4acd *ll) { +int sd_ipv4acd_is_running(sd_ipv4acd *ll) { assert_return(ll, false); return ll->state != IPV4ACD_STATE_INIT; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index dd427ddd78..0d915e20e7 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -18,13 +18,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <arpa/inet.h> #include <errno.h> -#include <string.h> #include <stdio.h> -#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> + +#include "sd-ipv4acd.h" +#include "sd-ipv4ll.h" +#include "alloc-util.h" #include "event-util.h" +#include "in-addr-util.h" #include "list.h" #include "random-util.h" #include "refcnt.h" @@ -32,9 +37,6 @@ #include "sparse-endian.h" #include "util.h" -#include "sd-ipv4acd.h" -#include "sd-ipv4ll.h" - #define IPV4LL_NETWORK 0xA9FE0000L #define IPV4LL_NETMASK 0xFFFF0000L @@ -226,12 +228,45 @@ int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) { return 0; } -bool sd_ipv4ll_is_running(sd_ipv4ll *ll) { +int sd_ipv4ll_is_running(sd_ipv4ll *ll) { assert_return(ll, false); return sd_ipv4acd_is_running(ll->acd); } +static bool ipv4ll_address_is_valid(const struct in_addr *address) { + uint32_t addr; + + assert(address); + + if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address)) + return false; + + addr = be32toh(address->s_addr); + + if ((addr & 0x0000FF00) == 0x0000 || + (addr & 0x0000FF00) == 0xFF00) + return false; + + return true; +} + +int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { + int r; + + assert_return(ll, -EINVAL); + assert_return(address, -EINVAL); + assert_return(ipv4ll_address_is_valid(address), -EINVAL); + + r = sd_ipv4acd_set_address(ll->acd, address); + if (r < 0) + return r; + + ll->address = address->s_addr; + + return 0; +} + static int ipv4ll_pick_address(sd_ipv4ll *ll) { struct in_addr in_addr; be32_t addr; @@ -247,18 +282,15 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) { return r; addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK); } while (addr == ll->address || - (ntohl(addr) & IPV4LL_NETMASK) != IPV4LL_NETWORK || (ntohl(addr) & 0x0000FF00) == 0x0000 || (ntohl(addr) & 0x0000FF00) == 0xFF00); in_addr.s_addr = addr; - r = sd_ipv4acd_set_address(ll->acd, &in_addr); + r = sd_ipv4ll_set_address(ll, &in_addr); if (r < 0) return r; - ll->address = addr; - return 0; } diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 17512884f5..4ebe8053fa 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -22,15 +22,19 @@ #include <arpa/inet.h> -#include "siphash24.h" -#include "hashmap.h" - -#include "lldp-tlv.h" -#include "lldp-port.h" #include "sd-lldp.h" -#include "prioq.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" #include "lldp-internal.h" +#include "lldp-port.h" +#include "lldp-tlv.h" #include "lldp-util.h" +#include "prioq.h" +#include "siphash24.h" +#include "string-util.h" typedef enum LLDPAgentRXState { LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4, @@ -68,16 +72,14 @@ struct sd_lldp { lldp_agent_statistics statistics; }; -static unsigned long chassis_id_hash_func(const void *p, - const uint8_t hash_key[HASH_KEY_SIZE]) { - uint64_t u; +static void chassis_id_hash_func(const void *p, struct siphash *state) { const lldp_chassis_id *id = p; assert(id); + assert(id->data); - siphash24((uint8_t *) &u, id->data, id->length, hash_key); - - return (unsigned long) u; + siphash24_compress(&id->length, sizeof(id->length), state); + siphash24_compress(id->data, id->length, state); } static int chassis_id_compare_func(const void *_a, const void *_b) { @@ -199,7 +201,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { goto out; } - /* skip type and lengh encoding */ + /* skip type and length encoding */ p += 2; q = p; @@ -338,7 +340,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { lldp->statistics.stats_frames_in_errors_total ++; } - tlv_packet_free(tlv); + sd_lldp_packet_unref(tlv); return 0; } @@ -455,7 +457,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { _cleanup_free_ char *s = NULL; char *k, *t; - r = lldp_read_chassis_id(p->packet, &type, &length, &mac); + r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length); if (r < 0) continue; @@ -468,7 +470,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { goto fail; } - r = lldp_read_port_id(p->packet, &type, &length, &port_id); + r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length); if (r < 0) continue; @@ -513,7 +515,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { free(s); s = k; - r = lldp_read_system_name(p->packet, &length, &k); + r = sd_lldp_packet_read_system_name(p->packet, &k, &length); if (r < 0) k = strappend(s, "'_NAME=N/A' "); else { @@ -535,7 +537,7 @@ int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { free(s); s = k; - (void) lldp_read_system_capability(p->packet, &data); + (void) sd_lldp_packet_read_system_capability(p->packet, &data); sprintf(buf, "'_CAP=%x'", data); @@ -702,3 +704,35 @@ int sd_lldp_new(int ifindex, return 0; } + +int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) { + lldp_neighbour_port *p; + lldp_chassis *c; + Iterator iter; + unsigned count = 0, i; + + assert_return(lldp, -EINVAL); + assert_return(tlvs, -EINVAL); + + HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { + LIST_FOREACH(port, p, c->ports) + count++; + } + + if (!count) { + *tlvs = NULL; + return 0; + } + + *tlvs = new(sd_lldp_packet *, count); + if (!*tlvs) + return -ENOMEM; + + i = 0; + HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { + LIST_FOREACH(port, p, c->ports) + (*tlvs)[i++] = sd_lldp_packet_ref(p->packet); + } + + return count; +} diff --git a/src/libsystemd-network/sd-icmp6-nd.c b/src/libsystemd-network/sd-ndisc.c index bedcac8d9e..c494b9d6d8 100644 --- a/src/libsystemd-network/sd-icmp6-nd.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -18,65 +18,70 @@ ***/ #include <netinet/icmp6.h> +#include <netinet/in.h> #include <netinet/ip6.h> -#include <string.h> #include <stdbool.h> -#include <netinet/in.h> +#include <string.h> #include <sys/ioctl.h> -#include "socket-util.h" -#include "async.h" +#include "sd-ndisc.h" -#include "dhcp6-internal.h" -#include "sd-icmp6-nd.h" +#include "alloc-util.h" +#include "async.h" +#include "icmp6-util.h" +#include "list.h" +#include "socket-util.h" -#define ICMP6_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC -#define ICMP6_MAX_ROUTER_SOLICITATIONS 3 +#define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC +#define NDISC_MAX_ROUTER_SOLICITATIONS 3 -enum icmp6_nd_state { - ICMP6_NEIGHBOR_DISCOVERY_IDLE = 0, - ICMP6_ROUTER_SOLICITATION_SENT = 10, - ICMP6_ROUTER_ADVERTISMENT_LISTEN = 11, +enum NDiscState { + NDISC_STATE_IDLE, + NDISC_STATE_SOLICITATION_SENT, + NDISC_STATE_ADVERTISMENT_LISTEN, + _NDISC_STATE_MAX, + _NDISC_STATE_INVALID = -1, }; #define IP6_MIN_MTU (unsigned)1280 -#define ICMP6_ND_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr)) -#define ICMP6_OPT_LEN_UNITS 8 +#define ICMP6_RECV_SIZE (IP6_MIN_MTU - sizeof(struct ip6_hdr)) +#define NDISC_OPT_LEN_UNITS 8 -typedef struct ICMP6Prefix ICMP6Prefix; +typedef struct NDiscPrefix NDiscPrefix; -struct ICMP6Prefix { +struct NDiscPrefix { unsigned n_ref; - LIST_FIELDS(ICMP6Prefix, prefixes); + sd_ndisc *nd; + + LIST_FIELDS(NDiscPrefix, prefixes); uint8_t len; - sd_event_source *timeout_valid; + usec_t valid_until; struct in6_addr addr; }; -struct sd_icmp6_nd { +struct sd_ndisc { unsigned n_ref; - enum icmp6_nd_state state; + enum NDiscState state; sd_event *event; int event_priority; int index; struct ether_addr mac_addr; uint32_t mtu; - ICMP6Prefix *expired_prefix; - LIST_HEAD(ICMP6Prefix, prefixes); + LIST_HEAD(NDiscPrefix, prefixes); int fd; sd_event_source *recv; sd_event_source *timeout; int nd_sent; - sd_icmp6_nd_callback_t callback; + sd_ndisc_callback_t callback; void *userdata; }; -#define log_icmp6_nd(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "ICMPv6 CLIENT: " fmt, ##__VA_ARGS__) +#define log_ndisc(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "NDisc CLIENT: " fmt, ##__VA_ARGS__) -static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) { +static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) { if (!prefix) return NULL; @@ -87,22 +92,26 @@ static ICMP6Prefix *icmp6_prefix_unref(ICMP6Prefix *prefix) { if (prefix->n_ref > 0) return NULL; - prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid); + if (prefix->nd) + LIST_REMOVE(prefixes, prefix->nd->prefixes, prefix); + free(prefix); + return NULL; } -static int icmp6_prefix_new(ICMP6Prefix **ret) { - _cleanup_free_ ICMP6Prefix *prefix = NULL; +static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) { + _cleanup_free_ NDiscPrefix *prefix = NULL; assert(ret); - prefix = new0(ICMP6Prefix, 1); + prefix = new0(NDiscPrefix, 1); if (!prefix) return -ENOMEM; prefix->n_ref = 1; LIST_INIT(prefixes, prefix); + prefix->nd = nd; *ret = prefix; prefix = NULL; @@ -110,12 +119,12 @@ static int icmp6_prefix_new(ICMP6Prefix **ret) { return 0; } -static void icmp6_nd_notify(sd_icmp6_nd *nd, int event) { +static void ndisc_notify(sd_ndisc *nd, int event) { if (nd->callback) nd->callback(nd, event, nd->userdata); } -int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback, +int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t callback, void *userdata) { assert(nd); @@ -125,7 +134,7 @@ int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t callback, return 0; } -int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) { +int sd_ndisc_set_index(sd_ndisc *nd, int interface_index) { assert(nd); assert(interface_index >= -1); @@ -134,7 +143,7 @@ int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index) { return 0; } -int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) { +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr) { assert(nd); if (mac_addr) @@ -146,7 +155,7 @@ int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr) { } -int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) { +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority) { int r; assert_return(nd, -EINVAL); @@ -165,7 +174,7 @@ int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority) { return 0; } -int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) { +int sd_ndisc_detach_event(sd_ndisc *nd) { assert_return(nd, -EINVAL); nd->event = sd_event_unref(nd->event); @@ -173,13 +182,13 @@ int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd) { return 0; } -sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd) { +sd_event *sd_ndisc_get_event(sd_ndisc *nd) { assert(nd); return nd->event; } -sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) { +sd_ndisc *sd_ndisc_ref(sd_ndisc *nd) { if (!nd) return NULL; @@ -190,7 +199,7 @@ sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd) { return nd; } -static int icmp6_nd_init(sd_icmp6_nd *nd) { +static int ndisc_init(sd_ndisc *nd) { assert(nd); nd->recv = sd_event_source_unref(nd->recv); @@ -200,8 +209,8 @@ static int icmp6_nd_init(sd_icmp6_nd *nd) { return 0; } -sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) { - ICMP6Prefix *prefix, *p; +sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { + NDiscPrefix *prefix, *p; if (!nd) return NULL; @@ -212,29 +221,26 @@ sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd) { if (nd->n_ref > 0) return NULL; - icmp6_nd_init(nd); - sd_icmp6_nd_detach_event(nd); - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { - LIST_REMOVE(prefixes, nd->prefixes, prefix); + ndisc_init(nd); + sd_ndisc_detach_event(nd); - prefix = icmp6_prefix_unref(prefix); - } + LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) + prefix = ndisc_prefix_unref(prefix); free(nd); return NULL; } -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_icmp6_nd*, sd_icmp6_nd_unref); -#define _cleanup_sd_icmp6_nd_free_ _cleanup_(sd_icmp6_nd_unrefp) +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ndisc*, sd_ndisc_unref); +#define _cleanup_sd_ndisc_free_ _cleanup_(sd_ndisc_unrefp) -int sd_icmp6_nd_new(sd_icmp6_nd **ret) { - _cleanup_sd_icmp6_nd_free_ sd_icmp6_nd *nd = NULL; +int sd_ndisc_new(sd_ndisc **ret) { + _cleanup_sd_ndisc_free_ sd_ndisc *nd = NULL; assert(ret); - nd = new0(sd_icmp6_nd, 1); + nd = new0(sd_ndisc, 1); if (!nd) return -ENOMEM; @@ -251,7 +257,7 @@ int sd_icmp6_nd_new(sd_icmp6_nd **ret) { return 0; } -int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) { +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu) { assert_return(nd, -EINVAL); assert_return(mtu, -EINVAL); @@ -263,75 +269,9 @@ int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu) { return 0; } -static int icmp6_ra_prefix_timeout(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_icmp6_nd *nd = userdata; - ICMP6Prefix *prefix, *p; - - assert(nd); - - LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { - if (prefix->timeout_valid != s) - continue; - - log_icmp6_nd(nd, "Prefix expired "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len); - - LIST_REMOVE(prefixes, nd->prefixes, prefix); - - nd->expired_prefix = prefix; - icmp6_nd_notify(nd, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED); - nd->expired_prefix = NULL; - - prefix = icmp6_prefix_unref(prefix); - - break; - } - - return 0; -} - -static int icmp6_ra_prefix_set_timeout(sd_icmp6_nd *nd, - ICMP6Prefix *prefix, - usec_t valid) { - usec_t time_now; - int r; - - assert_return(prefix, -EINVAL); - - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - return r; - - prefix->timeout_valid = sd_event_source_unref(prefix->timeout_valid); - - r = sd_event_add_time(nd->event, &prefix->timeout_valid, - clock_boottime_or_monotonic(), time_now + valid, - USEC_PER_SEC, icmp6_ra_prefix_timeout, nd); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(prefix->timeout_valid, - nd->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(prefix->timeout_valid, - "icmp6-prefix-timeout"); - -error: - if (r < 0) - prefix->timeout_valid = - sd_event_source_unref(prefix->timeout_valid); - - return r; -} - -static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, - const struct in6_addr *addr, - uint8_t addr_prefixlen) { +static int prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, + const struct in6_addr *addr, + uint8_t addr_prefixlen) { uint8_t bytes, mask, len; assert_return(prefix, -EINVAL); @@ -349,69 +289,44 @@ static int icmp6_prefix_match(const struct in6_addr *prefix, uint8_t prefixlen, return 0; } -static int icmp6_ra_prefix_match(ICMP6Prefix *head, const struct in6_addr *addr, - uint8_t addr_len, ICMP6Prefix **result) { - ICMP6Prefix *prefix; - - LIST_FOREACH(prefixes, prefix, head) { - if (icmp6_prefix_match(&prefix->addr, prefix->len, addr, - addr_len) >= 0) { - *result = prefix; - return 0; - } - } - - return -EADDRNOTAVAIL; -} - -int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen, - struct in6_addr *addr) { - return icmp6_prefix_match(prefix, prefixlen, addr, - sizeof(addr->s6_addr) * 8); -} - -int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr, - uint8_t *prefixlen) { +static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr, + uint8_t addr_len, NDiscPrefix **result) { + NDiscPrefix *prefix, *p; + usec_t time_now; int r; - ICMP6Prefix *prefix; - assert_return(nd, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(prefixlen, -EINVAL); + assert(nd); - r = icmp6_ra_prefix_match(nd->prefixes, addr, - sizeof(addr->s6_addr) * 8, &prefix); + r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) return r; - *prefixlen = prefix->len; - - return 0; -} - -int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, uint8_t *prefixlen) { - assert_return(nd, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(prefixlen, -EINVAL); + LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { + if (prefix->valid_until < time_now) { + prefix = ndisc_prefix_unref(prefix); - if (!nd->expired_prefix) - return -EADDRNOTAVAIL; + continue; + } - *addr = &nd->expired_prefix->addr; - *prefixlen = nd->expired_prefix->len; + if (prefix_match(&prefix->addr, prefix->len, addr, addr_len) >= 0) { + *result = prefix; + return 0; + } + } - return 0; + return -EADDRNOTAVAIL; } -static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len, - const struct nd_opt_prefix_info *prefix_opt) { - int r; - ICMP6Prefix *prefix; +static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, + const struct nd_opt_prefix_info *prefix_opt) { + NDiscPrefix *prefix; uint32_t lifetime; + usec_t time_now; char time_string[FORMAT_TIMESPAN_MAX]; + int r; - assert_return(nd, -EINVAL); - assert_return(prefix_opt, -EINVAL); + assert(nd); + assert(prefix_opt); if (len < prefix_opt->nd_opt_pi_len) return -ENOMSG; @@ -421,9 +336,8 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len, lifetime = be32toh(prefix_opt->nd_opt_pi_valid_time); - r = icmp6_ra_prefix_match(nd->prefixes, - &prefix_opt->nd_opt_pi_prefix, - prefix_opt->nd_opt_pi_prefix_len, &prefix); + r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix, + prefix_opt->nd_opt_pi_prefix_len, &prefix); if (r < 0 && r != -EADDRNOTAVAIL) return r; @@ -432,7 +346,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len, callback will be called immediately to clean up the prefix */ if (r == -EADDRNOTAVAIL) { - r = icmp6_prefix_new(&prefix); + r = ndisc_prefix_new(nd, &prefix); if (r < 0) return r; @@ -441,11 +355,10 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len, memcpy(&prefix->addr, &prefix_opt->nd_opt_pi_prefix, sizeof(prefix->addr)); - log_icmp6_nd(nd, "New prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr), + log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", + SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), prefix->len, lifetime, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - lifetime * USEC_PER_SEC, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC)); LIST_PREPEND(prefixes, nd->prefixes, prefix); @@ -455,7 +368,7 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len, prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len); - log_icmp6_nd(nd, "Prefix length mismatch %d/%d using %d", + log_ndisc(nd, "Prefix length mismatch %d/%d using %d", prefix->len, prefix_opt->nd_opt_pi_prefix_len, prefixlen); @@ -463,19 +376,22 @@ static int icmp6_ra_prefix_update(sd_icmp6_nd *nd, ssize_t len, prefix->len = prefixlen; } - log_icmp6_nd(nd, "Update prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(prefix->addr), + log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", + SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), prefix->len, lifetime, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - lifetime * USEC_PER_SEC, 0)); + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime * USEC_PER_SEC, USEC_PER_SEC)); } - r = icmp6_ra_prefix_set_timeout(nd, prefix, lifetime * USEC_PER_SEC); + r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; + + prefix->valid_until = time_now + lifetime * USEC_PER_SEC; return r; } -static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra, +static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len) { void *opt; struct nd_opt_hdr *opt_hdr; @@ -484,8 +400,8 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra, assert_return(ra, -EINVAL); len -= sizeof(*ra); - if (len < ICMP6_OPT_LEN_UNITS) { - log_icmp6_nd(nd, "Router Advertisement below minimum length"); + if (len < NDISC_OPT_LEN_UNITS) { + log_ndisc(nd, "Router Advertisement below minimum length"); return -ENOMSG; } @@ -493,7 +409,7 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra, opt = ra + 1; opt_hdr = opt; - while (len != 0 && len >= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS) { + while (len != 0 && len >= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS) { struct nd_opt_mtu *opt_mtu; uint32_t mtu; struct nd_opt_prefix_info *opt_prefix; @@ -510,7 +426,7 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra, if (mtu != nd->mtu) { nd->mtu = MAX(mtu, IP6_MIN_MTU); - log_icmp6_nd(nd, "Router Advertisement link MTU %d using %d", + log_ndisc(nd, "Router Advertisement link MTU %d using %d", mtu, nd->mtu); } @@ -519,29 +435,29 @@ static int icmp6_ra_parse(sd_icmp6_nd *nd, struct nd_router_advert *ra, case ND_OPT_PREFIX_INFORMATION: opt_prefix = opt; - icmp6_ra_prefix_update(nd, len, opt_prefix); + ndisc_prefix_update(nd, len, opt_prefix); break; } - len -= opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS; + len -= opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS; opt = (void *)((char *)opt + - opt_hdr->nd_opt_len * ICMP6_OPT_LEN_UNITS); + opt_hdr->nd_opt_len * NDISC_OPT_LEN_UNITS); opt_hdr = opt; } if (len > 0) - log_icmp6_nd(nd, "Router Advertisement contains %zd bytes of trailing garbage", len); + log_ndisc(nd, "Router Advertisement contains %zd bytes of trailing garbage", len); return 0; } -static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - sd_icmp6_nd *nd = userdata; +static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + sd_ndisc *nd = userdata; int r, buflen = 0; ssize_t len; _cleanup_free_ struct nd_router_advert *ra = NULL; - int event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE; + int event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE; assert(s); assert(nd); @@ -549,7 +465,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r r = ioctl(fd, FIONREAD, &buflen); if (r < 0 || buflen <= 0) - buflen = ICMP6_ND_RECV_SIZE; + buflen = ICMP6_RECV_SIZE; ra = malloc(buflen); if (!ra) @@ -557,7 +473,7 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r len = read(fd, ra, buflen); if (len < 0) { - log_icmp6_nd(nd, "Could not receive message from UDP socket: %m"); + log_ndisc(nd, "Could not receive message from UDP socket: %m"); return 0; } @@ -569,34 +485,34 @@ static int icmp6_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r nd->timeout = sd_event_source_unref(nd->timeout); - nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN; + nd->state = NDISC_STATE_ADVERTISMENT_LISTEN; if (ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER ) - event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER; + event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER; if (ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) - event = SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED; + event = SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED; - log_icmp6_nd(nd, "Received Router Advertisement flags %s/%s", + log_ndisc(nd, "Received Router Advertisement flags %s/%s", ra->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED? "MANAGED": "none", ra->nd_ra_flags_reserved & ND_RA_FLAG_OTHER? "OTHER": "none"); - if (event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE) { - r = icmp6_ra_parse(nd, ra, len); + if (event != SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE) { + r = ndisc_ra_parse(nd, ra, len); if (r < 0) { - log_icmp6_nd(nd, "Could not parse Router Advertisement: %s", + log_ndisc(nd, "Could not parse Router Advertisement: %s", strerror(-r)); return 0; } } - icmp6_nd_notify(nd, event); + ndisc_notify(nd, event); return 0; } -static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { - sd_icmp6_nd *nd = userdata; +static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { + sd_ndisc *nd = userdata; uint64_t time_now, next_timeout; struct ether_addr unset = { }; struct ether_addr *addr = NULL; @@ -608,89 +524,80 @@ static int icmp6_router_solicitation_timeout(sd_event_source *s, uint64_t usec, nd->timeout = sd_event_source_unref(nd->timeout); - if (nd->nd_sent >= ICMP6_MAX_ROUTER_SOLICITATIONS) { - icmp6_nd_notify(nd, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT); - nd->state = ICMP6_ROUTER_ADVERTISMENT_LISTEN; + if (nd->nd_sent >= NDISC_MAX_ROUTER_SOLICITATIONS) { + ndisc_notify(nd, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT); + nd->state = NDISC_STATE_ADVERTISMENT_LISTEN; } else { if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr))) addr = &nd->mac_addr; - r = dhcp_network_icmp6_send_router_solicitation(nd->fd, addr); + r = icmp6_send_router_solicitation(nd->fd, addr); if (r < 0) - log_icmp6_nd(nd, "Error sending Router Solicitation"); + log_ndisc(nd, "Error sending Router Solicitation"); else { - nd->state = ICMP6_ROUTER_SOLICITATION_SENT; - log_icmp6_nd(nd, "Sent Router Solicitation"); + nd->state = NDISC_STATE_SOLICITATION_SENT; + log_ndisc(nd, "Sent Router Solicitation"); } nd->nd_sent++; - r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) { - icmp6_nd_notify(nd, r); - return 0; - } + assert_se(sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now) >= 0); - next_timeout = time_now + ICMP6_ROUTER_SOLICITATION_INTERVAL; + next_timeout = time_now + NDISC_ROUTER_SOLICITATION_INTERVAL; r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), next_timeout, 0, - icmp6_router_solicitation_timeout, nd); + ndisc_router_solicitation_timeout, nd); if (r < 0) { - icmp6_nd_notify(nd, r); + ndisc_notify(nd, r); return 0; } - r = sd_event_source_set_priority(nd->timeout, - nd->event_priority); - if (r < 0) { - icmp6_nd_notify(nd, r); + r = sd_event_source_set_priority(nd->timeout, nd->event_priority); + if (r < 0) return 0; - } - r = sd_event_source_set_description(nd->timeout, "icmp6-timeout"); - if (r < 0) { - icmp6_nd_notify(nd, r); + r = sd_event_source_set_description(nd->timeout, "ndisc-timeout"); + if (r < 0) return 0; - } } return 0; } -int sd_icmp6_nd_stop(sd_icmp6_nd *nd) { +int sd_ndisc_stop(sd_ndisc *nd) { assert_return(nd, -EINVAL); assert_return(nd->event, -EINVAL); - log_icmp6_nd(client, "Stop ICMPv6"); + log_ndisc(client, "Stop NDisc"); - icmp6_nd_init(nd); + ndisc_init(nd); - nd->state = ICMP6_NEIGHBOR_DISCOVERY_IDLE; + nd->state = NDISC_STATE_IDLE; return 0; } -int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) { +int sd_ndisc_router_discovery_start(sd_ndisc *nd) { int r; assert(nd); assert(nd->event); - if (nd->state != ICMP6_NEIGHBOR_DISCOVERY_IDLE) + if (nd->state != NDISC_STATE_IDLE) return -EINVAL; if (nd->index < 1) return -EINVAL; - r = dhcp_network_icmp6_bind_router_solicitation(nd->index); + r = icmp6_bind_router_solicitation(nd->index); if (r < 0) return r; nd->fd = r; r = sd_event_add_io(nd->event, &nd->recv, nd->fd, EPOLLIN, - icmp6_router_advertisment_recv, nd); + ndisc_router_advertisment_recv, nd); if (r < 0) goto error; @@ -698,12 +605,12 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) { if (r < 0) goto error; - r = sd_event_source_set_description(nd->recv, "icmp6-receive-message"); + r = sd_event_source_set_description(nd->recv, "ndisc-receive-message"); if (r < 0) goto error; r = sd_event_add_time(nd->event, &nd->timeout, clock_boottime_or_monotonic(), - 0, 0, icmp6_router_solicitation_timeout, nd); + 0, 0, ndisc_router_solicitation_timeout, nd); if (r < 0) goto error; @@ -711,12 +618,12 @@ int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd) { if (r < 0) goto error; - r = sd_event_source_set_description(nd->timeout, "icmp6-timeout"); + r = sd_event_source_set_description(nd->timeout, "ndisc-timeout"); error: if (r < 0) - icmp6_nd_init(nd); + ndisc_init(nd); else - log_icmp6_nd(client, "Start Router Solicitation"); + log_ndisc(client, "Start Router Solicitation"); return r; } diff --git a/src/libsystemd-network/sd-pppoe.c b/src/libsystemd-network/sd-pppoe.c deleted file mode 100644 index 439d4eff38..0000000000 --- a/src/libsystemd-network/sd-pppoe.c +++ /dev/null @@ -1,810 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -/* See RFC 2516 */ - -#include <sys/ioctl.h> -#include <linux/ppp_defs.h> -#include <linux/ppp-ioctl.h> -#include <net/if.h> -#include <netinet/in.h> -#include <linux/if_pppox.h> - -#include "sd-pppoe.h" - -#include "event-util.h" - -#include "util.h" -#include "random-util.h" -#include "socket-util.h" -#include "async.h" -#include "utf8.h" - -#define PPPOE_MAX_PACKET_SIZE 1484 -#define PPPOE_MAX_PADR_RESEND 16 - -/* TODO: move this to socket-util.h without getting into - * a mess with the includes */ -union sockaddr_union_pppox { - struct sockaddr sa; - struct sockaddr_pppox pppox; -}; - -typedef enum PPPoEState { - PPPOE_STATE_INITIALIZING, - PPPOE_STATE_REQUESTING, - PPPOE_STATE_RUNNING, - PPPOE_STATE_STOPPED, - _PPPOE_STATE_MAX, - _PPPOE_STATE_INVALID = -1, -} PPPoEState; - -typedef struct PPPoETags { - char *service_name; - char *ac_name; - uint8_t *host_uniq; - size_t host_uniq_len; - uint8_t *cookie; - size_t cookie_len; -} PPPoETags; - -struct sd_pppoe { - unsigned n_ref; - - PPPoEState state; - uint64_t host_uniq; - - int ifindex; - char *ifname; - - sd_event *event; - int event_priority; - int fd; - sd_event_source *io; - sd_event_source *timeout; - int padr_resend_count; - - char *service_name; - struct ether_addr peer_mac; - be16_t session_id; - - int pppoe_fd; - int channel; - - sd_pppoe_cb_t cb; - void *userdata; - - PPPoETags tags; -}; - -#define PPPOE_PACKET_LENGTH(header) \ - be16toh((header)->length) - -#define PPPOE_PACKET_TAIL(packet) \ - (struct pppoe_tag*)((uint8_t*)(packet) + sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet)) - -#define PPPOE_TAG_LENGTH(tag) \ - be16toh((tag)->tag_len) - -#define PPPOE_TAG_TYPE(tag) \ - (tag)->tag_type - -#define PPPOE_TAG_NEXT(tag) \ - (struct pppoe_tag *)((uint8_t *)(tag) + sizeof(struct pppoe_tag) + PPPOE_TAG_LENGTH(tag)) - -#define PPPOE_TAGS_FOREACH(tag, header) \ - for (tag = (header)->tag; \ - ((uint8_t *)(tag) + sizeof(struct pppoe_tag) < (uint8_t*)PPPOE_PACKET_TAIL(header)) && \ - (PPPOE_TAG_NEXT(tag) <= PPPOE_PACKET_TAIL(header)) && \ - (tag >= (header)->tag) && \ - (PPPOE_TAG_TYPE(tag) != PTT_EOL); \ - tag = PPPOE_TAG_NEXT(tag)) - -static void pppoe_tags_clear(PPPoETags *tags) { - free(tags->service_name); - free(tags->ac_name); - free(tags->host_uniq); - free(tags->cookie); - - zero(*tags); -} - -int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex) { - assert_return(ppp, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - - ppp->ifindex = ifindex; - - return 0; -} - -int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname) { - char *name; - - assert_return(ppp, -EINVAL); - assert_return(ifname, -EINVAL); - - if (strlen(ifname) > IFNAMSIZ) - return -EINVAL; - - name = strdup(ifname); - if (!name) - return -ENOMEM; - - free(ppp->ifname); - ppp->ifname = name; - - return 0; -} - -int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name) { - _cleanup_free_ char *name = NULL; - - assert_return(ppp, -EINVAL); - - if (service_name) { - name = strdup(service_name); - if (!name) - return -ENOMEM; - } - - free(ppp->service_name); - ppp->service_name = name; - name = NULL; - - return 0; -} - -int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority) { - int r; - - assert_return(ppp, -EINVAL); - assert_return(!ppp->event, -EBUSY); - - if (event) - ppp->event = sd_event_ref(event); - else { - r = sd_event_default(&ppp->event); - if (r < 0) - return r; - } - - ppp->event_priority = priority; - - return 0; -} - -int sd_pppoe_detach_event(sd_pppoe *ppp) { - assert_return(ppp, -EINVAL); - - ppp->event = sd_event_unref(ppp->event); - - return 0; -} - -sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp) { - - if (!ppp) - return NULL; - - assert(ppp->n_ref > 0); - ppp->n_ref++; - - return ppp; -} - -sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp) { - - if (!ppp) - return NULL; - - assert(ppp->n_ref > 0); - ppp->n_ref--; - - if (ppp->n_ref > 0) - return NULL; - - pppoe_tags_clear(&ppp->tags); - free(ppp->ifname); - free(ppp->service_name); - sd_pppoe_stop(ppp); - sd_pppoe_detach_event(ppp); - - free(ppp); - return NULL; -} - -int sd_pppoe_new (sd_pppoe **ret) { - sd_pppoe *ppp; - - assert_return(ret, -EINVAL); - - ppp = new0(sd_pppoe, 1); - if (!ppp) - return -ENOMEM; - - ppp->n_ref = 1; - ppp->state = _PPPOE_STATE_INVALID; - ppp->ifindex = -1; - ppp->fd = -1; - ppp->pppoe_fd = -1; - ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND; - - *ret = ppp; - - return 0; -} - -int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel) { - assert_return(ppp, -EINVAL); - assert_return(channel, -EINVAL); - assert_return(ppp->pppoe_fd != -1, -EUNATCH); - assert_return(ppp->state == PPPOE_STATE_RUNNING, -EUNATCH); - - *channel = ppp->channel; - - return 0; -} - -int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata) { - assert_return(ppp, -EINVAL); - - ppp->cb = cb; - ppp->userdata = userdata; - - return 0; -} - -static void pppoe_tag_append(struct pppoe_hdr *packet, size_t packet_size, be16_t tag_type, const void *tag_data, uint16_t tag_len) { - struct pppoe_tag *tag; - - assert(packet); - assert(sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len <= packet_size); - assert(!(!tag_data ^ !tag_len)); - - tag = PPPOE_PACKET_TAIL(packet); - - tag->tag_len = htobe16(tag_len); - tag->tag_type = tag_type; - if (tag_data) - memcpy(tag->tag_data, tag_data, tag_len); - - packet->length = htobe16(PPPOE_PACKET_LENGTH(packet) + sizeof(struct pppoe_tag) + tag_len); -} - -static int pppoe_send(sd_pppoe *ppp, uint8_t code) { - union sockaddr_union link = { - .ll = { - .sll_family = AF_PACKET, - .sll_protocol = htons(ETH_P_PPP_DISC), - .sll_halen = ETH_ALEN, - }, - }; - _cleanup_free_ struct pppoe_hdr *packet = NULL; - int r; - - assert(ppp); - assert(ppp->fd != -1); - assert(IN_SET(code, PADI_CODE, PADR_CODE, PADT_CODE)); - - link.ll.sll_ifindex = ppp->ifindex; - if (code == PADI_CODE) - memset(&link.ll.sll_addr, 0xff, ETH_ALEN); - else - memcpy(&link.ll.sll_addr, &ppp->peer_mac, ETH_ALEN); - - packet = malloc0(PPPOE_MAX_PACKET_SIZE); - if (!packet) - return -ENOMEM; - - packet->ver = 0x1; - packet->type = 0x1; - packet->code = code; - if (code == PADT_CODE) - packet->sid = ppp->session_id; - - /* Service-Name */ - pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_SRV_NAME, - ppp->service_name, ppp->service_name ? strlen(ppp->service_name) : 0); - - /* AC-Cookie */ - if (code == PADR_CODE && ppp->tags.cookie) - pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_AC_COOKIE, - ppp->tags.cookie, ppp->tags.cookie_len); - - /* Host-Uniq */ - if (code != PADT_CODE) { - ppp->host_uniq = random_u64(); - - pppoe_tag_append(packet, PPPOE_MAX_PACKET_SIZE, PTT_HOST_UNIQ, - &ppp->host_uniq, sizeof(ppp->host_uniq)); - } - - r = sendto(ppp->fd, packet, sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet), - 0, &link.sa, sizeof(link.ll)); - if (r < 0) - return -errno; - - return 0; -} - -static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata); - -static int pppoe_arm_timeout(sd_pppoe *ppp) { - _cleanup_event_source_unref_ sd_event_source *timeout = NULL; - usec_t next_timeout = 0; - int r; - - assert(ppp); - - r = sd_event_now(ppp->event, clock_boottime_or_monotonic(), &next_timeout); - if (r < 0) - return r; - - next_timeout += 500 * USEC_PER_MSEC; - - r = sd_event_add_time(ppp->event, &timeout, clock_boottime_or_monotonic(), next_timeout, - 10 * USEC_PER_MSEC, pppoe_timeout, ppp); - if (r < 0) - return r; - - r = sd_event_source_set_priority(timeout, ppp->event_priority); - if (r < 0) - return r; - - sd_event_source_unref(ppp->timeout); - ppp->timeout = timeout; - timeout = NULL; - - return 0; -} - -static int pppoe_send_initiation(sd_pppoe *ppp) { - int r; - - r = pppoe_send(ppp, PADI_CODE); - if (r < 0) - return r; - - log_debug("PPPoE: sent DISCOVER (Service-Name: %s)", - ppp->service_name ? : ""); - - pppoe_arm_timeout(ppp); - - return r; -} - -static int pppoe_send_request(sd_pppoe *ppp) { - int r; - - r = pppoe_send(ppp, PADR_CODE); - if (r < 0) - return r; - - log_debug("PPPoE: sent REQUEST"); - - ppp->padr_resend_count --; - - pppoe_arm_timeout(ppp); - - return 0; -} - -static int pppoe_send_terminate(sd_pppoe *ppp) { - int r; - - r = pppoe_send(ppp, PADT_CODE); - if (r < 0) - return r; - - log_debug("PPPoE: sent TERMINATE"); - - return 0; -} - -static int pppoe_timeout(sd_event_source *s, uint64_t usec, void *userdata) { - sd_pppoe *ppp = userdata; - int r; - - assert(ppp); - - switch (ppp->state) { - case PPPOE_STATE_INITIALIZING: - r = pppoe_send_initiation(ppp); - if (r < 0) - log_warning_errno(r, "PPPoE: sending PADI failed: %m"); - - break; - case PPPOE_STATE_REQUESTING: - if (ppp->padr_resend_count <= 0) { - log_debug("PPPoE: PADR timed out, restarting PADI"); - - r = pppoe_send_initiation(ppp); - if (r < 0) - log_warning_errno(r, "PPPoE: sending PADI failed: %m"); - - ppp->padr_resend_count = PPPOE_MAX_PADR_RESEND; - ppp->state = PPPOE_STATE_INITIALIZING; - } else { - r = pppoe_send_request(ppp); - if (r < 0) - log_warning_errno(r, "PPPoE: sending PADR failed: %m"); - } - - break; - default: - assert_not_reached("timeout in invalid state"); - } - - return 0; -} - -static int pppoe_tag_parse_binary(struct pppoe_tag *tag, uint8_t **ret, size_t *length) { - uint8_t *data; - - assert(ret); - assert(length); - - data = memdup(tag->tag_data, PPPOE_TAG_LENGTH(tag)); - if (!data) - return -ENOMEM; - - free(*ret); - *ret = data; - *length = PPPOE_TAG_LENGTH(tag); - - return 0; -} - -static int pppoe_tag_parse_string(struct pppoe_tag *tag, char **ret) { - char *string; - - assert(ret); - - string = strndup(tag->tag_data, PPPOE_TAG_LENGTH(tag)); - if (!string) - return -ENOMEM; - - free(*ret); - *ret = string; - - return 0; -} - -static int pppoe_payload_parse(PPPoETags *tags, struct pppoe_hdr *header) { - struct pppoe_tag *tag; - int r; - - assert(tags); - - pppoe_tags_clear(tags); - - PPPOE_TAGS_FOREACH(tag, header) { - switch (PPPOE_TAG_TYPE(tag)) { - case PTT_SRV_NAME: - r = pppoe_tag_parse_string(tag, &tags->service_name); - if (r < 0) - return r; - - break; - case PTT_AC_NAME: - r = pppoe_tag_parse_string(tag, &tags->ac_name); - if (r < 0) - return r; - - break; - case PTT_HOST_UNIQ: - r = pppoe_tag_parse_binary(tag, &tags->host_uniq, &tags->host_uniq_len); - if (r < 0) - return r; - - break; - case PTT_AC_COOKIE: - r = pppoe_tag_parse_binary(tag, &tags->cookie, &tags->cookie_len); - if (r < 0) - return r; - - break; - case PTT_SRV_ERR: - case PTT_SYS_ERR: - case PTT_GEN_ERR: - { - _cleanup_free_ char *error = NULL; - - /* TODO: do something more sensible with the error messages */ - r = pppoe_tag_parse_string(tag, &error); - if (r < 0) - return r; - - if (strlen(error) > 0 && utf8_is_valid(error)) - log_debug("PPPoE: error - '%s'", error); - else - log_debug("PPPoE: error"); - - break; - } - default: - log_debug("PPPoE: ignoring unknown PPPoE tag type: 0x%.2x", PPPOE_TAG_TYPE(tag)); - } - } - - return 0; -} - -static int pppoe_open_pppoe_socket(sd_pppoe *ppp) { - int s; - - assert(ppp); - assert(ppp->pppoe_fd == -1); - - s = socket(AF_PPPOX, SOCK_STREAM, 0); - if (s < 0) - return -errno; - - ppp->pppoe_fd = s; - - return 0; -} - -static int pppoe_connect_pppoe_socket(sd_pppoe *ppp) { - union sockaddr_union_pppox link = { - .pppox = { - .sa_family = AF_PPPOX, - .sa_protocol = PX_PROTO_OE, - }, - }; - int r, channel; - - assert(ppp); - assert(ppp->pppoe_fd != -1); - assert(ppp->session_id); - assert(ppp->ifname); - - link.pppox.sa_addr.pppoe.sid = ppp->session_id; - memcpy(link.pppox.sa_addr.pppoe.dev, ppp->ifname, strlen(ppp->ifname)); - memcpy(link.pppox.sa_addr.pppoe.remote, &ppp->peer_mac, ETH_ALEN); - - r = connect(ppp->pppoe_fd, &link.sa, sizeof(link.pppox)); - if (r < 0) - return r; - - r = ioctl(ppp->pppoe_fd, PPPIOCGCHAN, &channel); - if (r < 0) - return -errno; - - ppp->channel = channel; - - return 0; -} - -static int pppoe_handle_message(sd_pppoe *ppp, struct pppoe_hdr *packet, struct ether_addr *mac) { - int r; - - assert(packet); - - if (packet->ver != 0x1 || packet->type != 0x1) - return 0; - - r = pppoe_payload_parse(&ppp->tags, packet); - if (r < 0) - return 0; - - switch (ppp->state) { - case PPPOE_STATE_INITIALIZING: - if (packet->code != PADO_CODE) - return 0; - - if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) || - memcmp(ppp->tags.host_uniq, &ppp->host_uniq, sizeof(ppp->host_uniq)) != 0) - return 0; - - log_debug("PPPoE: got OFFER (Peer: " - "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx; " - "Service-Name: '%s'; AC-Name: '%s')", - mac->ether_addr_octet[0], - mac->ether_addr_octet[1], - mac->ether_addr_octet[2], - mac->ether_addr_octet[3], - mac->ether_addr_octet[4], - mac->ether_addr_octet[5], - ppp->tags.service_name ? : "", - ppp->tags.ac_name ? : ""); - - memcpy(&ppp->peer_mac, mac, ETH_ALEN); - - r = pppoe_open_pppoe_socket(ppp); - if (r < 0) { - log_warning("PPPoE: could not open socket"); - return r; - } - - r = pppoe_send_request(ppp); - if (r < 0) - return 0; - - ppp->state = PPPOE_STATE_REQUESTING; - - break; - case PPPOE_STATE_REQUESTING: - if (packet->code != PADS_CODE) - return 0; - - if (ppp->tags.host_uniq_len != sizeof(ppp->host_uniq) || - memcmp(ppp->tags.host_uniq, &ppp->host_uniq, - sizeof(ppp->host_uniq)) != 0) - return 0; - - if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0) - return 0; - - ppp->session_id = packet->sid; - - log_debug("PPPoE: got CONFIRMATION (Session ID: %"PRIu16")", - be16toh(ppp->session_id)); - - r = pppoe_connect_pppoe_socket(ppp); - if (r < 0) { - log_warning("PPPoE: could not connect socket"); - return r; - } - - ppp->state = PPPOE_STATE_RUNNING; - - ppp->timeout = sd_event_source_unref(ppp->timeout); - assert(ppp->cb); - ppp->cb(ppp, SD_PPPOE_EVENT_RUNNING, ppp->userdata); - - break; - case PPPOE_STATE_RUNNING: - if (packet->code != PADT_CODE) - return 0; - - if (memcmp(&ppp->peer_mac, mac, ETH_ALEN) != 0) - return 0; - - if (ppp->session_id != packet->sid) - return 0; - - log_debug("PPPoE: got TERMINATE"); - - ppp->state = PPPOE_STATE_STOPPED; - - assert(ppp->cb); - ppp->cb(ppp, SD_PPPOE_EVENT_STOPPED, ppp->userdata); - - break; - case PPPOE_STATE_STOPPED: - break; - default: - assert_not_reached("PPPoE: invalid state when receiving message"); - } - - return 0; -} - -static int pppoe_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - sd_pppoe *ppp = userdata; - _cleanup_free_ struct pppoe_hdr *packet = NULL; - union sockaddr_union link = {}; - socklen_t addrlen = sizeof(link); - int buflen = 0, len, r; - - assert(ppp); - assert(fd != -1); - - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return r; - - if (buflen < 0) - /* this can't be right */ - return -EIO; - - packet = malloc0(buflen); - if (!packet) - return -ENOMEM; - - len = recvfrom(fd, packet, buflen, 0, &link.sa, &addrlen); - if (len < 0) { - log_warning_errno(r, "PPPoE: could not receive message from raw socket: %m"); - return 0; - } else if ((size_t)len < sizeof(struct pppoe_hdr)) - return 0; - else if ((size_t)len != sizeof(struct pppoe_hdr) + PPPOE_PACKET_LENGTH(packet)) - return 0; - - if (link.ll.sll_halen != ETH_ALEN) - /* not ethernet? */ - return 0; - - r = pppoe_handle_message(ppp, packet, (struct ether_addr*)&link.ll.sll_addr); - if (r < 0) - return r; - - return 1; -} - -int sd_pppoe_start(sd_pppoe *ppp) { - union sockaddr_union link = { - .ll = { - .sll_family = AF_PACKET, - .sll_protocol = htons(ETH_P_PPP_DISC), - }, - }; - _cleanup_close_ int s = -1; - _cleanup_event_source_unref_ sd_event_source *io = NULL; - int r; - - assert_return(ppp, -EINVAL); - assert_return(ppp->fd == -1, -EBUSY); - assert_return(!ppp->io, -EBUSY); - assert_return(ppp->ifindex > 0, -EUNATCH); - assert_return(ppp->ifname, -EUNATCH); - assert_return(ppp->event, -EUNATCH); - assert_return(ppp->cb, -EUNATCH); - - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - link.ll.sll_ifindex = ppp->ifindex; - - r = bind(s, &link.sa, sizeof(link.ll)); - if (r < 0) - return r; - - r = sd_event_add_io(ppp->event, &io, - s, EPOLLIN, pppoe_receive_message, - ppp); - if (r < 0) - return r; - - r = sd_event_source_set_priority(io, ppp->event_priority); - if (r < 0) - return r; - - ppp->fd = s; - s = -1; - ppp->io = io; - io = NULL; - - r = pppoe_send_initiation(ppp); - if (r < 0) - return r; - - ppp->state = PPPOE_STATE_INITIALIZING; - - return 0; -} - -int sd_pppoe_stop(sd_pppoe *ppp) { - assert_return(ppp, -EINVAL); - - if (ppp->state == PPPOE_STATE_RUNNING) - pppoe_send_terminate(ppp); - - ppp->io = sd_event_source_unref(ppp->io); - ppp->timeout = sd_event_source_unref(ppp->timeout); - ppp->fd = asynchronous_close(ppp->fd); - ppp->pppoe_fd = asynchronous_close(ppp->pppoe_fd); - - return 0; -} diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index c112ec8134..5b52c1cbb9 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -24,14 +24,16 @@ #include <sys/socket.h> #include <unistd.h> -#include "util.h" +#include "sd-dhcp-client.h" #include "sd-event.h" -#include "event-util.h" +#include "alloc-util.h" #include "dhcp-identifier.h" -#include "dhcp-protocol.h" #include "dhcp-internal.h" -#include "sd-dhcp-client.h" +#include "dhcp-protocol.h" +#include "event-util.h" +#include "util.h" +#include "fd-util.h" static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'}; diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index b1ef174849..2d29e28f16 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -5,11 +5,11 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "macro.h" - -#include "dhcp-protocol.h" +#include "alloc-util.h" #include "dhcp-internal.h" +#include "dhcp-protocol.h" +#include "macro.h" +#include "util.h" struct option_desc { uint8_t sname[64]; diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 7d8a1f6bd9..1a5c8c4605 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -22,11 +22,11 @@ #include <errno.h> +#include "sd-dhcp-server.h" #include "sd-event.h" -#include "event-util.h" -#include "sd-dhcp-server.h" #include "dhcp-server-internal.h" +#include "event-util.h" static void test_pool(struct in_addr *address, unsigned size, int ret) { _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; @@ -198,6 +198,17 @@ static void test_message_handler(void) { assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); } +static uint64_t client_id_hash_helper(DHCPClientId *id, uint8_t key[HASH_KEY_SIZE]) { + struct siphash state; + uint64_t hash; + + siphash24_init(&state, key); + client_id_hash_func(id, &state); + siphash24_finalize((uint8_t*)&hash, &state); + + return hash; +} + static void test_client_id_hash(void) { DHCPClientId a = { .length = 4, @@ -213,18 +224,18 @@ static void test_client_id_hash(void) { b.data = (uint8_t*)strdup("abcd"); assert_se(client_id_compare_func(&a, &b) == 0); - assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key)); + assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key)); a.length = 3; assert_se(client_id_compare_func(&a, &b) != 0); a.length = 4; assert_se(client_id_compare_func(&a, &b) == 0); - assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key)); + assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key)); b.length = 3; assert_se(client_id_compare_func(&a, &b) != 0); b.length = 4; assert_se(client_id_compare_func(&a, &b) == 0); - assert_se(client_id_hash_func(&a, hash_key) == client_id_hash_func(&b, hash_key)); + assert_se(client_id_hash_helper(&a, hash_key) == client_id_hash_helper(&b, hash_key)); free(b.data); b.data = (uint8_t*)strdup("abce"); diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 0c131a9897..17ed6d58f3 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -19,23 +19,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <net/ethernet.h> #include <stdbool.h> #include <stdio.h> -#include <sys/types.h> #include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> -#include <net/ethernet.h> -#include "socket-util.h" -#include "macro.h" +#include "sd-dhcp6-client.h" #include "sd-event.h" -#include "event-util.h" -#include "virt.h" -#include "sd-dhcp6-client.h" -#include "dhcp6-protocol.h" #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" +#include "dhcp6-protocol.h" +#include "event-util.h" +#include "fd-util.h" +#include "macro.h" +#include "socket-util.h" +#include "virt.h" static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} @@ -700,7 +701,7 @@ int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { static int test_client_solicit(sd_event *e) { sd_dhcp6_client *client; usec_t time_now = now(clock_boottime_or_monotonic()); - bool val = true; + int val = true; if (verbose) printf("* %s\n", __FUNCTION__); diff --git a/src/libsystemd-network/test-icmp6-rs.c b/src/libsystemd-network/test-icmp6-rs.c deleted file mode 100644 index 27b0ef4572..0000000000 --- a/src/libsystemd-network/test-icmp6-rs.c +++ /dev/null @@ -1,357 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <netinet/icmp6.h> - -#include "socket-util.h" - -#include "dhcp6-internal.h" -#include "sd-icmp6-nd.h" - -static struct ether_addr mac_addr = { - .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} -}; - -static bool verbose = false; -static sd_event_source *test_hangcheck; -static int test_fd[2]; - -typedef int (*send_ra_t)(uint8_t flags); -static send_ra_t send_ra_function; - -static int test_rs_hangcheck(sd_event_source *s, uint64_t usec, - void *userdata) { - assert_se(false); - - return 0; -} - -int dhcp_network_icmp6_bind_router_solicitation(int index) { - assert_se(index == 42); - - if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0) - return -errno; - - return test_fd[0]; -} - -static int send_ra_short_prefix(uint8_t flags) { - uint8_t advertisement[] = { - 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x03, 0x04, 0x34, 0xc0, 0x00, 0x00, 0x01, 0xf4, - 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - - assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == - sizeof(advertisement)); - - return 0; -} - -static void test_short_prefix_cb(sd_icmp6_nd *nd, int event, void *userdata) { - sd_event *e = userdata; - struct { - struct in6_addr addr; - uint8_t prefixlen; - bool success; - } addrs[] = { - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 52, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, false }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 60, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }, - 52, true }, - }; - uint8_t prefixlen; - unsigned int i; - - for (i = 0; i < ELEMENTSOF(addrs); i++) { - printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x", - __FUNCTION__, - addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1], - addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3], - addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5], - addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]); - - if (addrs[i].success) { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) >= 0); - assert_se(addrs[i].prefixlen == prefixlen); - printf("/%d onlink\n", prefixlen); - } else { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) == -EADDRNOTAVAIL); - printf("/128 offlink\n"); - } - } - - sd_event_exit(e, 0); -} - -static int send_ra_prefixes(uint8_t flags) { - uint8_t advertisement[] = { - 0x86, 0x00, 0xbe, 0xd7, 0x40, 0xc0, 0x00, 0xb4, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x3f, 0xc0, 0x00, 0x00, 0x01, 0xf4, - 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58, - 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x3c, 0x80, 0x00, 0x00, 0x03, 0x84, - 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x03, 0x84, - 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, - 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53 - }; - - assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == - sizeof(advertisement)); - - return 0; -} - -static void test_prefixes_cb(sd_icmp6_nd *nd, int event, void *userdata) { - sd_event *e = userdata; - struct { - struct in6_addr addr; - uint8_t prefixlen; - bool success; - } addrs[] = { - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 63, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0x0d, 0xad, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, false }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x0b, 0x16, 0xd0, 0x0d, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 60, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x9d, 0xab, 0xcd, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }, - 64, true }, - { { { { 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xed, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } }, - 63, false }, - }; - uint8_t prefixlen; - unsigned int i; - - for (i = 0; i < ELEMENTSOF(addrs); i++) { - printf(" %s prefix %02x%02x:%02x%02x:%02x%02x:%02x%02x", - __FUNCTION__, - addrs[i].addr.s6_addr[0], addrs[i].addr.s6_addr[1], - addrs[i].addr.s6_addr[2], addrs[i].addr.s6_addr[3], - addrs[i].addr.s6_addr[4], addrs[i].addr.s6_addr[5], - addrs[i].addr.s6_addr[6], addrs[i].addr.s6_addr[7]); - - if (addrs[i].success) { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) >= 0); - assert_se(addrs[i].prefixlen == prefixlen); - printf("/%d onlink\n", prefixlen); - } else { - assert_se(sd_icmp6_ra_get_prefixlen(nd, &addrs[i].addr, - &prefixlen) == -EADDRNOTAVAIL); - printf("/128 offlink\n"); - } - } - - send_ra_function = send_ra_short_prefix; - assert_se(sd_icmp6_nd_set_callback(nd, test_short_prefix_cb, e) >= 0); - assert_se(sd_icmp6_nd_stop(nd) >= 0); - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); -} - -static void test_prefixes(void) { - sd_event *e; - sd_icmp6_nd *nd; - - if (verbose) - printf("* %s\n", __FUNCTION__); - - send_ra_function = send_ra_prefixes; - - assert_se(sd_event_new(&e) >= 0); - - assert_se(sd_icmp6_nd_new(&nd) >= 0); - assert_se(nd); - - assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0); - - assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0); - assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0); - assert_se(sd_icmp6_nd_set_callback(nd, test_prefixes_cb, e) >= 0); - - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); - - sd_event_loop(e); - - nd = sd_icmp6_nd_unref(nd); - assert_se(!nd); - - close(test_fd[1]); - - sd_event_unref(e); -} - -static int send_ra(uint8_t flags) { - uint8_t advertisement[] = { - 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4, - 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, - 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, - 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, - }; - - advertisement[5] = flags; - - assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == - sizeof(advertisement)); - - if (verbose) - printf(" sent RA with flag 0x%02x\n", flags); - - return 0; -} - -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { - return send_ra_function(0); -} - -static void test_rs_done(sd_icmp6_nd *nd, int event, void *userdata) { - sd_event *e = userdata; - static int idx = 0; - struct { - uint8_t flag; - int event; - } flag_event[] = { - { 0, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE }, - { ND_RA_FLAG_OTHER, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER }, - { ND_RA_FLAG_MANAGED, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED } - }; - uint32_t mtu; - - assert_se(nd); - - assert_se(event == flag_event[idx].event); - idx++; - - if (verbose) - printf(" got event %d\n", event); - - if (idx < 3) { - send_ra(flag_event[idx].flag); - return; - } - - assert_se(sd_icmp6_ra_get_mtu(nd, &mtu) == -ENOMSG); - - sd_event_exit(e, 0); -} - -static void test_rs(void) { - sd_event *e; - sd_icmp6_nd *nd; - usec_t time_now = now(clock_boottime_or_monotonic()); - - if (verbose) - printf("* %s\n", __FUNCTION__); - - send_ra_function = send_ra; - - assert_se(sd_event_new(&e) >= 0); - - assert_se(sd_icmp6_nd_new(&nd) >= 0); - assert_se(nd); - - assert_se(sd_icmp6_nd_attach_event(nd, e, 0) >= 0); - - assert_se(sd_icmp6_nd_set_index(nd, 42) >= 0); - assert_se(sd_icmp6_nd_set_mac(nd, &mac_addr) >= 0); - assert_se(sd_icmp6_nd_set_callback(nd, test_rs_done, e) >= 0); - - assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), - time_now + 2 *USEC_PER_SEC, 0, - test_rs_hangcheck, NULL) >= 0); - - assert_se(sd_icmp6_nd_stop(nd) >= 0); - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); - assert_se(sd_icmp6_nd_stop(nd) >= 0); - - assert_se(sd_icmp6_router_solicitation_start(nd) >= 0); - - sd_event_loop(e); - - test_hangcheck = sd_event_source_unref(test_hangcheck); - - nd = sd_icmp6_nd_unref(nd); - assert_se(!nd); - - close(test_fd[1]); - - sd_event_unref(e); -} - -int main(int argc, char *argv[]) { - - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); - - test_rs(); - test_prefixes(); - - return 0; -} diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c index dd2e44e7a3..913a929069 100644 --- a/src/libsystemd-network/test-ipv4ll-manual.c +++ b/src/libsystemd-network/test-ipv4ll-manual.c @@ -19,21 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> +#include <net/if.h> +#include <stdlib.h> #include <unistd.h> - #include <linux/veth.h> -#include <net/if.h> #include "sd-event.h" -#include "sd-netlink.h" #include "sd-ipv4ll.h" +#include "sd-netlink.h" -#include "util.h" +#include "alloc-util.h" #include "event-util.h" -#include "netlink-util.h" #include "in-addr-util.h" +#include "netlink-util.h" +#include "parse-util.h" +#include "string-util.h" +#include "util.h" static void ll_handler(sd_ipv4ll *ll, int event, void *userdata) { _cleanup_free_ char *address = NULL; diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index e72204d992..6f416c51e4 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -18,20 +18,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <assert.h> #include <errno.h> #include <stdio.h> -#include <sys/types.h> +#include <stdlib.h> #include <sys/socket.h> +#include <sys/types.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" -#include "event-util.h" - #include "sd-ipv4ll.h" + #include "arp-util.h" +#include "event-util.h" +#include "fd-util.h" +#include "socket-util.h" +#include "util.h" static bool verbose = false; static bool extended = false; @@ -100,6 +101,7 @@ int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_ad } static void test_public_api_setters(sd_event *e) { + struct in_addr address = {}; unsigned seed = 0; sd_ipv4ll *ll; struct ether_addr mac_addr = { @@ -118,6 +120,16 @@ static void test_public_api_setters(sd_event *e) { assert_se(sd_ipv4ll_set_callback(NULL, NULL, NULL) == -EINVAL); assert_se(sd_ipv4ll_set_callback(ll, NULL, NULL) == 0); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + address.s_addr |= htobe32(169U << 24 | 254U << 16); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + address.s_addr |= htobe32(0x00FF); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + address.s_addr |= htobe32(0xF000); + assert_se(sd_ipv4ll_set_address(ll, &address) == 0); + address.s_addr |= htobe32(0x0F00); + assert_se(sd_ipv4ll_set_address(ll, &address) == -EINVAL); + assert_se(sd_ipv4ll_set_address_seed(NULL, seed) == -EINVAL); assert_se(sd_ipv4ll_set_address_seed(ll, seed) == 0); diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 06545aee59..99545d0b8b 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -20,31 +20,41 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <arpa/inet.h> +#include <net/ethernet.h> #include <stdio.h> #include <string.h> -#include <net/ethernet.h> -#include <arpa/inet.h> -#include "macro.h" -#include "lldp.h" +#include "sd-event.h" +#include "sd-lldp.h" + +#include "alloc-util.h" +#include "event-util.h" +#include "fd-util.h" +#include "lldp-network.h" #include "lldp-tlv.h" +#include "lldp.h" +#include "macro.h" +#include "string-util.h" #define TEST_LLDP_PORT "em1" #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp" #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc" +static int test_fd[2]; + static struct ether_addr mac_addr = { .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} }; static int lldp_build_tlv_packet(tlv_packet **ret) { - _cleanup_tlv_packet_free_ tlv_packet *m = NULL; + _cleanup_lldp_packet_unref_ tlv_packet *m = NULL; const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR; struct ether_header ether = { .ether_type = htons(ETHERTYPE_LLDP), }; - /* Append ethernet header */ + /* Append Ethernet header */ memcpy(ðer.ether_dhost, lldp_dst, ETHER_ADDR_LEN); memcpy(ðer.ether_shost, &mac_addr, ETHER_ADDR_LEN); @@ -202,6 +212,15 @@ static int lldp_parse_ttl_tlv(tlv_packet *m) { return 0; } +static int lldp_get_destination_type(tlv_packet *m) { + int dest; + + assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0); + assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE); + + return 0; +} + static int lldp_parse_tlv_packet(tlv_packet *m, int len) { uint8_t subtype; @@ -212,20 +231,241 @@ static int lldp_parse_tlv_packet(tlv_packet *m, int len) { assert_se(lldp_parse_ttl_tlv(m) >= 0); assert_se(lldp_parse_system_desc_tlv(m) >= 0); + assert_se(lldp_get_destination_type(m) >= 0); + return 0; } -int main(int argc, char *argv[]) { - _cleanup_tlv_packet_free_ tlv_packet *tlv = NULL; +static void test_parser(void) { + _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL; /* form a packet */ lldp_build_tlv_packet(&tlv); - /* parse the packet */ tlv_packet_parse_pdu(tlv, tlv->length); - /* verify */ lldp_parse_tlv_packet(tlv, tlv->length); +} + +int lldp_network_bind_raw_socket(int ifindex) { + if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0) + return -errno; + + return test_fd[0]; +} + +static int lldp_handler_calls; +static void lldp_handler (sd_lldp *lldp, int event, void *userdata) { + lldp_handler_calls++; +} + +static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_cb_t cb, void *cb_data) { + int r; + + r = sd_lldp_new(42, "dummy", &mac_addr, lldp); + if (r) + return r; + + r = sd_lldp_attach_event(*lldp, e, 0); + if (r) + return r; + + r = sd_lldp_set_callback(*lldp, cb, cb_data); + if (r) + return r; + + r = sd_lldp_start(*lldp); + if (r) + return r; + + return 0; +} + +static int stop_lldp(sd_lldp *lldp) { + int r; + + r = sd_lldp_stop(lldp); + if (r) + return r; + + r = sd_lldp_detach_event(lldp); + if (r) + return r; + + sd_lldp_free(lldp); + safe_close(test_fd[1]); + + return 0; +} + +static void test_receive_basic_packet(sd_event *e) { + sd_lldp *lldp; + sd_lldp_packet **packets; + uint8_t type, *data; + uint16_t length, ttl; + int dest_type; + char *str; + uint8_t frame[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */ + 0x03, 0x04, 0x05, + 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/ + /* LLDP optional TLVs */ + 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */ + 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */ + 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + + lldp_handler_calls = 0; + assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); + + assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); + sd_event_run(e, 0); + assert_se(lldp_handler_calls == 1); + assert_se(sd_lldp_get_packets(lldp, &packets) == 1); + + assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0); + assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); + assert_se(length == ETH_ALEN); + assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN)); + + assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0); + assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME); + assert_se(length == 3); + assert_se(strneq((char *) data, "1/3", 3)); + + assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0); + assert_se(length == 4); + assert_se(strneq(str, "Port", 4)); + + assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0); + assert_se(length == 3); + assert_se(strneq(str, "SYS", 3)); + + assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0); + assert_se(length == 4); /* This is the real length in the TLV packet */ + assert_se(strneq(str, "foo", 3)); + + assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0); + assert_se(ttl == 120); + + assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0); + assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE); + + sd_lldp_packet_unref(packets[0]); + free(packets); + + assert_se(stop_lldp(lldp) == 0); +} + +static void test_receive_incomplete_packet(sd_event *e) { + sd_lldp *lldp; + sd_lldp_packet **packets; + uint8_t frame[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */ + 0x03, 0x04, 0x05, + 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */ + /* Missing TTL */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + + lldp_handler_calls = 0; + assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); + + assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); + sd_event_run(e, 0); + assert_se(lldp_handler_calls == 0); + assert_se(sd_lldp_get_packets(lldp, &packets) == 0); + + assert_se(stop_lldp(lldp) == 0); +} + +static void test_receive_oui_packet(sd_event *e) { + sd_lldp *lldp; + sd_lldp_packet **packets; + uint32_t id32; + uint16_t id16, len; + uint8_t flags; + char *str; + uint8_t frame[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */ + 0x03, 0x04, 0x05, + 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port TLV: interface name, "1/3" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds*/ + /* LLDP optional TLVs */ + 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x01, /* Port VLAN ID: 0x1234 */ + 0x12, 0x34, + 0xfe, 0x07, 0x00, 0x80, 0xc2, 0x02, /* Port and protocol: flag 1, PPVID 0x7788 */ + 0x01, 0x77, 0x88, + 0xfe, 0x0d, 0x00, 0x80, 0xc2, 0x03, /* VLAN Name: ID 0x1234, name "Vlan51" */ + 0x12, 0x34, 0x06, 0x56, 0x6c, 0x61, + 0x6e, 0x35, 0x31, + 0xfe, 0x06, 0x00, 0x80, 0xc2, 0x06, /* Management VID: 0x0102 */ + 0x01, 0x02, + 0xfe, 0x09, 0x00, 0x80, 0xc2, 0x07, /* Link aggregation: status 1, ID 0x00140012 */ + 0x01, 0x00, 0x14, 0x00, 0x12, + 0x00, 0x00 /* End of LLDPDU */ + }; + + lldp_handler_calls = 0; + assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); + + assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); + sd_event_run(e, 0); + assert_se(lldp_handler_calls == 1); + assert_se(sd_lldp_get_packets(lldp, &packets) == 1); + + assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0); + assert_se(id16 == 0x1234); + + assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0); + assert_se(flags == 1); + assert_se(id16 == 0x7788); + + assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0); + assert_se(id16 == 0x1234); + assert_se(len == 6); + assert_se(strneq(str, "Vlan51", 6)); + + assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0); + assert_se(id16 == 0x0102); + + assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0); + assert_se(flags == 1); + assert_se(id32 == 0x00140012); + + sd_lldp_packet_unref(packets[0]); + free(packets); + + assert_se(stop_lldp(lldp) == 0); +} + +int main(int argc, char *argv[]) { + _cleanup_event_unref_ sd_event *e = NULL; + + test_parser(); + + /* LLDP reception tests */ + assert_se(sd_event_new(&e) == 0); + test_receive_basic_packet(e); + test_receive_incomplete_packet(e); + test_receive_oui_packet(e); return 0; } diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c new file mode 100644 index 0000000000..44eab94e8b --- /dev/null +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -0,0 +1,171 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <netinet/icmp6.h> + +#include "sd-ndisc.h" + +#include "icmp6-util.h" +#include "socket-util.h" + +static struct ether_addr mac_addr = { + .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} +}; + +static bool verbose = false; +static sd_event_source *test_hangcheck; +static int test_fd[2]; + +typedef int (*send_ra_t)(uint8_t flags); +static send_ra_t send_ra_function; + +static int test_rs_hangcheck(sd_event_source *s, uint64_t usec, + void *userdata) { + assert_se(false); + + return 0; +} + +int icmp6_bind_router_solicitation(int index) { + assert_se(index == 42); + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, test_fd) < 0) + return -errno; + + return test_fd[0]; +} + +static int send_ra(uint8_t flags) { + uint8_t advertisement[] = { + 0x86, 0x00, 0xde, 0x83, 0x40, 0xc0, 0x00, 0xb4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x04, 0x40, 0xc0, 0x00, 0x00, 0x01, 0xf4, + 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x20, 0x01, 0x0d, 0xb8, 0xde, 0xad, 0xbe, 0xef, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x1f, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, + 0x03, 0x6c, 0x61, 0x62, 0x05, 0x69, 0x6e, 0x74, + 0x72, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x78, 0x2b, 0xcb, 0xb3, 0x6d, 0x53, + }; + + advertisement[5] = flags; + + assert_se(write(test_fd[1], advertisement, sizeof(advertisement)) == + sizeof(advertisement)); + + if (verbose) + printf(" sent RA with flag 0x%02x\n", flags); + + return 0; +} + +int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { + return send_ra_function(0); +} + +static void test_rs_done(sd_ndisc *nd, int event, void *userdata) { + sd_event *e = userdata; + static int idx = 0; + struct { + uint8_t flag; + int event; + } flag_event[] = { + { 0, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE }, + { ND_RA_FLAG_OTHER, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER }, + { ND_RA_FLAG_MANAGED, SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED } + }; + uint32_t mtu; + + assert_se(nd); + + assert_se(event == flag_event[idx].event); + idx++; + + if (verbose) + printf(" got event %d\n", event); + + if (idx < 3) { + send_ra(flag_event[idx].flag); + return; + } + + assert_se(sd_ndisc_get_mtu(nd, &mtu) == -ENOMSG); + + sd_event_exit(e, 0); +} + +static void test_rs(void) { + sd_event *e; + sd_ndisc *nd; + usec_t time_now = now(clock_boottime_or_monotonic()); + + if (verbose) + printf("* %s\n", __FUNCTION__); + + send_ra_function = send_ra; + + assert_se(sd_event_new(&e) >= 0); + + assert_se(sd_ndisc_new(&nd) >= 0); + assert_se(nd); + + assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0); + + assert_se(sd_ndisc_set_index(nd, 42) >= 0); + assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0); + assert_se(sd_ndisc_set_callback(nd, test_rs_done, e) >= 0); + + assert_se(sd_event_add_time(e, &test_hangcheck, clock_boottime_or_monotonic(), + time_now + 2 *USEC_PER_SEC, 0, + test_rs_hangcheck, NULL) >= 0); + + assert_se(sd_ndisc_stop(nd) >= 0); + assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + assert_se(sd_ndisc_stop(nd) >= 0); + + assert_se(sd_ndisc_router_discovery_start(nd) >= 0); + + sd_event_loop(e); + + test_hangcheck = sd_event_source_unref(test_hangcheck); + + nd = sd_ndisc_unref(nd); + assert_se(!nd); + + close(test_fd[1]); + + sd_event_unref(e); +} + +int main(int argc, char *argv[]) { + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + log_open(); + + test_rs(); + + return 0; +} diff --git a/src/libsystemd-network/test-pppoe.c b/src/libsystemd-network/test-pppoe.c deleted file mode 100644 index 6d71569a26..0000000000 --- a/src/libsystemd-network/test-pppoe.c +++ /dev/null @@ -1,176 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen <teg@jklm.no> - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> - -#include <linux/veth.h> -#include <net/if.h> - -#include "util.h" -#include "sd-event.h" -#include "event-util.h" -#include "sd-netlink.h" -#include "sd-pppoe.h" -#include "process-util.h" - -static void pppoe_handler(sd_pppoe *ppp, int event, void *userdata) { - static int pppoe_state = -1; - sd_event *e = userdata; - - assert_se(ppp); - assert_se(e); - - switch (event) { - case SD_PPPOE_EVENT_RUNNING: - assert_se(pppoe_state == -1); - log_info("running"); - break; - case SD_PPPOE_EVENT_STOPPED: - assert_se(pppoe_state == SD_PPPOE_EVENT_RUNNING); - log_info("stopped"); - assert_se(sd_event_exit(e, 0) >= 0); - break; - default: - assert_not_reached("invalid pppoe event"); - } - - pppoe_state = event; -} - -static int client_run(const char *client_name, sd_event *e) { - sd_pppoe *pppoe; - int client_ifindex; - - client_ifindex = (int) if_nametoindex(client_name); - assert_se(client_ifindex > 0); - - assert_se(sd_pppoe_new(&pppoe) >= 0); - assert_se(sd_pppoe_attach_event(pppoe, e, 0) >= 0); - - assert_se(sd_pppoe_set_ifname(pppoe, "pppoe-client") >= 0); - assert_se(sd_pppoe_set_ifindex(pppoe, client_ifindex) >= 0); - assert_se(sd_pppoe_set_callback(pppoe, pppoe_handler, e) >= 0); - - log_info("starting PPPoE client, it will exit when the server times out and sends PADT"); - - assert_se(sd_pppoe_start(pppoe) >= 0); - - assert_se(sd_event_loop(e) >= 0); - - assert_se(!sd_pppoe_unref(pppoe)); - - return EXIT_SUCCESS; -} - -static int test_pppoe_server(sd_event *e) { - sd_netlink *rtnl; - sd_netlink_message *m; - pid_t pid; - int r, client_ifindex, server_ifindex; - - r = unshare(CLONE_NEWNET); - if (r < 0 && errno == EPERM) - return EXIT_TEST_SKIP; - - assert_se(r >= 0); - - assert_se(sd_netlink_open(&rtnl) >= 0); - assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0); - - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0) >= 0); - assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-server") >= 0); - assert_se(sd_netlink_message_open_container(m, IFLA_LINKINFO) >= 0); - assert_se(sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, "veth") >= 0); - assert_se(sd_netlink_message_open_container(m, VETH_INFO_PEER) >= 0); - assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, "pppoe-client") >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_message_close_container(m) >= 0); - assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0); - - client_ifindex = (int) if_nametoindex("pppoe-client"); - assert_se(client_ifindex > 0); - server_ifindex = (int) if_nametoindex("pppoe-server"); - assert_se(server_ifindex > 0); - - m = sd_netlink_message_unref(m); - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, client_ifindex) >= 0); - assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0); - assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0); - - m = sd_netlink_message_unref(m); - assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_SETLINK, server_ifindex) >= 0); - assert_se(sd_rtnl_message_link_set_flags(m, IFF_UP, IFF_UP) >= 0); - assert_se(sd_netlink_call(rtnl, m, 0, NULL) >= 0); - - pid = fork(); - assert_se(pid >= 0); - if (pid == 0) { - /* let the client send some discover messages before the server is started */ - sleep(2); - - /* TODO: manage pppoe-server-options */ - execlp("pppoe-server", "pppoe-server", "-F", - "-I", "pppoe-server", - "-C", "Test-AC", - "-S", "Service-Default", - "-S", "Service-First-Auxiliary", - "-S", "Service-Second-Auxiliary", - NULL); - assert_not_reached("failed to execute pppoe-server. not installed?"); - } - - client_run("pppoe-client", e); - - assert_se(kill(pid, SIGTERM) >= 0); - assert_se(wait_for_terminate(pid, NULL) >= 0); - - assert_se(!sd_netlink_message_unref(m)); - assert_se(!sd_netlink_unref(rtnl)); - - return EXIT_SUCCESS; -} - -int main(int argc, char *argv[]) { - _cleanup_event_unref_ sd_event *e = NULL; - - log_set_max_level(LOG_DEBUG); - log_parse_environment(); - log_open(); - - assert_se(sd_event_new(&e) >= 0); - - if (argc == 1) { - log_info("running PPPoE client against local server"); - - return test_pppoe_server(e); - } else if (argc == 2) { - log_info("running PPPoE client over '%s'", argv[1]); - - return client_run(argv[1], e); - } else { - log_error("This program takes one or no arguments.\n" - "\t %s [<ifname>]", program_invocation_short_name); - return EXIT_FAILURE; - } -} diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 518cbbb7ed..043ff13e6f 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -477,4 +477,7 @@ global: LIBSYSTEMD_227 { global: sd_bus_default_flush_close; + sd_bus_path_decode_many; + sd_bus_path_encode_many; + sd_listen_fds_with_names; } LIBSYSTEMD_226; diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 5c607f49b1..589a90bbff 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -22,11 +22,12 @@ #include <unistd.h> #include <fcntl.h> -#include "util.h" -#include "process-util.h" +#include "bus-container.h" #include "bus-internal.h" #include "bus-socket.h" -#include "bus-container.h" +#include "fd-util.h" +#include "process-util.h" +#include "util.h" int bus_container_connect_socket(sd_bus *b) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; @@ -217,15 +218,8 @@ int bus_container_connect_kernel(sd_bus *b) { _exit(EXIT_FAILURE); } - cmsg = CMSG_FIRSTHDR(&mh); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); - - mh.msg_controllen = cmsg->cmsg_len; - - if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0) + r = send_one_fd(pair[1], fd, 0); + if (r < 0) _exit(EXIT_FAILURE); _exit(EXIT_SUCCESS); diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index aeb48bedd1..d5bc32e757 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -26,14 +26,19 @@ #include <stddef.h> #include <errno.h> -#include "strv.h" #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-bloom.h" +#include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-control.h" -#include "bus-bloom.h" #include "bus-util.h" -#include "capability.h" +#include "capability-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" _public_ int sd_bus_get_unique_name(sd_bus *bus, const char **unique) { int r; diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index af5f7da11c..0afafc2942 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -22,8 +22,9 @@ #include "bus-internal.h" #include "bus-message.h" #include "bus-signature.h" -#include "bus-util.h" #include "bus-type.h" +#include "bus-util.h" +#include "string-util.h" _public_ int sd_bus_emit_signal( sd_bus *bus, diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 3e8cb0b7d0..2922da3763 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -19,22 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <linux/capability.h> +#include <stdlib.h> -#include "util.h" -#include "formats-util.h" -#include "process-util.h" -#include "terminal-util.h" -#include "capability.h" -#include "cgroup-util.h" -#include "fileio.h" -#include "audit.h" +#include "alloc-util.h" +#include "audit-util.h" +#include "bus-creds.h" +#include "bus-label.h" #include "bus-message.h" #include "bus-util.h" +#include "capability-util.h" +#include "cgroup-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" #include "strv.h" -#include "bus-creds.h" -#include "bus-label.h" +#include "terminal-util.h" +#include "user-util.h" +#include "util.h" enum { CAP_OFFSET_INHERITABLE = 0, diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 8833b9c677..43a7e67a6d 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -19,18 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "capability.h" -#include "strv.h" -#include "macro.h" +#include "alloc-util.h" +#include "bus-dump.h" +#include "bus-internal.h" +#include "bus-message.h" +#include "bus-type.h" #include "cap-list.h" +#include "capability-util.h" +#include "fileio.h" #include "formats-util.h" +#include "locale-util.h" +#include "macro.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" - -#include "bus-message.h" -#include "bus-internal.h" -#include "bus-type.h" -#include "bus-dump.h" +#include "util.h" static char *indent(unsigned level, unsigned flags) { char *p; diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c index 64a5a972ae..239d7245e6 100644 --- a/src/libsystemd/sd-bus/bus-error.c +++ b/src/libsystemd/sd-bus/bus-error.c @@ -20,16 +20,18 @@ ***/ #include <errno.h> -#include <stdlib.h> #include <stdarg.h> #include <stdbool.h> -#include <string.h> #include <stdio.h> - -#include "util.h" -#include "errno-list.h" +#include <stdlib.h> +#include <string.h> #include "sd-bus.h" + +#include "alloc-util.h" +#include "errno-list.h" +#include "string-util.h" +#include "util.h" #include "bus-error.h" BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_standard_errors[] = { @@ -565,7 +567,7 @@ _public_ int sd_bus_error_set_errnof(sd_bus_error *e, int error, const char *for const char *bus_error_message(const sd_bus_error *e, int error) { if (e) { - /* Sometimes the D-Bus server is a little bit too verbose with + /* Sometimes, the D-Bus server is a little bit too verbose with * its error messages, so let's override them here */ if (sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED)) return "Access denied"; diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c index fea796cd30..d9f9cd1c5e 100644 --- a/src/libsystemd/sd-bus/bus-internal.c +++ b/src/libsystemd/sd-bus/bus-internal.c @@ -19,8 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "bus-message.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-message.h" +#include "hexdecoct.h" +#include "string-util.h" bool object_path_is_valid(const char *p) { const char *q; diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index e399701beb..5fc0926f06 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -21,21 +21,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <pthread.h> - -#include "hashmap.h" -#include "prioq.h" -#include "list.h" -#include "util.h" -#include "refcnt.h" -#include "socket-util.h" +#include <sys/socket.h> #include "sd-bus.h" + #include "bus-error.h" -#include "bus-match.h" #include "bus-kernel.h" +#include "bus-match.h" +#include "hashmap.h" #include "kdbus.h" +#include "list.h" +#include "prioq.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" struct reply_callback { sd_bus_message_handler_t callback; diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c index 3149a56397..a90536bac9 100644 --- a/src/libsystemd/sd-bus/bus-introspect.c +++ b/src/libsystemd/sd-bus/bus-introspect.c @@ -19,11 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "bus-introspect.h" -#include "bus-signature.h" #include "bus-internal.h" +#include "bus-introspect.h" #include "bus-protocol.h" +#include "bus-signature.h" +#include "fd-util.h" +#include "fileio.h" +#include "string-util.h" +#include "util.h" int introspect_begin(struct introspect *i, bool trusted) { assert(i); diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 577a8b44c3..6716f6daca 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -34,19 +34,23 @@ #include <libgen.h> #undef basename -#include "util.h" -#include "strv.h" -#include "memfd-util.h" -#include "capability.h" -#include "fileio.h" -#include "formats-util.h" - +#include "alloc-util.h" +#include "bus-bloom.h" #include "bus-internal.h" -#include "bus-message.h" #include "bus-kernel.h" -#include "bus-bloom.h" -#include "bus-util.h" #include "bus-label.h" +#include "bus-message.h" +#include "bus-util.h" +#include "capability-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "memfd-util.h" +#include "parse-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" #define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t)) @@ -1433,12 +1437,12 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al if (!bus || !bus->is_kernel) return -EOPNOTSUPP; - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); if (bus->n_memfd_cache <= 0) { int r; - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); r = memfd_new(bus->description); if (r < 0) @@ -1460,7 +1464,7 @@ int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *al *allocated = c->allocated; fd = c->fd; - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); return fd; } @@ -1484,10 +1488,10 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si return; } - assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0); if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); close_and_munmap(fd, address, mapped); return; @@ -1507,7 +1511,7 @@ void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, si c->allocated = allocated; } - assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0); + assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0); } void bus_kernel_flush_memfd(sd_bus *b) { diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 7234e7926a..55dc7caa53 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -19,10 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-internal.h" -#include "bus-message.h" #include "bus-match.h" +#include "bus-message.h" #include "bus-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hexdecoct.h" +#include "string-util.h" #include "strv.h" /* Example: diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h index 53ee0463ca..bc85af3ec0 100644 --- a/src/libsystemd/sd-bus/bus-match.h +++ b/src/libsystemd/sd-bus/bus-match.h @@ -21,10 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "hashmap.h" - #include "sd-bus.h" +#include "hashmap.h" + enum bus_match_node_type { BUS_MATCH_ROOT, BUS_MATCH_VALUE, diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 72e2b9f785..5c80095bf0 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -23,19 +23,23 @@ #include <fcntl.h> #include <sys/mman.h> -#include "util.h" -#include "utf8.h" -#include "strv.h" -#include "time-util.h" -#include "memfd-util.h" - #include "sd-bus.h" -#include "bus-message.h" + +#include "alloc-util.h" +#include "bus-gvariant.h" #include "bus-internal.h" -#include "bus-type.h" +#include "bus-message.h" #include "bus-signature.h" -#include "bus-gvariant.h" +#include "bus-type.h" #include "bus-util.h" +#include "fd-util.h" +#include "io-util.h" +#include "memfd-util.h" +#include "string-util.h" +#include "strv.h" +#include "time-util.h" +#include "utf8.h" +#include "util.h" static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored); diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h index ff25003461..4c91dbae09 100644 --- a/src/libsystemd/sd-bus/bus-message.h +++ b/src/libsystemd/sd-bus/bus-message.h @@ -21,15 +21,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <byteswap.h> +#include <stdbool.h> #include <sys/socket.h> -#include "macro.h" #include "sd-bus.h" -#include "time-util.h" + #include "bus-creds.h" #include "bus-protocol.h" +#include "macro.h" +#include "time-util.h" struct bus_container { char enclosing; diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 1d061cb9cf..8c472626a8 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -19,15 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" -#include "set.h" +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-introspect.h" #include "bus-message.h" -#include "bus-type.h" #include "bus-signature.h" -#include "bus-introspect.h" -#include "bus-util.h" #include "bus-slot.h" +#include "bus-type.h" +#include "bus-util.h" +#include "set.h" +#include "string-util.h" +#include "strv.h" #include "bus-objects.h" static int node_vtable_get_userdata( @@ -1578,25 +1580,14 @@ _public_ int sd_bus_add_fallback( return bus_add_object(bus, slot, true, prefix, callback, userdata); } -static unsigned long vtable_member_hash_func(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void vtable_member_hash_func(const void *a, struct siphash *state) { const struct vtable_member *m = a; - uint8_t hash_key2[HASH_KEY_SIZE]; - unsigned long ret; assert(m); - ret = string_hash_func(m->path, hash_key); - - /* Use a slightly different hash key for the interface */ - memcpy(hash_key2, hash_key, HASH_KEY_SIZE); - hash_key2[0]++; - ret ^= string_hash_func(m->interface, hash_key2); - - /* And an even different one for the member */ - hash_key2[0]++; - ret ^= string_hash_func(m->member, hash_key2); - - return ret; + string_hash_func(m->path, state); + string_hash_func(m->interface, state); + string_hash_func(m->member, state); } static int vtable_member_compare_func(const void *a, const void *b) { diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index b149ea16da..550bad27ba 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -20,8 +20,11 @@ ***/ #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-control.h" #include "bus-objects.h" +#include "string-util.h" #include "bus-slot.h" sd_bus_slot *bus_slot_allocate( diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index d0b1e3d7dc..a5cb667630 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -20,22 +20,28 @@ ***/ #include <endian.h> +#include <poll.h> #include <stdlib.h> #include <unistd.h> -#include <poll.h> +#include "sd-bus.h" #include "sd-daemon.h" -#include "util.h" -#include "macro.h" -#include "missing.h" -#include "utf8.h" -#include "formats-util.h" -#include "signal-util.h" -#include "sd-bus.h" -#include "bus-socket.h" +#include "alloc-util.h" #include "bus-internal.h" #include "bus-message.h" +#include "bus-socket.h" +#include "fd-util.h" +#include "formats-util.h" +#include "hexdecoct.h" +#include "macro.h" +#include "missing.h" +#include "signal-util.h" +#include "stdio-util.h" +#include "string-util.h" +#include "user-util.h" +#include "utf8.h" +#include "util.h" #define SNDBUF_SIZE (8*1024*1024) diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index e43891be25..fd7e58fcfa 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -20,9 +20,11 @@ ***/ #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-internal.h" #include "bus-track.h" +#include "bus-util.h" struct sd_bus_track { unsigned n_ref; diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h index 581574ab73..ad89e6c911 100644 --- a/src/libsystemd/sd-bus/bus-type.h +++ b/src/libsystemd/sd-bus/bus-type.h @@ -23,9 +23,10 @@ #include <stdbool.h> -#include "macro.h" #include "sd-bus.h" +#include "macro.h" + bool bus_type_is_valid(char c) _const_; bool bus_type_is_valid_in_signature(char c) _const_; bool bus_type_is_basic(char c) _const_; diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c index abe482fc46..71f962b00c 100644 --- a/src/libsystemd/sd-bus/busctl-introspect.c +++ b/src/libsystemd/sd-bus/busctl-introspect.c @@ -19,11 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "xml.h" -#include "sd-bus-vtable.h" +#include "sd-bus.h" +#include "alloc-util.h" #include "busctl-introspect.h" +#include "string-util.h" +#include "util.h" +#include "xml.h" #define NODE_DEPTH_MAX 16 diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 5d07d5809c..452ac7c407 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -21,22 +21,27 @@ #include <getopt.h> -#include "strv.h" -#include "util.h" -#include "log.h" -#include "build.h" -#include "pager.h" -#include "path-util.h" -#include "set.h" - #include "sd-bus.h" -#include "bus-internal.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-dump.h" +#include "bus-internal.h" #include "bus-signature.h" #include "bus-type.h" +#include "bus-util.h" #include "busctl-introspect.h" +#include "escape.h" +#include "fd-util.h" +#include "locale-util.h" +#include "log.h" +#include "pager.h" +#include "parse-util.h" +#include "path-util.h" +#include "set.h" +#include "strv.h" #include "terminal-util.h" +#include "user-util.h" +#include "util.h" static bool arg_no_pager = false; static bool arg_legend = true; @@ -629,22 +634,24 @@ typedef struct Member { uint64_t flags; } Member; -static unsigned long member_hash_func(const void *p, const uint8_t hash_key[]) { +static void member_hash_func(const void *p, struct siphash *state) { const Member *m = p; - unsigned long ul; + uint64_t arity = 1; assert(m); assert(m->type); - ul = string_hash_func(m->type, hash_key); + string_hash_func(m->type, state); + + arity += !!m->name + !!m->interface; + + uint64_hash_func(&arity, state); if (m->name) - ul ^= string_hash_func(m->name, hash_key); + string_hash_func(m->name, state); if (m->interface) - ul ^= string_hash_func(m->interface, hash_key); - - return ul; + string_hash_func(m->interface, state); } static int member_compare_func(const void *a, const void *b) { @@ -1786,9 +1793,7 @@ static int parse_argv(int argc, char *argv[]) { return help(); case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 53d1c6f61d..a8d79b01b0 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -27,28 +27,33 @@ #include <sys/mman.h> #include <pthread.h> -#include "util.h" -#include "macro.h" -#include "strv.h" -#include "missing.h" -#include "def.h" -#include "cgroup-util.h" -#include "hostname-util.h" -#include "bus-label.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-container.h" +#include "bus-control.h" #include "bus-internal.h" -#include "bus-message.h" -#include "bus-type.h" -#include "bus-socket.h" #include "bus-kernel.h" -#include "bus-control.h" +#include "bus-label.h" +#include "bus-message.h" #include "bus-objects.h" -#include "bus-util.h" -#include "bus-container.h" #include "bus-protocol.h" -#include "bus-track.h" #include "bus-slot.h" +#include "bus-socket.h" +#include "bus-track.h" +#include "bus-type.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "def.h" +#include "fd-util.h" +#include "hostname-util.h" +#include "macro.h" +#include "missing.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define log_debug_bus_message(m) \ do { \ @@ -3454,6 +3459,171 @@ _public_ int sd_bus_path_decode(const char *path, const char *prefix, char **ext return 1; } +_public_ int sd_bus_path_encode_many(char **out, const char *path_template, ...) { + _cleanup_strv_free_ char **labels = NULL; + char *path, *path_pos, **label_pos; + const char *sep, *template_pos; + size_t path_length; + va_list list; + int r; + + assert_return(out, -EINVAL); + assert_return(path_template, -EINVAL); + + path_length = strlen(path_template); + + va_start(list, path_template); + for (sep = strchr(path_template, '%'); sep; sep = strchr(sep + 1, '%')) { + const char *arg; + char *label; + + arg = va_arg(list, const char *); + if (!arg) { + va_end(list); + return -EINVAL; + } + + label = bus_label_escape(arg); + if (!label) { + va_end(list); + return -ENOMEM; + } + + r = strv_consume(&labels, label); + if (r < 0) { + va_end(list); + return r; + } + + /* add label length, but account for the format character */ + path_length += strlen(label) - 1; + } + va_end(list); + + path = malloc(path_length + 1); + if (!path) + return -ENOMEM; + + path_pos = path; + label_pos = labels; + + for (template_pos = path_template; *template_pos; ) { + sep = strchrnul(template_pos, '%'); + path_pos = mempcpy(path_pos, template_pos, sep - template_pos); + if (!*sep) + break; + + path_pos = stpcpy(path_pos, *label_pos++); + template_pos = sep + 1; + } + + *path_pos = 0; + *out = path; + return 0; +} + +_public_ int sd_bus_path_decode_many(const char *path, const char *path_template, ...) { + _cleanup_strv_free_ char **labels = NULL; + const char *template_pos, *path_pos; + char **label_pos; + va_list list; + int r; + + /* + * This decodes an object-path based on a template argument. The + * template consists of a verbatim path, optionally including special + * directives: + * + * - Each occurrence of '%' in the template matches an arbitrary + * substring of a label in the given path. At most one such + * directive is allowed per label. For each such directive, the + * caller must provide an output parameter (char **) via va_arg. If + * NULL is passed, the given label is verified, but not returned. + * For each matched label, the *decoded* label is stored in the + * passed output argument, and the caller is responsible to free + * it. Note that the output arguments are only modified if the + * actualy path matched the template. Otherwise, they're left + * untouched. + * + * This function returns <0 on error, 0 if the path does not match the + * template, 1 if it matched. + */ + + assert_return(path, -EINVAL); + assert_return(path_template, -EINVAL); + + path_pos = path; + + for (template_pos = path_template; *template_pos; ) { + const char *sep; + size_t length; + char *label; + + /* verify everything until the next '%' matches verbatim */ + sep = strchrnul(template_pos, '%'); + length = sep - template_pos; + if (strncmp(path_pos, template_pos, length)) + return 0; + + path_pos += length; + template_pos += length; + + if (!*template_pos) + break; + + /* We found the next '%' character. Everything up until here + * matched. We now skip ahead to the end of this label and make + * sure it matches the tail of the label in the path. Then we + * decode the string in-between and save it for later use. */ + + ++template_pos; /* skip over '%' */ + + sep = strchrnul(template_pos, '/'); + length = sep - template_pos; /* length of suffix to match verbatim */ + + /* verify the suffixes match */ + sep = strchrnul(path_pos, '/'); + if (sep - path_pos < (ssize_t)length || + strncmp(sep - length, template_pos, length)) + return 0; + + template_pos += length; /* skip over matched label */ + length = sep - path_pos - length; /* length of sub-label to decode */ + + /* store unescaped label for later use */ + label = bus_label_unescape_n(path_pos, length); + if (!label) + return -ENOMEM; + + r = strv_consume(&labels, label); + if (r < 0) + return r; + + path_pos = sep; /* skip decoded label and suffix */ + } + + /* end of template must match end of path */ + if (*path_pos) + return 0; + + /* copy the labels over to the caller */ + va_start(list, path_template); + for (label_pos = labels; label_pos && *label_pos; ++label_pos) { + char **arg; + + arg = va_arg(list, char **); + if (arg) + *arg = *label_pos; + else + free(*label_pos); + } + va_end(list); + + free(labels); + labels = NULL; + return 1; +} + _public_ int sd_bus_try_close(sd_bus *bus) { int r; diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c index d14110aa04..96a0929a14 100644 --- a/src/libsystemd/sd-bus/test-bus-benchmark.c +++ b/src/libsystemd/sd-bus/test-bus-benchmark.c @@ -21,14 +21,16 @@ #include <sys/wait.h> -#include "def.h" -#include "util.h" -#include "time-util.h" - #include "sd-bus.h" -#include "bus-kernel.h" + +#include "alloc-util.h" #include "bus-internal.h" +#include "bus-kernel.h" #include "bus-util.h" +#include "def.h" +#include "fd-util.h" +#include "time-util.h" +#include "util.h" #define MAX_SIZE (2*1024*1024) diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index 20f1b532b7..767aef63ff 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -24,16 +24,18 @@ #include <unistd.h> #include <fcntl.h> -#include "log.h" -#include "util.h" -#include "macro.h" -#include "formats-util.h" - #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "bus-match.h" #include "bus-internal.h" +#include "bus-match.h" #include "bus-util.h" +#include "formats-util.h" +#include "log.h" +#include "macro.h" +#include "util.h" +#include "fd-util.h" static int match_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { log_info("Match triggered! interface=%s member=%s", strna(sd_bus_message_get_interface(m)), strna(sd_bus_message_get_member(m))); diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c index f586880593..51aa0a9ad0 100644 --- a/src/libsystemd/sd-bus/test-bus-cleanup.c +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -22,9 +22,10 @@ #include <stdio.h> #include "sd-bus.h" -#include "bus-util.h" + #include "bus-internal.h" #include "bus-message.h" +#include "bus-util.h" #include "refcnt.h" static void test_bus_new(void) { diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index b078bdc5f6..931c001788 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -23,14 +23,16 @@ #include <glib.h> #endif -#include "util.h" -#include "macro.h" #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-gvariant.h" -#include "bus-util.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-dump.h" +#include "bus-util.h" +#include "macro.h" +#include "util.h" static void test_bus_gvariant_is_fixed_size(void) { assert_se(bus_gvariant_is_fixed_size("") > 0); diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c index f3d1099dd2..dbdaa69fbe 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c +++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" #include "bus-kernel.h" #include "bus-util.h" +#include "fd-util.h" +#include "log.h" +#include "util.h" static int test_match(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { int *found = userdata; diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c index 6506eaab2e..0080f71d3b 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel.c +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -21,13 +21,15 @@ #include <fcntl.h> -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-kernel.h" #include "bus-util.h" -#include "bus-dump.h" +#include "fd-util.h" +#include "log.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int bus_ref = -1; diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index b203707f27..0747d6a37c 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -30,14 +30,17 @@ #include <dbus/dbus.h> #endif -#include "log.h" -#include "util.h" - #include "sd-bus.h" -#include "bus-message.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-dump.h" #include "bus-label.h" +#include "bus-message.h" +#include "bus-util.h" +#include "fd-util.h" +#include "log.h" +#include "hexdecoct.h" +#include "util.h" static void test_bus_path_encode_unique(void) { _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL; @@ -66,6 +69,36 @@ static void test_bus_path_encode(void) { assert_se(sd_bus_path_decode(e, "/foo/bar", &f) > 0 && streq(f, "foo.bar")); } +static void test_bus_path_encode_many(void) { + _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *f = NULL; + + assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/prefix/bar", "/prefix/%bar", NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar", "/prefix/%/suffix", NULL) == 0); + assert_se(sd_bus_path_decode_many("/prefix/foobar/suffix", "/prefix/%/suffix", &a) == 1 && streq_ptr(a, "foobar")); + assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", &b, &c) == 1 && streq_ptr(b, "foo") && streq_ptr(c, "bar")); + assert_se(sd_bus_path_decode_many("/prefix/one_foo_two/mid/three_bar_four/suffix", "/prefix/one_%_two/mid/three_%_four/suffix", NULL, &d) == 1 && streq_ptr(d, "bar")); + + assert_se(sd_bus_path_decode_many("/foo/bar", "/foo/bar/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/bar", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%bar", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/bar/suffix") == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%%/suffix", NULL, NULL) == 0); /* multiple '%' are treated verbatim */ + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffi", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/suffix", &e) == 1 && streq_ptr(e, "bar")); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/foo/%/%", NULL, NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/%", NULL, NULL, NULL) == 1); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%/%/%", NULL, NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%", NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/%/", NULL, NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%/", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "/%", NULL) == 0); + assert_se(sd_bus_path_decode_many("/foo/bar/suffix", "%", NULL) == 0); + + assert_se(sd_bus_path_encode_many(&f, "/prefix/one_%_two/mid/three_%_four/suffix", "foo", "bar") >= 0 && streq_ptr(f, "/prefix/one_foo_two/mid/three_bar_four/suffix")); +} + static void test_bus_label_escape_one(const char *a, const char *b) { _cleanup_free_ char *t = NULL, *x = NULL, *y = NULL; @@ -393,6 +426,7 @@ int main(int argc, char *argv[]) { test_bus_label_escape(); test_bus_path_encode(); test_bus_path_encode_unique(); + test_bus_path_encode_many(); return 0; } diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 0a35b750b3..5bc72e2355 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -22,16 +22,17 @@ #include <stdlib.h> #include <pthread.h> -#include "log.h" -#include "util.h" -#include "macro.h" -#include "strv.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-util.h" -#include "bus-dump.h" +#include "log.h" +#include "macro.h" +#include "strv.h" +#include "util.h" struct context { int fds[2]; diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c index aef768dc18..428e185769 100644 --- a/src/libsystemd/sd-bus/test-bus-proxy.c +++ b/src/libsystemd/sd-bus/test-bus-proxy.c @@ -23,13 +23,14 @@ #include <fcntl.h> #include <stdlib.h> -#include "util.h" -#include "log.h" - #include "sd-bus.h" + +#include "alloc-util.h" +#include "bus-dump.h" #include "bus-kernel.h" #include "bus-util.h" -#include "bus-dump.h" +#include "log.h" +#include "util.h" typedef struct { const char *sender; diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c index 080d8eddb7..5bf2c1ecf8 100644 --- a/src/libsystemd/sd-bus/test-bus-server.c +++ b/src/libsystemd/sd-bus/test-bus-server.c @@ -19,16 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <pthread.h> - -#include "log.h" -#include "util.h" -#include "macro.h" +#include <stdlib.h> #include "sd-bus.h" + #include "bus-internal.h" #include "bus-util.h" +#include "log.h" +#include "macro.h" +#include "util.h" struct context { int fds[2]; diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c index 17c6188ca0..92a810a7d8 100644 --- a/src/libsystemd/sd-bus/test-bus-signature.c +++ b/src/libsystemd/sd-bus/test-bus-signature.c @@ -19,7 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - +#include "string-util.h" #include "log.h" #include "bus-signature.h" #include "bus-internal.h" diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c index 2d062fc9b5..ff8df61a9e 100644 --- a/src/libsystemd/sd-bus/test-bus-zero-copy.c +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@ -21,14 +21,17 @@ #include <sys/mman.h> -#include "util.h" -#include "log.h" -#include "memfd-util.h" - #include "sd-bus.h" -#include "bus-message.h" -#include "bus-kernel.h" + +#include "alloc-util.h" #include "bus-dump.h" +#include "bus-kernel.h" +#include "bus-message.h" +#include "log.h" +#include "memfd-util.h" +#include "string-util.h" +#include "util.h" +#include "fd-util.h" #define FIRST_ARRAY 17 #define SECOND_ARRAY 33 diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 9ec73406c6..f1e9b7ed1b 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -19,29 +19,46 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <netinet/in.h> -#include <stdlib.h> #include <errno.h> -#include <unistd.h> -#include <string.h> -#include <stdarg.h> -#include <stdio.h> -#include <stddef.h> #include <limits.h> #include <mqueue.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/un.h> +#include <unistd.h> -#include "util.h" +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "parse-util.h" #include "path-util.h" #include "socket-util.h" -#include "sd-daemon.h" +#include "strv.h" +#include "util.h" + +#define SNDBUF_SIZE (8*1024*1024) + +static void unsetenv_all(bool unset_environment) { + + if (!unset_environment) + return; + + unsetenv("LISTEN_PID"); + unsetenv("LISTEN_FDS"); + unsetenv("LISTEN_FDNAMES"); +} _public_ int sd_listen_fds(int unset_environment) { const char *e; - unsigned n; - int r, fd; + int n, r, fd; pid_t pid; e = getenv("LISTEN_PID"); @@ -66,25 +83,68 @@ _public_ int sd_listen_fds(int unset_environment) { goto finish; } - r = safe_atou(e, &n); + r = safe_atoi(e, &n); if (r < 0) goto finish; - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) n; fd ++) { + assert_cc(SD_LISTEN_FDS_START < INT_MAX); + if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) { + r = -EINVAL; + goto finish; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { r = fd_cloexec(fd, true); if (r < 0) goto finish; } - r = (int) n; + r = n; finish: - if (unset_environment) { - unsetenv("LISTEN_PID"); - unsetenv("LISTEN_FDS"); + unsetenv_all(unset_environment); + return r; +} + +_public_ int sd_listen_fds_with_names(int unset_environment, char ***names) { + _cleanup_strv_free_ char **l = NULL; + bool have_names; + int n_names = 0, n_fds; + const char *e; + int r; + + if (!names) + return sd_listen_fds(unset_environment); + + e = getenv("LISTEN_FDNAMES"); + if (e) { + n_names = strv_split_extract(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (n_names < 0) { + unsetenv_all(unset_environment); + return n_names; + } + + have_names = true; + } else + have_names = false; + + n_fds = sd_listen_fds(unset_environment); + if (n_fds <= 0) + return n_fds; + + if (have_names) { + if (n_names != n_fds) + return -EINVAL; + } else { + r = strv_extend_n(&l, "unknown", n_fds); + if (r < 0) + return r; } - return r; + *names = l; + l = NULL; + + return n_fds; } _public_ int sd_is_fifo(int fd, const char *path) { @@ -310,10 +370,15 @@ _public_ int sd_is_socket_unix(int fd, int type, int listening, const char *path _public_ int sd_is_mq(int fd, const char *path) { struct mq_attr attr; - assert_return(fd >= 0, -EBADF); + /* Check that the fd is valid */ + assert_return(fcntl(fd, F_GETFD) >= 0, -errno); - if (mq_getattr(fd, &attr) < 0) + if (mq_getattr(fd, &attr) < 0) { + if (errno == EBADF) + /* A non-mq fd (or an invalid one, but we ruled that out above) */ + return 0; return -errno; + } if (path) { char fpath[PATH_MAX]; @@ -376,12 +441,19 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char goto finish; } + if (strlen(e) > sizeof(sockaddr.un.sun_path)) { + r = -EINVAL; + goto finish; + } + fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); if (fd < 0) { r = -errno; goto finish; } + fd_inc_sndbuf(fd, SNDBUF_SIZE); + iovec.iov_len = strlen(state); strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); @@ -396,9 +468,11 @@ _public_ int sd_pid_notify_with_fds(pid_t pid, int unset_environment, const char if (n_fds > 0 || have_pid) { /* CMSG_SPACE(0) may return value different then zero, which results in miscalculated controllen. */ - msghdr.msg_controllen = (n_fds ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + - CMSG_SPACE(sizeof(struct ucred)) * have_pid; - msghdr.msg_control = alloca(msghdr.msg_controllen); + msghdr.msg_controllen = + (n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) + + (have_pid ? CMSG_SPACE(sizeof(struct ucred)) : 0); + + msghdr.msg_control = alloca0(msghdr.msg_controllen); cmsg = CMSG_FIRSTHDR(&msghdr); if (n_fds > 0) { @@ -498,16 +572,11 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) { } _public_ int sd_booted(void) { - struct stat st; - /* We test whether the runtime unit file directory has been * created. This takes place in mount-setup.c, so is * guaranteed to happen very early during boot. */ - if (lstat("/run/systemd/system/", &st) < 0) - return 0; - - return !!S_ISDIR(st.st_mode); + return laccess("/run/systemd/system/", F_OK) >= 0; } _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { @@ -522,7 +591,7 @@ _public_ int sd_watchdog_enabled(int unset_environment, uint64_t *usec) { r = safe_atou64(s, &u); if (r < 0) goto finish; - if (u <= 0) { + if (u <= 0 || u >= USEC_INFINITY) { r = -EINVAL; goto finish; } diff --git a/src/machine-id-commit/Makefile b/src/libsystemd/sd-device/Makefile index d0b0e8e008..d0b0e8e008 120000 --- a/src/machine-id-commit/Makefile +++ b/src/libsystemd/sd-device/Makefile diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 5eb37e16cb..ae3157ee5e 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -18,15 +18,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "prioq.h" -#include "strv.h" -#include "set.h" - #include "sd-device.h" -#include "device-util.h" +#include "alloc-util.h" #include "device-enumerator-private.h" +#include "device-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "prioq.h" +#include "set.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define DEVICE_ENUMERATE_MAX_DEPTH 256 @@ -812,10 +815,8 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) { if (access("/sys/subsystem", F_OK) >= 0) { /* we have /subsystem/, forget all the old stuff */ r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL); - if (r < 0) { - log_debug("device-enumerator: failed to scan /sys/subsystem: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_debug_errno(r, "device-enumerator: failed to scan /sys/subsystem: %m"); } else { int k; diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 0ec9667744..a13477e753 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -19,25 +19,31 @@ ***/ #include <ctype.h> -#include <sys/types.h> #include <net/if.h> - -#include "util.h" -#include "macro.h" -#include "refcnt.h" -#include "path-util.h" -#include "strxcpyx.h" -#include "fileio.h" -#include "hashmap.h" -#include "set.h" -#include "strv.h" -#include "mkdir.h" +#include <sys/types.h> #include "sd-device.h" -#include "device-util.h" +#include "alloc-util.h" #include "device-internal.h" #include "device-private.h" +#include "device-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hashmap.h" +#include "macro.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "refcnt.h" +#include "set.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "strxcpyx.h" +#include "user-util.h" +#include "util.h" int device_add_property(sd_device *device, const char *key, const char *value) { int r; @@ -200,10 +206,8 @@ static int device_read_db(sd_device *device) { if (r < 0) { if (r == -ENOENT) return 0; - else { - log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r)); - return r; - } + else + return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path); } /* devices with a database entry are initialized */ @@ -247,7 +251,7 @@ static int device_read_db(sd_device *device) { db[i] = '\0'; r = handle_db_line(device, key, value); if (r < 0) - log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r)); + log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value); state = PRE_KEY; } diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h index 49a7b66a2b..d1f34efc2d 100644 --- a/src/libsystemd/sd-device/device-private.h +++ b/src/libsystemd/sd-device/device-private.h @@ -21,6 +21,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> +#include <stdbool.h> +#include <sys/types.h> + +#include "sd-device.h" + int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len); int device_new_from_strv(sd_device **ret, char **strv); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 7cea5a0746..0e49262087 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -19,23 +19,28 @@ ***/ #include <ctype.h> -#include <sys/types.h> #include <net/if.h> +#include <sys/types.h> -#include "util.h" -#include "macro.h" -#include "path-util.h" -#include "strxcpyx.h" +#include "sd-device.h" + +#include "alloc-util.h" +#include "device-internal.h" +#include "device-private.h" +#include "device-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "hashmap.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" #include "set.h" +#include "stat-util.h" +#include "string-util.h" #include "strv.h" - -#include "sd-device.h" - -#include "device-util.h" -#include "device-private.h" -#include "device-internal.h" +#include "strxcpyx.h" +#include "util.h" int device_new_aux(sd_device **ret) { _cleanup_device_unref_ sd_device *device = NULL; @@ -169,11 +174,10 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { /* the device does not exist (any more?) */ return -ENODEV; - log_debug("sd-device: could not canonicalize '%s': %m", _syspath); - return -errno; + return log_debug_errno(errno, "sd-device: could not canonicalize '%s': %m", _syspath); } } else if (r < 0) { - log_debug("sd-device: could not get target of '%s': %s", _syspath, strerror(-r)); + log_debug_errno(r, "sd-device: could not get target of '%s': %m", _syspath); return r; } @@ -296,15 +300,27 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s } else return -EINVAL; } else { - syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", sysname); + char *name; + size_t len = 0; + + /* translate sysname back to sysfs filename */ + name = strdupa(sysname); + while (name[len] != '\0') { + if (name[len] == '/') + name[len] = '!'; + + len ++; + } + + syspath = strjoina("/sys/subsystem/", subsystem, "/devices/", name); if (access(syspath, F_OK) >= 0) return sd_device_new_from_syspath(ret, syspath); - syspath = strjoina("/sys/bus/", subsystem, "/devices/", sysname); + syspath = strjoina("/sys/bus/", subsystem, "/devices/", name); if (access(syspath, F_OK) >= 0) return sd_device_new_from_syspath(ret, syspath); - syspath = strjoina("/sys/class/", subsystem, "/", sysname); + syspath = strjoina("/sys/class/", subsystem, "/", name); if (access(syspath, F_OK) >= 0) return sd_device_new_from_syspath(ret, syspath); } @@ -340,13 +356,10 @@ int device_set_ifindex(sd_device *device, const char *_ifindex) { assert(device); assert(_ifindex); - r = safe_atoi(_ifindex, &ifindex); + r = parse_ifindex(_ifindex, &ifindex); if (r < 0) return r; - if (ifindex <= 0) - return -EINVAL; - r = device_add_property_internal(device, "IFINDEX", _ifindex); if (r < 0) return r; @@ -516,7 +529,7 @@ int device_read_uevent_file(sd_device *device) { /* some devices may not have uevent files, see set_syspath() */ return 0; else if (r < 0) { - log_debug("sd-device: failed to read uevent file '%s': %s", path, strerror(-r)); + log_debug_errno(r, "sd-device: failed to read uevent file '%s': %m", path); return r; } @@ -555,7 +568,7 @@ int device_read_uevent_file(sd_device *device) { r = handle_uevent_line(device, key, value, &major, &minor); if (r < 0) - log_debug("sd-device: failed to handle uevent entry '%s=%s': %s", key, value, strerror(-r)); + log_debug_errno(r, "sd-device: failed to handle uevent entry '%s=%s': %m", key, value); state = PRE_KEY; } @@ -569,7 +582,7 @@ int device_read_uevent_file(sd_device *device) { if (major) { r = device_set_devnum(device, major, minor); if (r < 0) - log_debug("sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %s", major, minor, path, strerror(-r)); + log_debug_errno(r, "sd-device: could not set 'MAJOR=%s' or 'MINOR=%s' from '%s': %m", major, minor, path); } return 0; @@ -616,11 +629,9 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { struct ifreq ifr = {}; int ifindex; - r = safe_atoi(&id[1], &ifr.ifr_ifindex); + r = parse_ifindex(&id[1], &ifr.ifr_ifindex); if (r < 0) return r; - else if (ifr.ifr_ifindex <= 0) - return -EINVAL; sk = socket(PF_INET, SOCK_DGRAM, 0); if (sk < 0) @@ -1271,10 +1282,8 @@ int device_read_db_aux(sd_device *device, bool force) { if (r < 0) { if (r == -ENOENT) return 0; - else { - log_debug("sd-device: failed to read db '%s': %s", path, strerror(-r)); - return r; - } + else + return log_debug_errno(r, "sd-device: failed to read db '%s': %m", path); } /* devices with a database entry are initialized */ @@ -1318,7 +1327,7 @@ int device_read_db_aux(sd_device *device, bool force) { db[i] = '\0'; r = handle_db_line(device, key, value); if (r < 0) - log_debug("sd-device: failed to handle db entry '%c:%s': %s", key, value, strerror(-r)); + log_debug_errno(r, "sd-device: failed to handle db entry '%c:%s': %m", key, value); state = PRE_KEY; } diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h index e7cad9be46..ae020340a5 100644 --- a/src/libsystemd/sd-event/event-util.h +++ b/src/libsystemd/sd-event/event-util.h @@ -21,9 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "sd-event.h" +#include "util.h" + DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref); diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 48a5219275..ee4886700e 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -23,19 +23,22 @@ #include <sys/timerfd.h> #include <sys/wait.h> -#include "sd-id128.h" #include "sd-daemon.h" -#include "macro.h" -#include "prioq.h" +#include "sd-event.h" +#include "sd-id128.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "hashmap.h" -#include "util.h" -#include "time-util.h" +#include "list.h" +#include "macro.h" #include "missing.h" +#include "prioq.h" #include "set.h" -#include "list.h" #include "signal-util.h" - -#include "sd-event.h" +#include "string-util.h" +#include "time-util.h" +#include "util.h" #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC) @@ -242,12 +245,6 @@ static int pending_prioq_compare(const void *a, const void *b) { if (x->pending_iteration > y->pending_iteration) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -277,12 +274,6 @@ static int prepare_prioq_compare(const void *a, const void *b) { if (x->priority > y->priority) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -310,12 +301,6 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { if (x->time.next > y->time.next) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -343,12 +328,6 @@ static int latest_time_prioq_compare(const void *a, const void *b) { if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -370,12 +349,6 @@ static int exit_prioq_compare(const void *a, const void *b) { if (x->priority > y->priority) return 1; - /* Stability for the rest */ - if (x < y) - return -1; - if (x > y) - return 1; - return 0; } @@ -1153,8 +1126,8 @@ _public_ int sd_event_add_signal( callback = signal_exit_callback; r = pthread_sigmask(SIG_SETMASK, NULL, &ss); - if (r < 0) - return -errno; + if (r != 0) + return -r; if (!sigismember(&ss, sig)) return -EBUSY; diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index c092e56b7a..c1a3b49483 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -20,10 +20,12 @@ ***/ #include "sd-event.h" + +#include "fd-util.h" #include "log.h" -#include "util.h" #include "macro.h" #include "signal-util.h" +#include "util.h" static int prepare_handler(sd_event_source *s, void *userdata) { log_info("preparing %c", PTR_TO_INT(userdata)); diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h index fedccdec72..13fddfc8ad 100644 --- a/src/libsystemd/sd-hwdb/hwdb-internal.h +++ b/src/libsystemd/sd-hwdb/hwdb-internal.h @@ -19,6 +19,7 @@ #pragma once #include "sparse-endian.h" +#include "util.h" #define HWDB_SIG { 'K', 'S', 'L', 'P', 'H', 'H', 'R', 'H' } diff --git a/src/libsystemd/sd-hwdb/hwdb-util.h b/src/libsystemd/sd-hwdb/hwdb-util.h index ee020a2942..d366c6fa41 100644 --- a/src/libsystemd/sd-hwdb/hwdb-util.h +++ b/src/libsystemd/sd-hwdb/hwdb-util.h @@ -21,10 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" - #include "sd-hwdb.h" +#include "util.h" + DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb*, sd_hwdb_unref); #define _cleanup_hwdb_unref_ _cleanup_(sd_hwdb_unrefp) diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c index f0316be659..0e034863d6 100644 --- a/src/libsystemd/sd-hwdb/sd-hwdb.c +++ b/src/libsystemd/sd-hwdb/sd-hwdb.c @@ -19,21 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> -#include <string.h> +#include <fnmatch.h> #include <inttypes.h> +#include <stdio.h> #include <stdlib.h> -#include <fnmatch.h> +#include <string.h> #include <sys/mman.h> #include "sd-hwdb.h" +#include "alloc-util.h" +#include "fd-util.h" #include "hashmap.h" -#include "refcnt.h" - -#include "hwdb-util.h" #include "hwdb-internal.h" +#include "hwdb-util.h" +#include "refcnt.h" +#include "string-util.h" struct sd_hwdb { RefCount n_ref; diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index eb539ad318..1e17ea6a06 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -23,10 +23,14 @@ #include <fcntl.h> #include <unistd.h> -#include "util.h" -#include "macro.h" #include "sd-id128.h" + +#include "fd-util.h" +#include "io-util.h" +#include "macro.h" +#include "hexdecoct.h" #include "random-util.h" +#include "util.h" _public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) { unsigned n; diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 265c7c7db2..3f2e459825 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -19,21 +19,33 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <string.h> #include <errno.h> -#include <sys/inotify.h> #include <poll.h> +#include <string.h> +#include <sys/inotify.h> +#include <unistd.h> -#include "util.h" +#include "sd-login.h" + +#include "alloc-util.h" #include "cgroup-util.h" -#include "macro.h" -#include "strv.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" -#include "login-util.h" #include "formats-util.h" +#include "fs-util.h" #include "hostname-util.h" -#include "sd-login.h" +#include "io-util.h" +#include "login-util.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" /* Error codes: * @@ -920,9 +932,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) { *(char*) (mempcpy(buf, word, l)) = 0; - if (safe_atoi(buf, &ifi) < 0) - continue; - if (ifi <= 0) + if (parse_ifindex(buf, &ifi) < 0) continue; if (!GREEDY_REALLOC(ni, allocated, nr+1)) { diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index f734ce9eee..b0f94c9522 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -22,11 +22,14 @@ #include <poll.h> #include <string.h> -#include "systemd/sd-login.h" +#include "sd-login.h" -#include "util.h" -#include "strv.h" +#include "alloc-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static void test_login(void) { _cleanup_close_pair_ int pair[2] = { -1, -1 }; diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c index e2f637f7f9..a00865b56b 100644 --- a/src/libsystemd/sd-netlink/local-addresses.c +++ b/src/libsystemd/sd-netlink/local-addresses.c @@ -21,6 +21,8 @@ ***/ #include "sd-netlink.h" + +#include "alloc-util.h" #include "netlink-util.h" #include "macro.h" #include "local-addresses.h" diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 4026e2c341..8519a4d523 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -23,13 +23,12 @@ #include <linux/netlink.h> -#include "refcnt.h" -#include "prioq.h" -#include "list.h" - #include "sd-netlink.h" +#include "list.h" #include "netlink-types.h" +#include "prioq.h" +#include "refcnt.h" #define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC)) @@ -64,6 +63,9 @@ struct sd_netlink { struct sockaddr_nl nl; } sockaddr; + Hashmap *broadcast_group_refs; + bool broadcast_group_dont_leave:1; /* until we can rely on 4.2 */ + sd_netlink_message **rqueue; unsigned rqueue_size; size_t rqueue_allocated; @@ -124,7 +126,8 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret); int socket_open(int family); int socket_bind(sd_netlink *nl); -int socket_join_broadcast_group(sd_netlink *nl, unsigned group); +int socket_broadcast_group_ref(sd_netlink *nl, unsigned group); +int socket_broadcast_group_unref(sd_netlink *nl, unsigned group); int socket_write_message(sd_netlink *nl, sd_netlink_message *m); int socket_read_message(sd_netlink *nl); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 0d8e37b856..03971b3596 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -23,16 +23,17 @@ #include <stdbool.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" +#include "sd-netlink.h" + +#include "alloc-util.h" #include "formats-util.h" -#include "refcnt.h" #include "missing.h" - -#include "sd-netlink.h" -#include "netlink-util.h" #include "netlink-internal.h" #include "netlink-types.h" +#include "netlink-util.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL) #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr; @@ -149,6 +150,15 @@ int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) { return 0; } +int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) { + assert_return(m, -EINVAL); + assert_return(flags, -EINVAL); + + m->hdr->nlmsg_flags = flags; + + return 0; +} + int sd_netlink_message_is_broadcast(sd_netlink_message *m) { assert_return(m, -EINVAL); diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 84ff7c38c9..13945202e4 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -23,16 +23,17 @@ #include <stdbool.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" +#include "sd-netlink.h" + +#include "alloc-util.h" #include "formats-util.h" -#include "refcnt.h" #include "missing.h" - -#include "sd-netlink.h" -#include "netlink-util.h" #include "netlink-internal.h" #include "netlink-types.h" +#include "netlink-util.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" int socket_open(int family) { int fd; @@ -44,6 +45,65 @@ int socket_open(int family) { return fd; } +static int broadcast_groups_get(sd_netlink *nl) { + _cleanup_free_ uint32_t *groups = NULL; + socklen_t len = 0, old_len; + unsigned i, j; + int r; + + assert(nl); + assert(nl->fd > 0); + + r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len); + if (r < 0) { + if (errno == ENOPROTOOPT) { + nl->broadcast_group_dont_leave = true; + return 0; + } else + return -errno; + } + + if (len == 0) + return 0; + + groups = new0(uint32_t, len); + if (!groups) + return -ENOMEM; + + old_len = len; + + r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, groups, &len); + if (r < 0) + return -errno; + + if (old_len != len) + return -EIO; + + r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL); + if (r < 0) + return r; + + for (i = 0; i < len; i++) { + for (j = 0; j < sizeof(uint32_t) * 8; j ++) { + uint32_t offset; + unsigned group; + + offset = 1U << j; + + if (!(groups[i] & offset)) + continue; + + group = i * sizeof(uint32_t) * 8 + j + 1; + + r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1)); + if (r < 0) + return r; + } + } + + return 0; +} + int socket_bind(sd_netlink *nl) { socklen_t addrlen; int r, one = 1; @@ -63,11 +123,32 @@ int socket_bind(sd_netlink *nl) { if (r < 0) return -errno; + r = broadcast_groups_get(nl); + if (r < 0) + return r; + return 0; } +static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) { + assert(nl); + + return PTR_TO_UINT(hashmap_get(nl->broadcast_group_refs, UINT_TO_PTR(group))); +} -int socket_join_broadcast_group(sd_netlink *nl, unsigned group) { +static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_ref) { + int r; + + assert(nl); + + r = hashmap_replace(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(n_ref)); + if (r < 0) + return r; + + return 0; +} + +static int broadcast_group_join(sd_netlink *nl, unsigned group) { int r; assert(nl); @@ -81,6 +162,79 @@ int socket_join_broadcast_group(sd_netlink *nl, unsigned group) { return 0; } +int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) { + unsigned n_ref; + int r; + + assert(nl); + + n_ref = broadcast_group_get_ref(nl, group); + + n_ref ++; + + r = hashmap_ensure_allocated(&nl->broadcast_group_refs, NULL); + if (r < 0) + return r; + + r = broadcast_group_set_ref(nl, group, n_ref); + if (r < 0) + return r; + + if (n_ref > 1) + /* not yet in the group */ + return 0; + + r = broadcast_group_join(nl, group); + if (r < 0) + return r; + + return 0; +} + +static int broadcast_group_leave(sd_netlink *nl, unsigned group) { + int r; + + assert(nl); + assert(nl->fd >= 0); + assert(group > 0); + + if (nl->broadcast_group_dont_leave) + return 0; + + r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group)); + if (r < 0) + return -errno; + + return 0; +} + +int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) { + unsigned n_ref; + int r; + + assert(nl); + + n_ref = broadcast_group_get_ref(nl, group); + + assert(n_ref > 0); + + n_ref --; + + r = broadcast_group_set_ref(nl, group, n_ref); + if (r < 0) + return r; + + if (n_ref > 0) + /* still refs left */ + return 0; + + r = broadcast_group_leave(nl, group); + if (r < 0) + return r; + + return 0; +} + /* returns the number of bytes sent, or a negative error code */ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) { union { diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 2128329191..cf0a6248d6 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -28,16 +28,15 @@ #include <linux/if_bridge.h> #include <linux/if_addr.h> #include <linux/if.h> - #include <linux/ip.h> #include <linux/if_link.h> #include <linux/if_tunnel.h> #include "macro.h" -#include "util.h" - -#include "netlink-types.h" #include "missing.h" +#include "netlink-types.h" +#include "string-table.h" +#include "util.h" /* Maximum ARP IP target defined in kernel */ #define BOND_MAX_ARP_TARGETS 16 @@ -97,7 +96,7 @@ static const NLType rtnl_link_info_data_macvlan_types[IFLA_MACVLAN_MAX + 1] = { [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = { +static const NLType rtnl_link_bridge_management_types[IFLA_BRIDGE_MAX + 1] = { [IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 }, [IFLA_BRIDGE_MODE] = { .type = NETLINK_TYPE_U16 }, /* @@ -106,6 +105,15 @@ static const NLType rtnl_link_info_data_bridge_types[IFLA_BRIDGE_MAX + 1] = { */ }; +static const NLType rtnl_link_info_data_bridge_types[IFLA_BR_MAX + 1] = { + [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_MAX_AGE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_AGEING_TIME] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_STP_STATE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_BR_PRIORITY] = { .type = NETLINK_TYPE_U16 }, +}; + static const NLType rtnl_link_info_data_vlan_types[IFLA_VLAN_MAX + 1] = { [IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 }, /* diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 482ff6b1c2..6f9fd2993b 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -19,7 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - #include "sd-netlink.h" #include "netlink-util.h" diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index 9df0aa28bf..acc6c15ff3 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -21,9 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-netlink.h" #include "util.h" -#include "sd-netlink.h" int rtnl_message_new_synthetic_error(int error, uint32_t serial, sd_netlink_message **ret); uint32_t rtnl_message_get_serial(sd_netlink_message *m); diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 2f31f4ee69..7cccb9b1d5 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -23,16 +23,16 @@ #include <stdbool.h> #include <unistd.h> -#include "util.h" -#include "socket-util.h" +#include "sd-netlink.h" + #include "formats-util.h" -#include "refcnt.h" #include "missing.h" - -#include "sd-netlink.h" -#include "netlink-util.h" #include "netlink-internal.h" #include "netlink-types.h" +#include "netlink-util.h" +#include "refcnt.h" +#include "socket-util.h" +#include "util.h" int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) { struct rtmsg *rtm; @@ -99,6 +99,66 @@ int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) { return 0; } +int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(protocol, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *protocol = rtm->rtm_protocol; + + return 0; +} + +int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(scope, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *scope = rtm->rtm_scope; + + return 0; +} + +int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(tos, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *tos = rtm->rtm_tos; + + return 0; +} + +int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) { + struct rtmsg *rtm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); + assert_return(table, -EINVAL); + + rtm = NLMSG_DATA(m->hdr); + + *table = rtm->rtm_table; + + return 0; +} + int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) { struct rtmsg *rtm; diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index d248869c8d..7c24e053cf 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -19,17 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <poll.h> - -#include "missing.h" -#include "macro.h" -#include "util.h" -#include "hashmap.h" +#include <sys/socket.h> #include "sd-netlink.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "hashmap.h" +#include "macro.h" +#include "missing.h" #include "netlink-internal.h" #include "netlink-util.h" +#include "socket-util.h" +#include "util.h" static int sd_netlink_new(sd_netlink **ret) { _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; @@ -183,10 +186,11 @@ sd_netlink *sd_netlink_unref(sd_netlink *rtnl) { sd_event_unref(rtnl->event); while ((f = rtnl->match_callbacks)) { - LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f); - free(f); + sd_netlink_remove_match(rtnl, f->type, f->callback, f->userdata); } + hashmap_free(rtnl->broadcast_group_refs); + safe_close(rtnl->fd); free(rtnl); } @@ -856,26 +860,33 @@ int sd_netlink_add_match(sd_netlink *rtnl, switch (type) { case RTM_NEWLINK: - case RTM_SETLINK: - case RTM_GETLINK: case RTM_DELLINK: - r = socket_join_broadcast_group(rtnl, RTNLGRP_LINK); + r = socket_broadcast_group_ref(rtnl, RTNLGRP_LINK); if (r < 0) return r; break; case RTM_NEWADDR: - case RTM_GETADDR: case RTM_DELADDR: - r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV4_IFADDR); + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_IFADDR); if (r < 0) return r; - r = socket_join_broadcast_group(rtnl, RTNLGRP_IPV6_IFADDR); + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_IFADDR); if (r < 0) return r; break; + case RTM_NEWROUTE: + case RTM_DELROUTE: + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV4_ROUTE); + if (r < 0) + return r; + + r = socket_broadcast_group_ref(rtnl, RTNLGRP_IPV6_ROUTE); + if (r < 0) + return r; + break; default: return -EOPNOTSUPP; } @@ -892,23 +903,50 @@ int sd_netlink_remove_match(sd_netlink *rtnl, sd_netlink_message_handler_t callback, void *userdata) { struct match_callback *c; + int r; assert_return(rtnl, -EINVAL); assert_return(callback, -EINVAL); assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - /* we should unsubscribe from the broadcast groups at this point, but it is not so - trivial for a few reasons: the refcounting is a bit of a mess and not obvious - how it will look like after we add genetlink support, and it is also not possible - to query what broadcast groups were subscribed to when we inherit the socket to get - the initial refcount. The latter could indeed be done for the first 32 broadcast - groups (which incidentally is all we currently support in .socket units anyway), - but we better not rely on only ever using 32 groups. */ LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) if (c->callback == callback && c->type == type && c->userdata == userdata) { LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c); free(c); + switch (type) { + case RTM_NEWLINK: + case RTM_DELLINK: + r = socket_broadcast_group_unref(rtnl, RTNLGRP_LINK); + if (r < 0) + return r; + + break; + case RTM_NEWADDR: + case RTM_DELADDR: + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_IFADDR); + if (r < 0) + return r; + + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_IFADDR); + if (r < 0) + return r; + + break; + case RTM_NEWROUTE: + case RTM_DELROUTE: + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV4_ROUTE); + if (r < 0) + return r; + + r = socket_broadcast_group_unref(rtnl, RTNLGRP_IPV6_ROUTE); + if (r < 0) + return r; + break; + default: + return -EOPNOTSUPP; + } + return 1; } diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c index 9867eec065..7180175970 100644 --- a/src/libsystemd/sd-netlink/test-local-addresses.c +++ b/src/libsystemd/sd-netlink/test-local-addresses.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "in-addr-util.h" #include "local-addresses.h" #include "af-list.h" diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index c9cb415ca0..58b774e0e1 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -19,16 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/ether.h> #include <net/if.h> +#include <netinet/ether.h> -#include "util.h" -#include "macro.h" #include "sd-netlink.h" -#include "socket-util.h" -#include "netlink-util.h" + +#include "ether-addr-util.h" #include "event-util.h" +#include "macro.h" #include "missing.h" +#include "netlink-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" static void test_message_link_bridge(sd_netlink *rtnl) { _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index 48958e8a9f..a2d6c59314 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" +#include "alloc-util.h" +#include "fd-util.h" #include "network-util.h" +#include "strv.h" bool network_is_online(void) { _cleanup_free_ char *state = NULL; diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 87d87359b8..efbceba83d 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -20,16 +20,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> -#include <sys/inotify.h> #include <poll.h> +#include <string.h> +#include <sys/inotify.h> -#include "util.h" +#include "sd-network.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" #include "macro.h" +#include "parse-util.h" +#include "string-util.h" #include "strv.h" -#include "fileio.h" -#include "sd-network.h" +#include "util.h" _public_ int sd_network_get_operational_state(char **state) { _cleanup_free_ char *s = NULL; diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c index 7363be2794..480f1ad065 100644 --- a/src/libsystemd/sd-path/sd-path.c +++ b/src/libsystemd/sd-path/sd-path.c @@ -17,12 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "sd-path.h" + +#include "alloc-util.h" #include "architecture.h" +#include "fd-util.h" +#include "fileio.h" +#include "missing.h" #include "path-util.h" +#include "string-util.h" #include "strv.h" -#include "sd-path.h" -#include "missing.h" +#include "user-util.h" +#include "util.h" static int from_environment(const char *envname, const char *fallback, const char **ret) { assert(ret); diff --git a/src/libsystemd/sd-resolve/resolve-util.h b/src/libsystemd/sd-resolve/resolve-util.h index 019cdaffe1..51a8a8af83 100644 --- a/src/libsystemd/sd-resolve/resolve-util.h +++ b/src/libsystemd/sd-resolve/resolve-util.h @@ -21,9 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "sd-resolve.h" +#include "util.h" + DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve*, sd_resolve_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve_query*, sd_resolve_query_unref); diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 888b372c99..34a0b03f92 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -19,24 +19,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <signal.h> -#include <unistd.h> -#include <stdio.h> -#include <string.h> -#include <stdlib.h> #include <errno.h> +#include <poll.h> +#include <pthread.h> #include <resolv.h> +#include <signal.h> #include <stdint.h> -#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/prctl.h> -#include <poll.h> +#include <unistd.h> -#include "util.h" +#include "sd-resolve.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "list.h" -#include "socket-util.h" #include "missing.h" #include "resolve-util.h" -#include "sd-resolve.h" +#include "socket-util.h" +#include "util.h" #define WORKERS_MIN 1U #define WORKERS_MAX 16U @@ -580,12 +584,8 @@ static void resolve_free(sd_resolve *resolve) { } /* Now terminate them and wait until they are gone. */ - for (i = 0; i < resolve->n_valid_workers; i++) { - for (;;) { - if (pthread_join(resolve->workers[i], NULL) != EINTR) - break; - } - } + for (i = 0; i < resolve->n_valid_workers; i++) + pthread_join(resolve->workers[i], NULL); /* Close all communication channels */ for (i = 0; i < _FD_MAX; i++) diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c index e8056529f5..05544a584c 100644 --- a/src/libsystemd/sd-resolve/test-resolve.c +++ b/src/libsystemd/sd-resolve/test-resolve.c @@ -20,18 +20,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <sys/socket.h> #include <arpa/inet.h> -#include <stdio.h> +#include <errno.h> #include <netinet/in.h> #include <resolv.h> -#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> -#include "socket-util.h" #include "sd-resolve.h" -#include "resolve-util.h" + +#include "alloc-util.h" #include "macro.h" +#include "resolve-util.h" +#include "socket-util.h" +#include "string-util.h" static int getaddrinfo_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, void *userdata) { const struct addrinfo *i; diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c index 6f2aa6064c..381397cc52 100644 --- a/src/libsystemd/sd-utf8/sd-utf8.c +++ b/src/libsystemd/sd-utf8/sd-utf8.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "sd-utf8.h" + #include "util.h" #include "utf8.h" -#include "sd-utf8.h" _public_ const char *sd_utf8_is_valid(const char *s) { assert_return(s, NULL); diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h index aa36b8cb12..40d59201cf 100644 --- a/src/libudev/libudev-device-internal.h +++ b/src/libudev/libudev-device-internal.h @@ -21,9 +21,10 @@ #pragma once #include "libudev.h" -#include "libudev-private.h" #include "sd-device.h" +#include "libudev-private.h" + /** * udev_device: * diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c index 4b9c053b54..2d3e62410c 100644 --- a/src/libudev/libudev-device-private.c +++ b/src/libudev/libudev-device-private.c @@ -19,10 +19,10 @@ ***/ #include "libudev.h" -#include "libudev-private.h" -#include "libudev-device-internal.h" #include "device-private.h" +#include "libudev-device-internal.h" +#include "libudev-private.h" int udev_device_tag_index(struct udev_device *udev_device, struct udev_device *udev_device_old, bool add) { sd_device *device_old = NULL; diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index 9a8d682107..814e016800 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -18,29 +18,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdbool.h> -#include <errno.h> -#include <string.h> +#include <ctype.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> -#include <ctype.h> +#include <linux/sockios.h> #include <net/if.h> -#include <sys/stat.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <sys/socket.h> -#include <linux/sockios.h> +#include <sys/stat.h> +#include <unistd.h> +#include "libudev.h" #include "sd-device.h" -#include "device-util.h" -#include "device-private.h" -#include "libudev.h" -#include "libudev-private.h" +#include "alloc-util.h" +#include "device-private.h" +#include "device-util.h" #include "libudev-device-internal.h" +#include "libudev-private.h" +#include "parse-util.h" /** * SECTION:libudev-device diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c index df088946df..442f9615f2 100644 --- a/src/libudev/libudev-enumerate.c +++ b/src/libudev/libudev-enumerate.c @@ -18,22 +18,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <errno.h> -#include <string.h> #include <dirent.h> +#include <errno.h> #include <fnmatch.h> #include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include "libudev.h" -#include "libudev-device-internal.h" #include "sd-device.h" -#include "device-util.h" -#include "device-enumerator-private.h" +#include "alloc-util.h" +#include "device-enumerator-private.h" +#include "device-util.h" +#include "libudev-device-internal.h" /** * SECTION:libudev-enumerate diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c index 98951fb85b..eba698d163 100644 --- a/src/libudev/libudev-hwdb.c +++ b/src/libudev/libudev-hwdb.c @@ -17,9 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "libudev-private.h" #include "sd-hwdb.h" + +#include "alloc-util.h" #include "hwdb-util.h" +#include "libudev-private.h" /** * SECTION:libudev-hwdb diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c index 19e9130be0..da496ed456 100644 --- a/src/libudev/libudev-list.c +++ b/src/libudev/libudev-list.c @@ -17,11 +17,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stddef.h> #include <errno.h> +#include <stddef.h> +#include <stdlib.h> #include <string.h> +#include "alloc-util.h" #include "libudev-private.h" /** diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index 282aa2b0d9..f870eba9eb 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -17,22 +17,28 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> +#include <linux/filter.h> +#include <linux/netlink.h> +#include <poll.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> #include <string.h> -#include <poll.h> #include <sys/socket.h> -#include <linux/netlink.h> -#include <linux/filter.h> +#include <unistd.h> #include "libudev.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" #include "libudev-private.h" -#include "socket-util.h" #include "missing.h" -#include "formats-util.h" +#include "mount-util.h" +#include "socket-util.h" +#include "string-util.h" /** * SECTION:libudev-monitor @@ -408,10 +414,8 @@ _public_ int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) if (err >= 0) monitor_set_nl_address(udev_monitor); - else { - log_debug_errno(errno, "bind failed: %m"); - return -errno; - } + else + return log_debug_errno(errno, "bind failed: %m"); /* enable receiving of sender credentials */ err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 1240ea79cc..5f50496291 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -25,10 +25,11 @@ #include <stdbool.h> #include "libudev.h" + #include "macro.h" -#include "util.h" #include "mkdir.h" #include "strxcpyx.h" +#include "util.h" #define READ_END 0 #define WRITE_END 1 @@ -135,8 +136,6 @@ int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_expor #define UTIL_NAME_SIZE 512 #define UTIL_LINE_SIZE 16384 #define UDEV_ALLOWED_CHARS_INPUT "/ $%?," -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size); -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size); int util_log_priority(const char *priority); size_t util_path_encode(const char *src, char *dest, size_t size); void util_remove_trailing_chars(char *path, char c); diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c index 11e15d13e6..58410b1b8f 100644 --- a/src/libudev/libudev-queue.c +++ b/src/libudev/libudev-queue.c @@ -24,6 +24,9 @@ #include <errno.h> #include <sys/inotify.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "libudev-private.h" /** diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index f4656277c6..574cfeac85 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -17,18 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> +#include <ctype.h> #include <errno.h> +#include <stddef.h> +#include <stdlib.h> #include <string.h> -#include <ctype.h> +#include <unistd.h> -#include "device-nodes.h" #include "libudev.h" + +#include "MurmurHash2.h" +#include "device-nodes.h" #include "libudev-private.h" +#include "syslog-util.h" #include "utf8.h" -#include "MurmurHash2.h" /** * SECTION:libudev-util @@ -100,52 +102,6 @@ int util_resolve_subsys_kernel(struct udev *udev, const char *string, return 0; } -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size) -{ - char path[UTIL_PATH_SIZE]; - char target[UTIL_PATH_SIZE]; - ssize_t len; - const char *pos; - - strscpyl(path, sizeof(path), syspath, "/", slink, NULL); - len = readlink(path, target, sizeof(target)); - if (len <= 0 || len == (ssize_t)sizeof(target)) - return -1; - target[len] = '\0'; - pos = strrchr(target, '/'); - if (pos == NULL) - return -1; - pos = &pos[1]; - return strscpy(value, size, pos); -} - -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size) -{ - char link_target[UTIL_PATH_SIZE]; - - ssize_t len; - int i; - int back; - char *base = NULL; - - len = readlink(syspath, link_target, sizeof(link_target)); - if (len <= 0 || len == (ssize_t)sizeof(link_target)) - return -1; - link_target[len] = '\0'; - - for (back = 0; startswith(&link_target[back * 3], "../"); back++) - ; - for (i = 0; i <= back; i++) { - base = strrchr(syspath, '/'); - if (base == NULL) - return -EINVAL; - base[0] = '\0'; - } - - strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL); - return 0; -} - int util_log_priority(const char *priority) { char *endptr; diff --git a/src/libudev/libudev.c b/src/libudev/libudev.c index ec15d2576b..63fb05547d 100644 --- a/src/libudev/libudev.c +++ b/src/libudev/libudev.c @@ -17,16 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <ctype.h> +#include <stdarg.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> #include <string.h> -#include <ctype.h> #include "libudev.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "libudev-private.h" #include "missing.h" +#include "string-util.h" /** * SECTION:libudev diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 4a91c7420a..4a339dcfd4 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -20,26 +20,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <ftw.h> +#include <getopt.h> #include <locale.h> -#include <stdlib.h> #include <stdbool.h> -#include <getopt.h> +#include <stdlib.h> #include <string.h> -#include <ftw.h> #include "sd-bus.h" -#include "bus-util.h" + #include "bus-error.h" -#include "util.h" -#include "spawn-polkit-agent.h" -#include "build.h" -#include "strv.h" -#include "pager.h" -#include "set.h" +#include "bus-util.h" #include "def.h" -#include "virt.h" +#include "fd-util.h" #include "fileio.h" #include "locale-util.h" +#include "pager.h" +#include "set.h" +#include "spawn-polkit-agent.h" +#include "strv.h" +#include "util.h" +#include "virt.h" static bool arg_no_pager = false; static bool arg_ask_password = true; @@ -546,9 +547,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_CONVERT: arg_convert = false; @@ -678,7 +677,7 @@ int main(int argc, char*argv[]) { if (r <= 0) goto finish; - r = bus_open_transport(arg_transport, arg_host, false, &bus); + r = bus_connect_transport(arg_transport, arg_host, false, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; diff --git a/src/locale/localed.c b/src/locale/localed.c index e3eef4a610..720cbbaaba 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -24,25 +24,29 @@ #include <string.h> #include <unistd.h> +#ifdef HAVE_XKBCOMMON +#include <xkbcommon/xkbcommon.h> +#endif + #include "sd-bus.h" -#include "util.h" -#include "mkdir.h" -#include "strv.h" -#include "def.h" -#include "env-util.h" -#include "fileio.h" -#include "fileio-label.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-message.h" +#include "bus-util.h" +#include "def.h" +#include "env-util.h" #include "event-util.h" +#include "fd-util.h" +#include "fileio-label.h" +#include "fileio.h" #include "locale-util.h" +#include "mkdir.h" +#include "path-util.h" #include "selinux-util.h" - -#ifdef HAVE_XKBCOMMON -#include <xkbcommon/xkbcommon.h> -#endif +#include "strv.h" +#include "user-util.h" +#include "util.h" enum { /* We don't list LC_ALL here on purpose. People should be diff --git a/src/login/inhibit.c b/src/login/inhibit.c index c53ea8add7..70fef332f7 100644 --- a/src/login/inhibit.c +++ b/src/login/inhibit.c @@ -19,21 +19,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fcntl.h> #include <getopt.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> #include <unistd.h> -#include <fcntl.h> #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "util.h" -#include "build.h" -#include "strv.h" +#include "bus-util.h" +#include "fd-util.h" #include "formats-util.h" #include "process-util.h" #include "signal-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" static const char* arg_what = "idle:sleep:shutdown"; static const char* arg_who = NULL; @@ -179,9 +182,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_WHAT: arg_what = optarg; diff --git a/src/login/loginctl.c b/src/login/loginctl.c index be52518161..aff68a49fe 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -19,31 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> -#include <string.h> #include <getopt.h> #include <locale.h> +#include <string.h> +#include <unistd.h> #include "sd-bus.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" +#include "bus-util.h" +#include "cgroup-show.h" +#include "cgroup-util.h" #include "log.h" -#include "util.h" +#include "logs-show.h" #include "macro.h" #include "pager.h" -#include "build.h" +#include "parse-util.h" +#include "process-util.h" +#include "signal-util.h" +#include "spawn-polkit-agent.h" #include "strv.h" -#include "unit-name.h" #include "sysfs-show.h" -#include "logs-show.h" -#include "cgroup-show.h" -#include "cgroup-util.h" -#include "spawn-polkit-agent.h" -#include "verbs.h" -#include "process-util.h" #include "terminal-util.h" -#include "signal-util.h" +#include "unit-name.h" +#include "user-util.h" +#include "util.h" +#include "verbs.h" static char **arg_property = NULL; static bool arg_all = false; @@ -1416,9 +1419,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'p': { r = strv_extend(&arg_property, optarg); @@ -1544,7 +1545,7 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - r = bus_open_transport(arg_transport, arg_host, false, &bus); + r = bus_connect_transport(arg_transport, arg_host, false, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c index 466225d69c..d0dd569a03 100644 --- a/src/login/logind-acl.c +++ b/src/login/logind-acl.c @@ -22,12 +22,17 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "formats-util.h" #include "acl-util.h" -#include "set.h" +#include "alloc-util.h" +#include "dirent-util.h" +#include "escape.h" +#include "fd-util.h" +#include "formats-util.h" #include "logind-acl.h" +#include "set.h" +#include "string-util.h" #include "udev-util.h" +#include "util.h" static int flush_acl(acl_t acl) { acl_entry_t i; diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h index ec09843a78..93e9ed02eb 100644 --- a/src/login/logind-acl.h +++ b/src/login/logind-acl.h @@ -23,7 +23,8 @@ #include <sys/types.h> #include <stdbool.h> -#include <libudev.h> + +#include "libudev.h" #ifdef HAVE_ACL diff --git a/src/login/logind-action.c b/src/login/logind-action.c index f635fb1b63..185108f8f1 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -21,15 +21,18 @@ #include <unistd.h> -#include "conf-parser.h" -#include "special.h" -#include "sleep-config.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" -#include "logind-action.h" +#include "bus-util.h" +#include "conf-parser.h" #include "formats-util.h" +#include "logind-action.h" #include "process-util.h" +#include "sleep-config.h" +#include "special.h" +#include "string-table.h" #include "terminal-util.h" +#include "user-util.h" int manager_handle_action( Manager *m, @@ -147,7 +150,6 @@ int manager_handle_action( offending->uid, strna(u), offending->pid, strna(comm)); - warn_melody(); return -EPERM; } diff --git a/src/login/logind-action.h b/src/login/logind-action.h index ff98065371..e9b424b5f6 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -36,6 +36,7 @@ typedef enum HandleAction { } HandleAction; #include "logind.h" +#include "logind-inhibit.h" int manager_handle_action( Manager *m, diff --git a/src/login/logind-button.c b/src/login/logind-button.c index f40e35a8cb..b08b69dbfc 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -19,16 +19,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> #include <fcntl.h> +#include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include <linux/input.h> #include "sd-messages.h" -#include "util.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "logind-button.h" +#include "string-util.h" +#include "util.h" Button* button_new(Manager *m, const char *name) { Button *b; diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 6c05c11dbd..b3f30c8dc9 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -25,13 +25,16 @@ #include <pwd.h> #include <linux/vt.h> -#include "strv.h" -#include "cgroup-util.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" -#include "udev-util.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "fd-util.h" #include "logind.h" +#include "strv.h" #include "terminal-util.h" +#include "udev-util.h" +#include "user-util.h" int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) { Device *d; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 22e37a1638..7890d68aa0 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -20,29 +20,36 @@ ***/ #include <errno.h> +#include <pwd.h> #include <string.h> #include <unistd.h> -#include <pwd.h> #include "sd-messages.h" -#include "strv.h" -#include "mkdir.h" -#include "path-util.h" -#include "special.h" -#include "sleep-config.h" -#include "fileio-label.h" -#include "unit-name.h" -#include "audit.h" -#include "bus-util.h" -#include "bus-error.h" + +#include "alloc-util.h" +#include "audit-util.h" #include "bus-common-errors.h" -#include "udev-util.h" -#include "selinux-util.h" +#include "bus-error.h" +#include "bus-util.h" +#include "dirent-util.h" #include "efivars.h" -#include "logind.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio-label.h" #include "formats-util.h" +#include "fs-util.h" +#include "logind.h" +#include "mkdir.h" +#include "path-util.h" #include "process-util.h" +#include "selinux-util.h" +#include "sleep-config.h" +#include "special.h" +#include "strv.h" #include "terminal-util.h" +#include "udev-util.h" +#include "unit-name.h" +#include "user-util.h" #include "utmp-wtmp.h" int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) { @@ -1352,24 +1359,26 @@ static int bus_manager_log_shutdown( return 0; if (streq(unit_name, SPECIAL_POWEROFF_TARGET)) { - p = "MESSAGE=System is powering down."; + p = "MESSAGE=System is powering down"; q = "SHUTDOWN=power-off"; } else if (streq(unit_name, SPECIAL_HALT_TARGET)) { - p = "MESSAGE=System is halting."; + p = "MESSAGE=System is halting"; q = "SHUTDOWN=halt"; } else if (streq(unit_name, SPECIAL_REBOOT_TARGET)) { - p = "MESSAGE=System is rebooting."; + p = "MESSAGE=System is rebooting"; q = "SHUTDOWN=reboot"; } else if (streq(unit_name, SPECIAL_KEXEC_TARGET)) { - p = "MESSAGE=System is rebooting with kexec."; + p = "MESSAGE=System is rebooting with kexec"; q = "SHUTDOWN=kexec"; } else { - p = "MESSAGE=System is shutting down."; + p = "MESSAGE=System is shutting down"; q = NULL; } - if (!isempty(m->wall_message)) - p = strjoina(p, " (", m->wall_message, ")"); + if (isempty(m->wall_message)) + p = strjoina(p, "."); + else + p = strjoina(p, " (", m->wall_message, ")."); return log_struct(LOG_NOTICE, LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN), @@ -2022,7 +2031,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd } utmp_wall("The system shutdown has been cancelled", - lookup_uid(uid), tty, logind_wall_tty_filter, m); + uid_to_name(uid), tty, logind_wall_tty_filter, m); } return sd_bus_reply_method_return(message, "b", cancelled); @@ -2586,7 +2595,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err } if (m->action_job && streq(m->action_job, path)) { - log_info("Operation finished."); + log_info("Operation '%s' finished.", inhibit_what_to_string(m->action_what)); /* Tell people that they now may take a lock again */ send_prepare_for(m, m->action_what, false); diff --git a/src/login/logind-device.c b/src/login/logind-device.c index ee4c45fb8d..ffb9162e56 100644 --- a/src/login/logind-device.c +++ b/src/login/logind-device.c @@ -21,8 +21,9 @@ #include <string.h> -#include "util.h" +#include "alloc-util.h" #include "logind-device.h" +#include "util.h" Device* device_new(Manager *m, const char *sysfs, bool master) { Device *d; diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 0c9c1e5e97..33fbdde557 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -24,11 +24,18 @@ #include <string.h> #include <unistd.h> -#include "util.h" -#include "mkdir.h" -#include "logind-inhibit.h" +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "logind-inhibit.h" +#include "mkdir.h" +#include "parse-util.h" +#include "string-table.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" Inhibitor* inhibitor_new(Manager *m, const char* id) { Inhibitor *i; diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 346e1d2cec..43b578f364 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -22,13 +22,15 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "bus-util.h" -#include "strv.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" -#include "logind.h" +#include "bus-util.h" #include "logind-seat.h" +#include "logind.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" static int property_get_active_session( sd_bus *bus, diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index 8d13a63688..1f4936cebe 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -20,17 +20,23 @@ ***/ #include <errno.h> -#include <unistd.h> #include <fcntl.h> #include <string.h> +#include <unistd.h> #include "sd-messages.h" -#include "logind-seat.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" #include "logind-acl.h" -#include "util.h" +#include "logind-seat.h" #include "mkdir.h" -#include "formats-util.h" +#include "parse-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" Seat *seat_new(Manager *m, const char *id) { Seat *s; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index e6b4ccd7c6..7810199a54 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -22,15 +22,16 @@ #include <errno.h> #include <string.h> -#include "util.h" -#include "strv.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-label.h" - -#include "logind.h" -#include "logind-session.h" +#include "bus-util.h" +#include "fd-util.h" #include "logind-session-device.h" +#include "logind-session.h" +#include "logind.h" +#include "strv.h" +#include "util.h" static int property_get_user( sd_bus *bus, diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c index 656f268dba..9bf3ca0995 100644 --- a/src/login/logind-session-device.c +++ b/src/login/logind-session-device.c @@ -20,16 +20,19 @@ ***/ #include <fcntl.h> -#include <libudev.h> #include <linux/input.h> #include <string.h> #include <sys/ioctl.h> #include <sys/types.h> -#include "util.h" -#include "missing.h" +#include "libudev.h" + +#include "alloc-util.h" #include "bus-util.h" +#include "fd-util.h" #include "logind-session-device.h" +#include "missing.h" +#include "util.h" enum SessionDeviceNotifications { SESSION_DEVICE_RESUME, diff --git a/src/login/logind-session.c b/src/login/logind-session.c index f5fe030b07..1d561a6f8a 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -21,24 +21,33 @@ #include <errno.h> #include <fcntl.h> -#include <linux/vt.h> #include <linux/kd.h> +#include <linux/vt.h> #include <signal.h> #include <string.h> #include <sys/ioctl.h> #include <unistd.h> #include "sd-messages.h" -#include "util.h" -#include "mkdir.h" -#include "path-util.h" -#include "fileio.h" -#include "audit.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "audit-util.h" #include "bus-error.h" -#include "logind-session.h" +#include "bus-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "io-util.h" +#include "logind-session.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-table.h" #include "terminal-util.h" +#include "user-util.h" +#include "util.h" #define RELEASE_USEC (20*USEC_PER_SEC) @@ -987,7 +996,7 @@ static int session_open_vt(Session *s) { sprintf(path, "/dev/tty%u", s->vtnr); s->vtfd = open_terminal(path, O_RDWR | O_CLOEXEC | O_NONBLOCK | O_NOCTTY); if (s->vtfd < 0) - return log_error_errno(errno, "cannot open VT %s of session %s: %m", path, s->id); + return log_error_errno(s->vtfd, "cannot open VT %s of session %s: %m", path, s->id); return s->vtfd; } @@ -1049,9 +1058,13 @@ error: } void session_restore_vt(Session *s) { + + static const struct vt_mode mode = { + .mode = VT_AUTO, + }; + _cleanup_free_ char *utf8 = NULL; - int vt, kb = K_XLATE; - struct vt_mode mode = { 0 }; + int vt, kb, old_fd; /* We need to get a fresh handle to the virtual terminal, * since the old file-descriptor is potentially in a hung-up @@ -1059,7 +1072,7 @@ void session_restore_vt(Session *s) { * little dance to avoid having the terminal be available * for reuse before we've cleaned it up. */ - int old_fd = s->vtfd; + old_fd = s->vtfd; s->vtfd = -1; vt = session_open_vt(s); @@ -1072,13 +1085,13 @@ void session_restore_vt(Session *s) { if (read_one_line_file("/sys/module/vt/parameters/default_utf8", &utf8) >= 0 && *utf8 == '1') kb = K_UNICODE; + else + kb = K_XLATE; (void) ioctl(vt, KDSKBMODE, kb); - mode.mode = VT_AUTO; (void) ioctl(vt, VT_SETMODE, &mode); - - fchown(vt, 0, -1); + (void) fchown(vt, 0, (gid_t) -1); s->vtfd = safe_close(s->vtfd); } diff --git a/src/login/logind-user-dbus.c b/src/login/logind-user-dbus.c index 20ea2fbdc4..df901f6558 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -22,11 +22,13 @@ #include <errno.h> #include <string.h> -#include "strv.h" +#include "alloc-util.h" #include "bus-util.h" -#include "logind.h" -#include "logind-user.h" #include "formats-util.h" +#include "logind-user.h" +#include "logind.h" +#include "strv.h" +#include "user-util.h" static int property_get_display( sd_bus *bus, diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 47669afdef..56bc5a010c 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -19,27 +19,35 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/mount.h> +#include <errno.h> #include <string.h> +#include <sys/mount.h> #include <unistd.h> -#include <errno.h> -#include "util.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "hashmap.h" -#include "fileio.h" -#include "path-util.h" -#include "special.h" -#include "unit-name.h" -#include "bus-util.h" +#include "alloc-util.h" #include "bus-error.h" -#include "conf-parser.h" +#include "bus-util.h" #include "clean-ipc.h" -#include "smack-util.h" +#include "conf-parser.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "hashmap.h" #include "label.h" #include "logind-user.h" +#include "mkdir.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "rm-rf.h" +#include "smack-util.h" +#include "special.h" +#include "string-table.h" +#include "unit-name.h" +#include "user-util.h" +#include "util.h" User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) { User *u; @@ -868,12 +876,12 @@ int config_parse_tmpfs_size( errno = 0; ul = strtoul(rvalue, &f, 10); if (errno != 0 || f != e) { - log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue); return 0; } if (ul <= 0 || ul >= 100) { - log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Percentage value out of range, ignoring: %s", rvalue); return 0; } @@ -883,7 +891,7 @@ int config_parse_tmpfs_size( r = parse_size(rvalue, 1024, &k); if (r < 0 || (uint64_t) (size_t) k != k) { - log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue); return 0; } diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 1e13ff01de..3e7a935a34 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -25,15 +25,18 @@ #include <pwd.h> #include "sd-messages.h" -#include "strv.h" -#include "special.h" -#include "unit-name.h" -#include "audit.h" -#include "bus-util.h" -#include "bus-error.h" + +#include "alloc-util.h" +#include "audit-util.h" #include "bus-common-errors.h" -#include "logind.h" +#include "bus-error.h" +#include "bus-util.h" #include "formats-util.h" +#include "logind.h" +#include "special.h" +#include "strv.h" +#include "unit-name.h" +#include "user-util.h" #include "utmp-wtmp.h" _const_ static usec_t when_wall(usec_t n, usec_t elapse) { @@ -94,7 +97,7 @@ static int warn_wall(Manager *m, usec_t n) { return 0; } - utmp_wall(l, lookup_uid(m->scheduled_shutdown_uid), + utmp_wall(l, uid_to_name(m->scheduled_shutdown_uid), m->scheduled_shutdown_tty, logind_wall_tty_filter, m); return 1; diff --git a/src/login/logind.c b/src/login/logind.c index 8ac2aceb9b..83896ea627 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -20,20 +20,25 @@ ***/ #include <errno.h> -#include <libudev.h> #include <fcntl.h> #include <string.h> #include <unistd.h> +#include "libudev.h" #include "sd-daemon.h" -#include "strv.h" -#include "conf-parser.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "udev-util.h" +#include "bus-util.h" +#include "conf-parser.h" +#include "def.h" +#include "dirent-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "signal-util.h" #include "logind.h" +#include "signal-util.h" +#include "strv.h" +#include "udev-util.h" static void manager_free(Manager *m); @@ -292,8 +297,7 @@ static int manager_enumerate_seats(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/seats: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/seats: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -329,8 +333,7 @@ static int manager_enumerate_linger_users(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /var/lib/systemd/linger/: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -365,8 +368,7 @@ static int manager_enumerate_users(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/users: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/users: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -406,8 +408,7 @@ static int manager_enumerate_sessions(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/sessions: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/sessions: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -453,8 +454,7 @@ static int manager_enumerate_inhibitors(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/inhibit: %m"); } FOREACH_DIRENT(de, d, return -errno) { @@ -744,8 +744,7 @@ static int manager_connect_console(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /sys/class/tty/tty0/active: %m"); } r = sd_event_add_io(m->event, &m->console_active_event_source, m->console_active_fd, 0, manager_dispatch_console, m); diff --git a/src/login/logind.h b/src/login/logind.h index 7990da5a93..44e05d8b01 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -22,20 +22,21 @@ ***/ #include <stdbool.h> -#include <libudev.h> -#include "sd-event.h" +#include "libudev.h" #include "sd-bus.h" -#include "list.h" +#include "sd-event.h" + #include "hashmap.h" +#include "list.h" #include "set.h" typedef struct Manager Manager; +#include "logind-action.h" +#include "logind-button.h" #include "logind-device.h" #include "logind-inhibit.h" -#include "logind-button.h" -#include "logind-action.h" struct Manager { sd_event *event; diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index f66f1ce842..0d61f528db 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -19,31 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <endian.h> #include <errno.h> #include <fcntl.h> -#include <sys/file.h> #include <pwd.h> -#include <endian.h> - -#include <security/pam_modules.h> #include <security/_pam_macros.h> -#include <security/pam_modutil.h> #include <security/pam_ext.h> #include <security/pam_misc.h> +#include <security/pam_modules.h> +#include <security/pam_modutil.h> +#include <sys/file.h> +#include "alloc-util.h" +#include "audit-util.h" #include "bus-common-errors.h" -#include "util.h" -#include "audit.h" -#include "macro.h" -#include "strv.h" +#include "bus-error.h" #include "bus-util.h" #include "def.h" -#include "socket-util.h" +#include "fd-util.h" #include "fileio.h" -#include "bus-error.h" #include "formats-util.h" -#include "terminal-util.h" #include "hostname-util.h" +#include "login-util.h" +#include "macro.h" +#include "parse-util.h" +#include "socket-util.h" +#include "strv.h" +#include "terminal-util.h" +#include "util.h" static int parse_argv( pam_handle_t *handle, diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c index 9a9fb7622d..e9ca4bb03d 100644 --- a/src/login/sysfs-show.c +++ b/src/login/sysfs-show.c @@ -21,13 +21,17 @@ #include <errno.h> #include <string.h> -#include <libudev.h> -#include "util.h" -#include "sysfs-show.h" +#include "libudev.h" + +#include "alloc-util.h" +#include "locale-util.h" #include "path-util.h" -#include "udev-util.h" +#include "string-util.h" +#include "sysfs-show.h" #include "terminal-util.h" +#include "udev-util.h" +#include "util.h" static int show_sysfs_one( struct udev *udev, @@ -114,7 +118,7 @@ static int show_sysfs_one( "%s%s:%s%s%s%s", is_master ? "[MASTER] " : "", subsystem, sysname, - name ? " \"" : "", name ? name : "", name ? "\"" : "") < 0) + name ? " \"" : "", strempty(name), name ? "\"" : "") < 0) return -ENOMEM; free(k); diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c index 03516de916..d0727ff7c7 100644 --- a/src/login/test-inhibit.c +++ b/src/login/test-inhibit.c @@ -21,10 +21,12 @@ #include <unistd.h> -#include "macro.h" -#include "util.h" #include "sd-bus.h" + #include "bus-util.h" +#include "fd-util.h" +#include "macro.h" +#include "util.h" static int inhibit(sd_bus *bus, const char *what) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; diff --git a/src/machine-id-commit/machine-id-commit.c b/src/machine-id-commit/machine-id-commit.c deleted file mode 100644 index 0f7748e453..0000000000 --- a/src/machine-id-commit/machine-id-commit.c +++ /dev/null @@ -1,107 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Didier Roche - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdlib.h> -#include <stdio.h> -#include <getopt.h> -#include <errno.h> - -#include "machine-id-setup.h" -#include "log.h" -#include "build.h" - -static const char *arg_root = NULL; - -static void help(void) { - printf("%s [OPTIONS...]\n\n" - "Commit a transient /etc/machine-id on disk if writable.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " --root=ROOT Filesystem root\n", - program_invocation_short_name); -} - -static int parse_argv(int argc, char *argv[]) { - - enum { - ARG_VERSION = 0x100, - ARG_ROOT, - }; - - static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "root", required_argument, NULL, ARG_ROOT }, - {} - }; - - int c; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "hqcv", options, NULL)) >= 0) - switch (c) { - - case 'h': - help(); - return 0; - - case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; - - case ARG_ROOT: - arg_root = optarg; - break; - - case '?': - return -EINVAL; - - default: - assert_not_reached("Unhandled option"); - } - - if (optind < argc) { - log_error("Extraneous arguments"); - return -EINVAL; - } - - return 1; -} - -int main(int argc, char *argv[]) { - int r; - - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - r = machine_id_commit(arg_root); - -finish: - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; -} diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index 20cb60b804..f1165ea09c 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -19,24 +19,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stdio.h> -#include <getopt.h> #include <errno.h> +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> -#include "machine-id-setup.h" #include "log.h" -#include "build.h" +#include "machine-id-setup.h" +#include "util.h" +#include "path-util.h" -static const char *arg_root = ""; +static char *arg_root = NULL; +static bool arg_commit = false; static void help(void) { printf("%s [OPTIONS...]\n\n" "Initialize /etc/machine-id from a random source.\n\n" " -h --help Show this help\n" " --version Show package version\n" - " --root=ROOT Filesystem root\n", - program_invocation_short_name); + " --root=ROOT Filesystem root\n" + " --commit Commit transient ID\n" + , program_invocation_short_name); } static int parse_argv(int argc, char *argv[]) { @@ -44,16 +47,18 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_ROOT, + ARG_COMMIT, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "root", required_argument, NULL, ARG_ROOT }, + { "commit", no_argument, NULL, ARG_COMMIT }, {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -67,12 +72,16 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_ROOT: - arg_root = optarg; + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; + break; + + case ARG_COMMIT: + arg_commit = true; break; case '?': @@ -98,7 +107,14 @@ int main(int argc, char *argv[]) { r = parse_argv(argc, argv); if (r <= 0) - return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; + goto finish; + + if (arg_commit) + r = machine_id_commit(arg_root); + else + r = machine_id_setup(arg_root); - return machine_id_setup(arg_root) < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +finish: + free(arg_root); + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 2453a9ff04..4ec1766033 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -19,11 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-label.h" -#include "strv.h" #include "bus-util.h" -#include "machine-image.h" #include "image-dbus.h" +#include "machine-image.h" +#include "strv.h" +#include "user-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType); diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index b010c90989..452130a29c 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -29,23 +29,27 @@ #include <libgen.h> #undef basename -#include "bus-util.h" -#include "bus-label.h" -#include "strv.h" +#include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-internal.h" +#include "bus-label.h" +#include "bus-util.h" #include "copy.h" +#include "env-util.h" +#include "fd-util.h" #include "fileio.h" +#include "formats-util.h" +#include "fs-util.h" #include "in-addr-util.h" #include "local-addresses.h" -#include "path-util.h" -#include "mkdir.h" -#include "bus-internal.h" -#include "machine.h" #include "machine-dbus.h" -#include "formats-util.h" +#include "machine.h" +#include "mkdir.h" +#include "path-util.h" #include "process-util.h" -#include "env-util.h" +#include "strv.h" #include "terminal-util.h" +#include "user-util.h" static int property_get_id( sd_bus *bus, @@ -639,7 +643,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu _cleanup_free_ char *pty_name = NULL; _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL; sd_bus *container_bus = NULL; - _cleanup_close_ int master = -1; + _cleanup_close_ int master = -1, slave = -1; _cleanup_strv_free_ char **env = NULL, **args = NULL; Machine *m = userdata; const char *p, *unit, *user, *path, *description, *utmp_id; @@ -700,8 +704,11 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu return r; p = path_startswith(pty_name, "/dev/pts/"); - if (!p) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name); + assert(p); + + slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC); + if (slave < 0) + return slave; utmp_id = path_startswith(pty_name, "/dev/"); assert(utmp_id); @@ -735,20 +742,19 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu description = strjoina("Shell for User ", isempty(user) ? "root" : user); r = sd_bus_message_append(tm, - "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)", + "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)", "Description", "s", description, - "StandardInput", "s", "tty", - "StandardOutput", "s", "tty", - "StandardError", "s", "tty", - "TTYPath", "s", pty_name, + "StandardInputFileDescriptor", "h", slave, + "StandardOutputFileDescriptor", "h", slave, + "StandardErrorFileDescriptor", "h", slave, "SendSIGHUP", "b", true, "IgnoreSIGPIPE", "b", false, "KillMode", "s", "mixed", - "TTYVHangup", "b", true, "TTYReset", "b", true, "UtmpIdentifier", "s", utmp_id, "UtmpMode", "s", "user", - "PAMName", "s", "login"); + "PAMName", "s", "login", + "WorkingDirectory", "s", "-~"); if (r < 0) return r; @@ -844,6 +850,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; + slave = safe_close(slave); + r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h index 38b46ad936..194e680e05 100644 --- a/src/machine/machine-dbus.h +++ b/src/machine/machine-dbus.h @@ -23,6 +23,8 @@ #include "sd-bus.h" +#include "machine.h" + extern const sd_bus_vtable machine_vtable[]; char *machine_bus_path(Machine *s); diff --git a/src/machine/machine.c b/src/machine/machine.c index b52ecd015c..196bc4b8f4 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -19,23 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <errno.h> #include <string.h> #include <unistd.h> -#include <errno.h> #include "sd-messages.h" -#include "util.h" -#include "mkdir.h" -#include "hashmap.h" +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" +#include "formats-util.h" +#include "hashmap.h" +#include "machine-dbus.h" +#include "machine.h" +#include "mkdir.h" +#include "parse-util.h" #include "special.h" +#include "string-table.h" +#include "terminal-util.h" #include "unit-name.h" -#include "bus-util.h" -#include "bus-error.h" -#include "machine.h" -#include "machine-dbus.h" -#include "formats-util.h" +#include "util.h" +#include "extract-word.h" Machine* machine_new(Manager *manager, MachineClass class, const char *name) { Machine *m; @@ -306,19 +313,26 @@ int machine_load(Machine *m) { } if (netif) { - size_t l, allocated = 0, nr = 0; - const char *word, *state; + size_t allocated = 0, nr = 0; + const char *p; int *ni = NULL; - FOREACH_WORD(word, l, netif, state) { - char buf[l+1]; + p = netif; + for(;;) { + _cleanup_free_ char *word = NULL; int ifi; - *(char*) (mempcpy(buf, word, l)) = 0; + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + break; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_warning_errno(r, "Failed to parse NETIF: %s", netif); + break; + } - if (safe_atoi(buf, &ifi) < 0) - continue; - if (ifi <= 0) + if (parse_ifindex(word, &ifi) < 0) continue; if (!GREEDY_REALLOC(ni, allocated, nr+1)) { @@ -538,7 +552,7 @@ int machine_kill(Machine *m, KillWho who, int signo) { return 0; } - /* Otherwise make PID 1 do it for us, for the entire cgroup */ + /* Otherwise, make PID 1 do it for us, for the entire cgroup */ return manager_kill_unit(m->manager, m->unit, signo, NULL); } @@ -571,6 +585,25 @@ int machine_openpt(Machine *m, int flags) { } } +int machine_open_terminal(Machine *m, const char *path, int mode) { + assert(m); + + switch (m->class) { + + case MACHINE_HOST: + return open_terminal(path, mode); + + case MACHINE_CONTAINER: + if (m->leader <= 0) + return -EINVAL; + + return open_terminal_in_namespace(m->leader, path, mode); + + default: + return -EOPNOTSUPP; + } +} + MachineOperation *machine_operation_unref(MachineOperation *o) { if (!o) return NULL; diff --git a/src/machine/machine.h b/src/machine/machine.h index 5f978289f2..ad7f2a162f 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -123,3 +123,4 @@ const char *kill_who_to_string(KillWho k) _const_; KillWho kill_who_from_string(const char *s) _pure_; int machine_openpt(Machine *m, int flags); +int machine_open_terminal(Machine *m, const char *path, int mode); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index d276fbe956..7e17c7a41c 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -19,44 +19,48 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <unistd.h> +#include <arpa/inet.h> #include <errno.h> -#include <string.h> +#include <fcntl.h> #include <getopt.h> #include <locale.h> -#include <fcntl.h> -#include <netinet/in.h> -#include <arpa/inet.h> #include <net/if.h> +#include <netinet/in.h> +#include <string.h> #include <sys/mount.h> +#include <sys/socket.h> +#include <unistd.h> #include "sd-bus.h" -#include "log.h" -#include "util.h" -#include "macro.h" -#include "pager.h" -#include "spawn-polkit-agent.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "build.h" -#include "strv.h" -#include "unit-name.h" +#include "bus-util.h" #include "cgroup-show.h" -#include "logs-show.h" #include "cgroup-util.h" -#include "ptyfwd.h" -#include "event-util.h" -#include "path-util.h" -#include "mkdir.h" #include "copy.h" -#include "verbs.h" +#include "env-util.h" +#include "event-util.h" +#include "fd-util.h" +#include "hostname-util.h" #include "import-util.h" +#include "log.h" +#include "logs-show.h" +#include "macro.h" +#include "mkdir.h" +#include "pager.h" +#include "parse-util.h" +#include "path-util.h" #include "process-util.h" -#include "terminal-util.h" +#include "ptyfwd.h" #include "signal-util.h" -#include "env-util.h" -#include "hostname-util.h" +#include "spawn-polkit-agent.h" +#include "strv.h" +#include "terminal-util.h" +#include "unit-name.h" +#include "util.h" +#include "verbs.h" +#include "web-util.h" static char **arg_property = NULL; static bool arg_all = false; @@ -1092,9 +1096,10 @@ static int copy_files(int argc, char *argv[], void *userdata) { container_path = copy_from ? argv[2] : dest; if (!path_is_absolute(host_path)) { - abs_host_path = path_make_absolute_cwd(host_path); - if (!abs_host_path) - return log_oom(); + r = path_make_absolute_cwd(host_path, &abs_host_path); + if (r < 0) + return log_error_errno(r, "Failed to make path absolute: %m"); + host_path = abs_host_path; } @@ -1110,10 +1115,8 @@ static int copy_files(int argc, char *argv[], void *userdata) { argv[1], copy_from ? container_path : host_path, copy_from ? host_path : container_path); - if (r < 0) { - log_error("Failed to copy: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to copy: %s", bus_error_message(&error, r)); return 0; } @@ -1173,7 +1176,7 @@ static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *r return 0; } -static int process_forward(sd_event *event, PTYForward **forward, int master, bool ignore_vhangup, const char *name) { +static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) { char last_char = 0; bool machine_died; int ret = 0, r; @@ -1192,7 +1195,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL); - r = pty_forward_new(event, master, ignore_vhangup, false, forward); + r = pty_forward_new(event, master, flags, forward); if (r < 0) return log_error_errno(r, "Failed to create PTY forwarder: %m"); @@ -1203,7 +1206,7 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, bo pty_forward_get_last_char(*forward, &last_char); machine_died = - ignore_vhangup && + (flags & PTY_FORWARD_IGNORE_VHANGUP) && pty_forward_get_ignore_vhangup(*forward) == 0; *forward = pty_forward_free(*forward); @@ -1286,7 +1289,7 @@ static int login_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return process_forward(event, &forward, master, true, machine); + return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine); } static int shell_machine(int argc, char *argv[], void *userdata) { @@ -1390,7 +1393,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - return process_forward(event, &forward, master, false, machine); + return process_forward(event, &forward, master, 0, machine); } static int remove_image(int argc, char *argv[], void *userdata) { @@ -2382,7 +2385,7 @@ static int set_limit(int argc, char *argv[], void *userdata) { uint64_t limit; int r; - if (streq(argv[argc-1], "-")) + if (STR_IN_SET(argv[argc-1], "-", "none", "infinity")) limit = (uint64_t) -1; else { r = parse_size(argv[argc-1], 1024, &limit); @@ -2554,9 +2557,7 @@ static int parse_argv(int argc, char *argv[]) { return help(0, NULL, NULL); case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'p': r = strv_extend(&arg_property, optarg); @@ -2747,7 +2748,7 @@ int main(int argc, char*argv[]) { if (r <= 0) goto finish; - r = bus_open_transport(arg_transport, arg_host, false, &bus); + r = bus_connect_transport(arg_transport, arg_host, false, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 41bb106d28..7827f063c1 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -24,21 +24,26 @@ #include <unistd.h> #include "sd-id128.h" -#include "strv.h" -#include "path-util.h" -#include "unit-name.h" -#include "bus-util.h" + +#include "alloc-util.h" +#include "btrfs-util.h" #include "bus-common-errors.h" +#include "bus-util.h" #include "cgroup-util.h" -#include "btrfs-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "process-util.h" #include "hostname-util.h" +#include "image-dbus.h" +#include "machine-dbus.h" #include "machine-image.h" #include "machine-pool.h" -#include "image-dbus.h" #include "machined.h" -#include "machine-dbus.h" +#include "path-util.h" +#include "process-util.h" +#include "stdio-util.h" +#include "strv.h" +#include "unit-name.h" +#include "user-util.h" static int property_get_pool_path( sd_bus *bus, @@ -79,7 +84,7 @@ static int property_get_pool_usage( if (fd >= 0) { BtrfsQuotaInfo q; - if (btrfs_subvol_get_quota_fd(fd, &q) >= 0) + if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0) usage = q.referenced; } @@ -115,7 +120,7 @@ static int property_get_pool_limit( if (fd >= 0) { BtrfsQuotaInfo q; - if (btrfs_subvol_get_quota_fd(fd, &q) >= 0) + if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0) size = q.referenced_max; } @@ -831,7 +836,9 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */ return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m"); - r = btrfs_quota_limit("/var/lib/machines", limit); + (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit); + + r = btrfs_subvol_set_subtree_quota_limit("/var/lib/machines", 0, limit); if (r == -ENOTTY) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs."); if (r < 0) diff --git a/src/machine/machined.c b/src/machine/machined.c index df3cc9972a..a099de9f36 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -24,15 +24,19 @@ #include <unistd.h> #include "sd-daemon.h" -#include "cgroup-util.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-error.h" -#include "label.h" +#include "bus-util.h" +#include "cgroup-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "signal-util.h" #include "hostname-util.h" +#include "label.h" #include "machine-image.h" #include "machined.h" +#include "signal-util.h" Manager *manager_new(void) { Manager *m; @@ -146,8 +150,7 @@ int manager_enumerate_machines(Manager *m) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open /run/systemd/machines: %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/machines: %m"); } FOREACH_DIRENT(de, d, return -errno) { diff --git a/src/machine/machined.h b/src/machine/machined.h index b3e59bf998..dac7a29ed1 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -23,10 +23,11 @@ #include <stdbool.h> -#include "list.h" -#include "hashmap.h" -#include "sd-event.h" #include "sd-bus.h" +#include "sd-event.h" + +#include "hashmap.h" +#include "list.h" typedef struct Manager Manager; diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index 5bbe314ba0..13784763f1 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -20,17 +20,21 @@ ***/ #include <errno.h> -#include <string.h> -#include <sys/stat.h> -#include <limits.h> #include <getopt.h> #include <libkmod.h> +#include <limits.h> +#include <string.h> +#include <sys/stat.h> +#include "conf-files.h" +#include "def.h" +#include "fd-util.h" +#include "fileio.h" #include "log.h" -#include "util.h" +#include "proc-cmdline.h" +#include "string-util.h" #include "strv.h" -#include "conf-files.h" -#include "build.h" +#include "util.h" static char **arg_proc_cmdline_modules = NULL; @@ -51,7 +55,7 @@ static int add_modules(const char *p) { if (!k) return log_oom(); - if (strv_extend_strv(&arg_proc_cmdline_modules, k) < 0) + if (strv_extend_strv(&arg_proc_cmdline_modules, k, true) < 0) return log_oom(); return 0; @@ -147,8 +151,7 @@ static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent if (feof(f)) break; - log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); } l = strstrip(line); @@ -199,9 +202,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case '?': return -EINVAL; diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 75572b6388..ba7e3ba74a 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -19,29 +19,34 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <getopt.h> #include <net/if.h> +#include <stdbool.h> -#include "sd-network.h" -#include "sd-netlink.h" -#include "sd-hwdb.h" #include "sd-device.h" +#include "sd-hwdb.h" +#include "sd-netlink.h" +#include "sd-network.h" -#include "strv.h" -#include "build.h" -#include "util.h" -#include "pager.h" -#include "lldp.h" -#include "netlink-util.h" +#include "alloc-util.h" +#include "arphrd-list.h" #include "device-util.h" +#include "ether-addr-util.h" #include "hwdb-util.h" -#include "arphrd-list.h" +#include "lldp.h" #include "local-addresses.h" +#include "locale-util.h" +#include "locale-util.h" +#include "netlink-util.h" +#include "pager.h" +#include "parse-util.h" #include "socket-util.h" -#include "ether-addr-util.h" -#include "verbs.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" #include "terminal-util.h" +#include "util.h" +#include "verbs.h" static bool arg_no_pager = false; static bool arg_legend = true; @@ -516,7 +521,7 @@ static int link_status_one( assert(rtnl); assert(name); - if (safe_atoi(name, &ifindex) >= 0 && ifindex > 0) + if (parse_ifindex(name, &ifindex) >= 0) r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex); else { r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0); @@ -1063,9 +1068,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_NO_PAGER: arg_no_pager = true; diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c index d609daafde..889fe1e30d 100644 --- a/src/network/networkd-address-pool.c +++ b/src/network/networkd-address-pool.c @@ -19,8 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "networkd.h" +#include "alloc-util.h" #include "networkd-address-pool.h" +#include "networkd.h" +#include "set.h" +#include "string-util.h" int address_pool_new( Manager *m, @@ -96,9 +99,10 @@ static bool address_pool_prefix_is_taken( HASHMAP_FOREACH(l, p->manager->links, i) { Address *a; + Iterator j; /* Don't clash with assigned addresses */ - LIST_FOREACH(addresses, a, l->addresses) { + SET_FOREACH(a, l->addresses, j) { if (a->family != p->family) continue; diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index b0d296941e..8b6acf2e1d 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -21,26 +21,39 @@ #include <net/if.h> -#include "utf8.h" -#include "util.h" +#include "alloc-util.h" #include "conf-parser.h" #include "firewall-util.h" #include "netlink-util.h" - -#include "networkd.h" #include "networkd-address.h" +#include "networkd.h" +#include "parse-util.h" +#include "set.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" -static void address_init(Address *address) { - assert(address); +int address_new(Address **ret) { + _cleanup_address_free_ Address *address = NULL; + + address = new0(Address, 1); + if (!address) + return -ENOMEM; address->family = AF_UNSPEC; address->scope = RT_SCOPE_UNIVERSE; address->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME; address->cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME; + + *ret = address; + address = NULL; + + return 0; } int address_new_static(Network *network, unsigned section, Address **ret) { _cleanup_address_free_ Address *address = NULL; + int r; if (section) { address = hashmap_get(network->addresses_by_section, UINT_TO_PTR(section)); @@ -52,11 +65,9 @@ int address_new_static(Network *network, unsigned section, Address **ret) { } } - address = new0(Address, 1); - if (!address) - return -ENOMEM; - - address_init(address); + r = address_new(&address); + if (r < 0) + return r; address->network = network; @@ -74,21 +85,6 @@ int address_new_static(Network *network, unsigned section, Address **ret) { return 0; } -int address_new_dynamic(Address **ret) { - _cleanup_address_free_ Address *address = NULL; - - address = new0(Address, 1); - if (!address) - return -ENOMEM; - - address_init(address); - - *ret = address; - address = NULL; - - return 0; -} - void address_free(Address *address) { if (!address) return; @@ -101,10 +97,112 @@ void address_free(Address *address) { UINT_TO_PTR(address->section)); } + if (address->link) { + set_remove(address->link->addresses, address); + set_remove(address->link->addresses_foreign, address); + } + free(address); } -int address_establish(Address *address, Link *link) { +static void address_hash_func(const void *b, struct siphash *state) { + const Address *a = b; + + assert(a); + + siphash24_compress(&a->family, sizeof(a->family), state); + + switch (a->family) { + case AF_INET: + siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state); + + /* peer prefix */ + if (a->prefixlen != 0) { + uint32_t prefix; + + if (a->in_addr_peer.in.s_addr != 0) + prefix = be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen); + else + prefix = be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen); + + siphash24_compress(&prefix, sizeof(prefix), state); + } + + /* fallthrough */ + case AF_INET6: + /* local address */ + siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state); + + break; + default: + /* treat any other address family as AF_UNSPEC */ + break; + } +} + +static int address_compare_func(const void *c1, const void *c2) { + const Address *a1 = c1, *a2 = c2; + + if (a1->family < a2->family) + return -1; + if (a1->family > a2->family) + return 1; + + switch (a1->family) { + /* use the same notion of equality as the kernel does */ + case AF_INET: + if (a1->prefixlen < a2->prefixlen) + return -1; + if (a1->prefixlen > a2->prefixlen) + return 1; + + /* compare the peer prefixes */ + if (a1->prefixlen != 0) { + /* make sure we don't try to shift by 32. + * See ISO/IEC 9899:TC3 § 6.5.7.3. */ + uint32_t b1, b2; + + if (a1->in_addr_peer.in.s_addr != 0) + b1 = be32toh(a1->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen); + else + b1 = be32toh(a1->in_addr.in.s_addr) >> (32 - a1->prefixlen); + + if (a2->in_addr_peer.in.s_addr != 0) + b2 = be32toh(a2->in_addr_peer.in.s_addr) >> (32 - a1->prefixlen); + else + b2 = be32toh(a2->in_addr.in.s_addr) >> (32 - a1->prefixlen); + + if (b1 < b2) + return -1; + if (b1 > b2) + return 1; + } + + /* fall-through */ + case AF_INET6: + return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family)); + default: + /* treat any other address family as AF_UNSPEC */ + return 0; + } +} + +static const struct hash_ops address_hash_ops = { + .hash = address_hash_func, + .compare = address_compare_func +}; + +bool address_equal(Address *a1, Address *a2) { + if (a1 == a2) + return true; + + if (!a1 || !a2) + return false; + + return address_compare_func(a1, a2) == 0; +} + +static int address_establish(Address *address, Link *link) { bool masq; int r; @@ -112,9 +210,9 @@ int address_establish(Address *address, Link *link) { assert(link); masq = link->network && - link->network->ip_masquerade && - address->family == AF_INET && - address->scope < RT_SCOPE_LINK; + link->network->ip_masquerade && + address->family == AF_INET && + address->scope < RT_SCOPE_LINK; /* Add firewall entry if this is requested */ if (address->ip_masquerade_done != masq) { @@ -131,11 +229,86 @@ int address_establish(Address *address, Link *link) { return 0; } -int address_release(Address *address, Link *link) { +static int address_add_internal(Link *link, Set **addresses, + int family, + const union in_addr_union *in_addr, + unsigned char prefixlen, + Address **ret) { + _cleanup_address_free_ Address *address = NULL; int r; - assert(address); assert(link); + assert(addresses); + assert(in_addr); + + r = address_new(&address); + if (r < 0) + return r; + + address->family = family; + address->in_addr = *in_addr; + address->prefixlen = prefixlen; + + r = set_ensure_allocated(addresses, &address_hash_ops); + if (r < 0) + return r; + + r = set_put(*addresses, address); + if (r < 0) + return r; + + address->link = link; + + if (ret) + *ret = address; + + address = NULL; + + return 0; +} + +int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) { + return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret); +} + +int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) { + Address *address; + int r; + + r = address_get(link, family, in_addr, prefixlen, &address); + if (r == -ENOENT) { + /* Address does not exist, create a new one */ + r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address); + if (r < 0) + return r; + } else if (r == 0) { + /* Take over a foreign address */ + r = set_ensure_allocated(&link->addresses, &address_hash_ops); + if (r < 0) + return r; + + r = set_put(link->addresses, address); + if (r < 0) + return r; + + set_remove(link->addresses_foreign, address); + } else if (r == 1) { + /* Already exists, do nothing */ + ; + } else + return r; + + if (ret) + *ret = address; + + return 0; +} + +static int address_release(Address *address) { + int r; + + assert(address); + assert(address->link); /* Remove masquerading firewall entry if it was added */ if (address->ip_masquerade_done) { @@ -144,7 +317,7 @@ int address_release(Address *address, Link *link) { r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0); if (r < 0) - log_link_warning_errno(link, r, "Failed to disable IP masquerading: %m"); + log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m"); address->ip_masquerade_done = false; } @@ -152,81 +325,97 @@ int address_release(Address *address, Link *link) { return 0; } -int address_drop(Address *address, Link *link, - sd_netlink_message_handler_t callback) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; - int r; +int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo) { + bool ready; assert(address); - assert(address->family == AF_INET || address->family == AF_INET6); - assert(link); - assert(link->ifindex > 0); - assert(link->manager); - assert(link->manager->rtnl); + assert(cinfo); - address_release(address, link); + ready = address_is_ready(address); - r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, - link->ifindex, address->family); - if (r < 0) - return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m"); + address->added = true; + address->flags = flags; + address->scope = scope; + address->cinfo = *cinfo; - r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); - if (r < 0) - return log_error_errno(r, "Could not set prefixlen: %m"); + if (address->link) { + link_update_operstate(address->link); - if (address->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); - else if (address->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6); - if (r < 0) - return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m"); + if (!ready && address_is_ready(address)) + link_check_ready(address->link); + } - r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); - if (r < 0) - return log_error_errno(r, "Could not send rtnetlink message: %m"); + return 0; +} - link_ref(link); +int address_drop(Address *address) { + Link *link; + bool ready; + + assert(address); + + ready = address_is_ready(address); + link = address->link; + + address_release(address); + address_free(address); + + link_update_operstate(link); + + if (link && !ready) + link_check_ready(link); return 0; } -int address_update(Address *address, Link *link, - sd_netlink_message_handler_t callback) { +int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) { + Address address = {}, *existing; + + assert(link); + assert(in_addr); + assert(ret); + + address.family = family; + address.in_addr = *in_addr; + address.prefixlen = prefixlen; + + existing = set_get(link->addresses, &address); + if (existing) { + *ret = existing; + + return 1; + } else { + existing = set_get(link->addresses_foreign, &address); + if (!existing) + return -ENOENT; + } + + *ret = existing; + + return 0; +} + +int address_remove(Address *address, Link *link, + sd_netlink_message_handler_t callback) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; int r; assert(address); assert(address->family == AF_INET || address->family == AF_INET6); + assert(link); assert(link->ifindex > 0); assert(link->manager); assert(link->manager->rtnl); - r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req, + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, link->ifindex, address->family); if (r < 0) - return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m"); + return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m"); r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); if (r < 0) return log_error_errno(r, "Could not set prefixlen: %m"); - address->flags |= IFA_F_PERMANENT; - - r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff); - if (r < 0) - return log_error_errno(r, "Could not set flags: %m"); - - if (address->flags & ~0xff && link->rtnl_extended_attrs) { - r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags); - if (r < 0) - return log_error_errno(r, "Could not set extended flags: %m"); - } - - r = sd_rtnl_message_addr_set_scope(req, address->scope); - if (r < 0) - return log_error_errno(r, "Could not set scope: %m"); - if (address->family == AF_INET) r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in); else if (address->family == AF_INET6) @@ -234,22 +423,6 @@ int address_update(Address *address, Link *link, if (r < 0) return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m"); - if (address->family == AF_INET) { - r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); - if (r < 0) - return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m"); - } - - if (address->label) { - r = sd_netlink_message_append_string(req, IFA_LABEL, address->label); - if (r < 0) - return log_error_errno(r, "Could not append IFA_LABEL attribute: %m"); - } - - r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo); - if (r < 0) - return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m"); - r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); if (r < 0) return log_error_errno(r, "Could not send rtnetlink message: %m"); @@ -292,7 +465,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) { } else if (original->family == AF_INET6) in_addr.in6.s6_addr[15] |= 1; - r = address_new_dynamic(&na); + r = address_new(&na); if (r < 0) return r; @@ -318,8 +491,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) { return 0; } -int address_configure(Address *address, Link *link, - sd_netlink_message_handler_t callback) { +int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; int r; @@ -334,8 +506,12 @@ int address_configure(Address *address, Link *link, if (r < 0) return r; - r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR, - link->ifindex, address->family); + if (update) + r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req, + link->ifindex, address->family); + else + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR, + link->ifindex, address->family); if (r < 0) return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m"); @@ -392,13 +568,23 @@ int address_configure(Address *address, Link *link, if (r < 0) return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m"); - r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + r = address_establish(address, link); if (r < 0) + return r; + + r = sd_netlink_call_async(link->manager->rtnl, req, callback, link, 0, NULL); + if (r < 0) { + address_release(address); return log_error_errno(r, "Could not send rtnetlink message: %m"); + } link_ref(link); - address_establish(address, link); + r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL); + if (r < 0) { + address_release(address); + return log_error_errno(r, "Could not add address: %m"); + } return 0; } @@ -430,15 +616,13 @@ int config_parse_broadcast( return r; if (n->family == AF_INET6) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue); return 0; } r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Broadcast is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue); return 0; } @@ -487,10 +671,10 @@ int config_parse_address(const char *unit, e = strchr(rvalue, '/'); if (e) { unsigned i; + r = safe_atou(e + 1, &i); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Prefix length is invalid, ignoring assignment: %s", e + 1); + log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length is invalid, ignoring assignment: %s", e + 1); return 0; } @@ -502,23 +686,20 @@ int config_parse_address(const char *unit, r = in_addr_from_string_auto(address, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Address is invalid, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Address is invalid, ignoring assignment: %s", address); return 0; } if (!e && f == AF_INET) { r = in_addr_default_prefixlen(&buffer.in, &n->prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Prefix length not specified, and a default one can not be deduced for '%s', ignoring assignment", address); return 0; } } if (n->family != AF_UNSPEC && f != n->family) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Address is incompatible, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, 0, "Address is incompatible, ignoring assignment: %s", address); return 0; } @@ -567,9 +748,7 @@ int config_parse_label(const char *unit, return log_oom(); if (!ascii_is_valid(label) || strlen(label) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Interface label is not ASCII clean or is too" - " long, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is not ASCII clean or is too long, ignoring assignment: %s", rvalue); free(label); return 0; } @@ -587,49 +766,8 @@ int config_parse_label(const char *unit, return 0; } -bool address_equal(Address *a1, Address *a2) { - /* same object */ - if (a1 == a2) - return true; - - /* one, but not both, is NULL */ - if (!a1 || !a2) - return false; - - if (a1->family != a2->family) - return false; - - switch (a1->family) { - /* use the same notion of equality as the kernel does */ - case AF_UNSPEC: - return true; +bool address_is_ready(const Address *a) { + assert(a); - case AF_INET: - if (a1->prefixlen != a2->prefixlen) - return false; - else if (a1->prefixlen == 0) - /* make sure we don't try to shift by 32. - * See ISO/IEC 9899:TC3 § 6.5.7.3. */ - return true; - else { - uint32_t b1, b2; - - b1 = be32toh(a1->in_addr.in.s_addr); - b2 = be32toh(a2->in_addr.in.s_addr); - - return (b1 >> (32 - a1->prefixlen)) == (b2 >> (32 - a1->prefixlen)); - } - - case AF_INET6: { - uint64_t *b1, *b2; - - b1 = (uint64_t*)&a1->in_addr.in6; - b2 = (uint64_t*)&a2->in_addr.in6; - - return (((b1[0] ^ b2[0]) | (b1[1] ^ b2[1])) == 0UL); - } - - default: - assert_not_reached("Invalid address family"); - } + return a->added && !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)); } diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 39789a2382..0b1f3b688b 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -38,6 +38,8 @@ struct Address { Network *network; unsigned section; + Link *link; + int family; unsigned char prefixlen; unsigned char scope; @@ -50,20 +52,24 @@ struct Address { union in_addr_union in_addr; union in_addr_union in_addr_peer; - bool ip_masquerade_done; + bool added:1; + bool ip_masquerade_done:1; LIST_FIELDS(Address, addresses); }; int address_new_static(Network *network, unsigned section, Address **ret); -int address_new_dynamic(Address **ret); +int address_new(Address **ret); void address_free(Address *address); -int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_update(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_drop(Address *address, Link *link, sd_netlink_message_handler_t callback); -int address_establish(Address *address, Link *link); -int address_release(Address *address, Link *link); +int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); +int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); +int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret); +int address_update(Address *address, unsigned char flags, unsigned char scope, struct ifa_cacheinfo *cinfo); +int address_drop(Address *address); +int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update); +int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback); bool address_equal(Address *a1, Address *a2); +bool address_is_ready(const Address *a); DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free); #define _cleanup_address_free_ _cleanup_(address_freep) diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 04f04df117..b58fc5808c 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -22,10 +22,11 @@ #include <netinet/ether.h> #include <linux/if.h> +#include "alloc-util.h" +#include "dhcp-lease-internal.h" #include "hostname-util.h" -#include "networkd-link.h" #include "network-internal.h" -#include "dhcp-lease-internal.h" +#include "networkd-link.h" static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { @@ -45,7 +46,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, if (!link->dhcp4_messages) { link->dhcp4_configured = true; - link_client_handler(link); + link_check_ready(link); } return 1; @@ -72,11 +73,13 @@ static int link_set_dhcp_routes(Link *link) { if (r < 0) return log_link_warning_errno(link, r, "DHCP error: could not get address: %m"); - r = route_new_dynamic(&route, RTPROT_DHCP); + r = route_new(&route); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); - r = route_new_dynamic(&route_gw, RTPROT_DHCP); + route->protocol = RTPROT_DHCP; + + r = route_new(&route_gw); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); @@ -84,11 +87,12 @@ static int link_set_dhcp_routes(Link *link) { * route for the gw host so that we can route no matter the * netmask or existing kernel route tables. */ route_gw->family = AF_INET; - route_gw->dst_addr.in = gateway; + route_gw->dst.in = gateway; route_gw->dst_prefixlen = 32; - route_gw->prefsrc_addr.in = address; + route_gw->prefsrc.in = address; route_gw->scope = RT_SCOPE_LINK; - route_gw->metrics = link->network->dhcp_route_metric; + route_gw->protocol = RTPROT_DHCP; + route_gw->priority = link->network->dhcp_route_metric; r = route_configure(route_gw, link, &dhcp4_route_handler); if (r < 0) @@ -97,9 +101,9 @@ static int link_set_dhcp_routes(Link *link) { link->dhcp4_messages ++; route->family = AF_INET; - route->in_addr.in = gateway; - route->prefsrc_addr.in = address; - route->metrics = link->network->dhcp_route_metric; + route->gw.in = gateway; + route->prefsrc.in = address; + route->priority = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); if (r < 0) { @@ -120,15 +124,16 @@ static int link_set_dhcp_routes(Link *link) { for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; - r = route_new_dynamic(&route, RTPROT_DHCP); + r = route_new(&route); if (r < 0) return log_link_error_errno(link, r, "Could not allocate route: %m"); route->family = AF_INET; - route->in_addr.in = static_routes[i].gw_addr; - route->dst_addr.in = static_routes[i].dst_addr; + route->protocol = RTPROT_DHCP; + route->gw.in = static_routes[i].gw_addr; + route->dst.in = static_routes[i].dst_addr; route->dst_prefixlen = static_routes[i].dst_prefixlen; - route->metrics = link->network->dhcp_route_metric; + route->priority = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); if (r < 0) @@ -162,45 +167,45 @@ static int dhcp_lease_lost(Link *link) { for (i = 0; i < n; i++) { _cleanup_route_free_ Route *route = NULL; - r = route_new_dynamic(&route, RTPROT_UNSPEC); + r = route_new(&route); if (r >= 0) { route->family = AF_INET; - route->in_addr.in = routes[i].gw_addr; - route->dst_addr.in = routes[i].dst_addr; + route->gw.in = routes[i].gw_addr; + route->dst.in = routes[i].dst_addr; route->dst_prefixlen = routes[i].dst_prefixlen; - route_drop(route, link, - &link_route_drop_handler); + route_remove(route, link, + &link_route_remove_handler); } } } } - r = address_new_dynamic(&address); + r = address_new(&address); if (r >= 0) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r >= 0) { _cleanup_route_free_ Route *route_gw = NULL; _cleanup_route_free_ Route *route = NULL; - r = route_new_dynamic(&route_gw, RTPROT_UNSPEC); + r = route_new(&route_gw); if (r >= 0) { route_gw->family = AF_INET; - route_gw->dst_addr.in = gateway; + route_gw->dst.in = gateway; route_gw->dst_prefixlen = 32; route_gw->scope = RT_SCOPE_LINK; - route_drop(route_gw, link, - &link_route_drop_handler); + route_remove(route_gw, link, + &link_route_remove_handler); } - r = route_new_dynamic(&route, RTPROT_UNSPEC); + r = route_new(&route); if (r >= 0) { route->family = AF_INET; - route->in_addr.in = gateway; + route->gw.in = gateway; - route_drop(route, link, - &link_route_drop_handler); + route_remove(route, link, + &link_route_remove_handler); } } @@ -214,7 +219,7 @@ static int dhcp_lease_lost(Link *link) { address->in_addr.in = addr; address->prefixlen = prefixlen; - address_drop(address, link, &link_address_drop_handler); + address_remove(address, link, &link_address_remove_handler); } } @@ -267,7 +272,7 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, log_link_error_errno(link, r, "Could not set DHCPv4 address: %m"); link_enter_failed(link); } else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); link_set_dhcp_routes(link); @@ -288,7 +293,7 @@ static int dhcp4_update_address(Link *link, prefixlen = in_addr_netmask_to_prefixlen(netmask); - r = address_new_dynamic(&addr); + r = address_new(&addr); if (r < 0) return r; @@ -299,9 +304,9 @@ static int dhcp4_update_address(Link *link, addr->prefixlen = prefixlen; addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr; - /* use update rather than configure so that we will update the - * lifetime of an existing address if it has already been configured */ - r = address_update(addr, link, &dhcp4_address_handler); + /* allow reusing an existing address and simply update its lifetime + * in case it already exists */ + r = address_configure(addr, link, &dhcp4_address_handler, true); if (r < 0) return r; @@ -528,9 +533,11 @@ int dhcp4_configure(Link *link) { assert(link->network); assert(link->network->dhcp & ADDRESS_FAMILY_IPV4); - r = sd_dhcp_client_new(&link->dhcp_client); - if (r < 0) - return r; + if (!link->dhcp_client) { + r = sd_dhcp_client_new(&link->dhcp_client); + if (r < 0) + return r; + } r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0); if (r < 0) diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index 13105c7865..c3332bb1ac 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -22,12 +22,11 @@ #include <netinet/ether.h> #include <linux/if.h> -#include "networkd-link.h" -#include "network-internal.h" - -#include "sd-icmp6-nd.h" #include "sd-dhcp6-client.h" +#include "network-internal.h" +#include "networkd-link.h" + static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link); static int dhcp6_lease_information_acquired(sd_dhcp6_client *client, @@ -53,24 +52,22 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, return 1; } - log_link_error(link, "Could not set DHCPv6 address: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not set DHCPv6 address: %m"); link_enter_failed(link); } else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); return 1; } -static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr, - uint8_t prefixlen, uint32_t lifetime_preferred, - uint32_t lifetime_valid) { +static int dhcp6_address_change(Link *link, struct in6_addr *ip6_addr, + uint32_t lifetime_preferred, uint32_t lifetime_valid) { int r; _cleanup_address_free_ Address *addr = NULL; - r = address_new_dynamic(&addr); + r = address_new(&addr); if (r < 0) return r; @@ -78,17 +75,17 @@ static int dhcp6_address_update(Link *link, struct in6_addr *ip6_addr, memcpy(&addr->in_addr.in6, ip6_addr, sizeof(*ip6_addr)); addr->flags = IFA_F_NOPREFIXROUTE; - addr->prefixlen = prefixlen; + addr->prefixlen = 128; addr->cinfo.ifa_prefered = lifetime_preferred; addr->cinfo.ifa_valid = lifetime_valid; log_link_info(link, - "DHCPv6 address "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(addr->in_addr.in6), + "DHCPv6 address "SD_NDISC_ADDRESS_FORMAT_STR"/%d timeout preferred %d valid %d", + SD_NDISC_ADDRESS_FORMAT_VAL(addr->in_addr.in6), addr->prefixlen, lifetime_preferred, lifetime_valid); - r = address_update(addr, link, dhcp6_address_handler); + r = address_configure(addr, link, dhcp6_address_handler, true); if (r < 0) log_link_warning_errno(link, r, "Could not assign DHCPv6 address: %m"); @@ -100,7 +97,6 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { sd_dhcp6_lease *lease; struct in6_addr ip6_addr; uint32_t lifetime_preferred, lifetime_valid; - uint8_t prefixlen; r = sd_dhcp6_client_get_lease(client, &lease); if (r < 0) @@ -112,19 +108,7 @@ static int dhcp6_lease_address_acquired(sd_dhcp6_client *client, Link *link) { &lifetime_preferred, &lifetime_valid) >= 0) { - r = sd_icmp6_ra_get_prefixlen(link->icmp6_router_discovery, - &ip6_addr, &prefixlen); - if (r < 0 && r != -EADDRNOTAVAIL) { - log_link_warning(link, "Could not get prefix information: %s", - strerror(-r)); - return r; - } - - if (r == -EADDRNOTAVAIL) - prefixlen = 128; - - r = dhcp6_address_update(link, &ip6_addr, prefixlen, - lifetime_preferred, lifetime_valid); + r = dhcp6_address_change(link, &ip6_addr, lifetime_preferred, lifetime_valid); if (r < 0) return r; } @@ -172,50 +156,39 @@ static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { default: if (event < 0) - log_link_warning(link, "DHCPv6 error: %s", - strerror(-event)); + log_link_warning_errno(link, event, "DHCPv6 error: %m"); else - log_link_warning(link, "DHCPv6 unknown event: %d", - event); + log_link_warning(link, "DHCPv6 unknown event: %d", event); return; } - link_client_handler(link); + link_check_ready(link); } -static int dhcp6_configure(Link *link, int event) { - int r; - bool information_request; +int dhcp6_configure(Link *link, bool inf_req) { + int r, information_request; assert_return(link, -EINVAL); - assert_return(IN_SET(event, SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED), -EINVAL); link->dhcp6_configured = false; if (link->dhcp6_client) { - r = sd_dhcp6_client_get_information_request(link->dhcp6_client, - &information_request); + r = sd_dhcp6_client_get_information_request(link->dhcp6_client, &information_request); if (r < 0) { - log_link_warning(link, "Could not get DHCPv6 Information request setting: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not get DHCPv6 Information request setting: %m"); goto error; } - if (information_request && event != SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) { + if (information_request && !inf_req) { r = sd_dhcp6_client_stop(link->dhcp6_client); if (r < 0) { - log_link_warning(link, "Could not stop DHCPv6 while setting Managed mode %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not stop DHCPv6 while setting Managed mode: %m"); goto error; } - r = sd_dhcp6_client_set_information_request(link->dhcp6_client, - false); + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, false); if (r < 0) { - log_link_warning(link, "Could not unset DHCPv6 Information request: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not unset DHCPv6 Information request: %m"); goto error; } @@ -223,8 +196,7 @@ static int dhcp6_configure(Link *link, int event) { r = sd_dhcp6_client_start(link->dhcp6_client); if (r < 0 && r != -EALREADY) { - log_link_warning(link, "Could not restart DHCPv6: %s", - strerror(-r)); + log_link_warning_errno(link, r, "Could not restart DHCPv6: %m"); goto error; } @@ -257,9 +229,8 @@ static int dhcp6_configure(Link *link, int event) { if (r < 0) goto error; - if (event == SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER) { - r = sd_dhcp6_client_set_information_request(link->dhcp6_client, - true); + if (inf_req) { + r = sd_dhcp6_client_set_information_request(link->dhcp6_client, true); if (r < 0) goto error; } @@ -274,109 +245,3 @@ static int dhcp6_configure(Link *link, int event) { link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client); return r; } - -static int dhcp6_prefix_expired(Link *link) { - int r; - sd_dhcp6_lease *lease; - struct in6_addr *expired_prefix, ip6_addr; - uint8_t expired_prefixlen; - uint32_t lifetime_preferred, lifetime_valid; - - r = sd_icmp6_ra_get_expired_prefix(link->icmp6_router_discovery, - &expired_prefix, &expired_prefixlen); - if (r < 0) - return r; - - r = sd_dhcp6_client_get_lease(link->dhcp6_client, &lease); - if (r < 0) - return r; - - log_link_info(link, "IPv6 prefix "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d expired", - SD_ICMP6_ND_ADDRESS_FORMAT_VAL(*expired_prefix), - expired_prefixlen); - - sd_dhcp6_lease_reset_address_iter(lease); - - while (sd_dhcp6_lease_get_address(lease, &ip6_addr, - &lifetime_preferred, - &lifetime_valid) >= 0) { - - r = sd_icmp6_prefix_match(expired_prefix, expired_prefixlen, - &ip6_addr); - if (r < 0) - continue; - - log_link_info(link, "IPv6 prefix length updated "SD_ICMP6_ND_ADDRESS_FORMAT_STR"/%d", SD_ICMP6_ND_ADDRESS_FORMAT_VAL(ip6_addr), 128); - - dhcp6_address_update(link, &ip6_addr, 128, lifetime_preferred, lifetime_valid); - } - - return 0; -} - -static void icmp6_router_handler(sd_icmp6_nd *nd, int event, void *userdata) { - Link *link = userdata; - - assert(link); - assert(link->network); - assert(link->manager); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return; - - switch(event) { - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE: - return; - - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT: - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER: - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED: - dhcp6_configure(link, event); - - break; - - case SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED: - if (!link->rtnl_extended_attrs) - dhcp6_prefix_expired(link); - - break; - - default: - if (event < 0) - log_link_warning(link, "ICMPv6 error: %s", - strerror(-event)); - else - log_link_warning(link, "ICMPv6 unknown event: %d", - event); - - break; - } - -} - -int icmp6_configure(Link *link) { - int r; - - assert_return(link, -EINVAL); - - r = sd_icmp6_nd_new(&link->icmp6_router_discovery); - if (r < 0) - return r; - - r = sd_icmp6_nd_attach_event(link->icmp6_router_discovery, NULL, 0); - if (r < 0) - return r; - - r = sd_icmp6_nd_set_mac(link->icmp6_router_discovery, &link->mac); - if (r < 0) - return r; - - r = sd_icmp6_nd_set_index(link->icmp6_router_discovery, link->ifindex); - if (r < 0) - return r; - - r = sd_icmp6_nd_set_callback(link->icmp6_router_discovery, - icmp6_router_handler, link); - - return r; -} diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 22efadb843..c9222b8cb8 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -22,12 +22,12 @@ #include <net/if.h> #include <net/ethernet.h> +#include "alloc-util.h" #include "conf-parser.h" -#include "util.h" #include "netlink-util.h" - -#include "networkd.h" #include "networkd-fdb.h" +#include "networkd.h" +#include "util.h" /* create a new FDB entry or get an existing one. */ int fdb_entry_new_static(Network *const network, @@ -197,7 +197,7 @@ int config_parse_fdb_hwaddr( &fdb_entry->mac_addr->ether_addr_octet[5]); if (ETHER_ADDR_LEN != r) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not a valid MAC address, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue); return 0; } diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index af3e3884e6..ed0d861e7a 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -42,9 +42,9 @@ static int ipv4ll_address_lost(Link *link) { log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr)); - r = address_new_dynamic(&address); + r = address_new(&address); if (r < 0) { - log_link_error(link, "Could not allocate address: %s", strerror(-r)); + log_link_error_errno(link, r, "Could not allocate address: %m"); return r; } @@ -53,22 +53,21 @@ static int ipv4ll_address_lost(Link *link) { address->prefixlen = 16; address->scope = RT_SCOPE_LINK; - address_drop(address, link, &link_address_drop_handler); + address_remove(address, link, &link_address_remove_handler); - r = route_new_dynamic(&route, RTPROT_UNSPEC); + r = route_new(&route); if (r < 0) { - log_link_error(link, "Could not allocate route: %s", - strerror(-r)); + log_link_error_errno(link, r, "Could not allocate route: %m"); return r; } route->family = AF_INET; route->scope = RT_SCOPE_LINK; - route->metrics = IPV4LL_ROUTE_METRIC; + route->priority = IPV4LL_ROUTE_METRIC; - route_drop(route, link, &link_route_drop_handler); + route_remove(route, link, &link_route_remove_handler); - link_client_handler(link); + link_check_ready(link); return 0; } @@ -82,14 +81,14 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *u r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set ipv4ll route: %s", strerror(-r)); + log_link_error_errno(link, r, "could not set ipv4ll route: %m"); link_enter_failed(link); } link->ipv4ll_route = true; if (link->ipv4ll_address == true) - link_client_handler(link); + link_check_ready(link); return 1; } @@ -103,15 +102,15 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, void r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error(link, "could not set ipv4ll address: %s", strerror(-r)); + log_link_error_errno(link, r, "could not set ipv4ll address: %m"); link_enter_failed(link); } else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); link->ipv4ll_address = true; if (link->ipv4ll_route == true) - link_client_handler(link); + link_check_ready(link); return 1; } @@ -134,7 +133,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u", ADDRESS_FMT_VAL(address)); - r = address_new_dynamic(&ll_addr); + r = address_new(&ll_addr); if (r < 0) return r; @@ -144,19 +143,20 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen); ll_addr->scope = RT_SCOPE_LINK; - r = address_configure(ll_addr, link, ipv4ll_address_handler); + r = address_configure(ll_addr, link, ipv4ll_address_handler, false); if (r < 0) return r; link->ipv4ll_address = false; - r = route_new_dynamic(&route, RTPROT_STATIC); + r = route_new(&route); if (r < 0) return r; route->family = AF_INET; route->scope = RT_SCOPE_LINK; - route->metrics = IPV4LL_ROUTE_METRIC; + route->protocol = RTPROT_STATIC; + route->priority = IPV4LL_ROUTE_METRIC; r = route_configure(route, link, ipv4ll_route_handler); if (r < 0) @@ -208,9 +208,11 @@ int ipv4ll_configure(Link *link) { assert(link->network); assert(link->network->link_local & ADDRESS_FAMILY_IPV4); - r = sd_ipv4ll_new(&link->ipv4ll); - if (r < 0) - return r; + if (!link->ipv4ll) { + r = sd_ipv4ll_new(&link->ipv4ll); + if (r < 0) + return r; + } if (link->udev_device) { r = net_get_unique_predictable_data(link->udev_device, seed); diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 1a1524dfb4..11b35d6cf8 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -22,8 +22,10 @@ #include "bus-util.h" #include "strv.h" -#include "networkd.h" +#include "alloc-util.h" #include "networkd-link.h" +#include "networkd.h" +#include "parse-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState); @@ -101,7 +103,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void if (r < 0) return 0; - r = safe_atoi(identifier, &ifindex); + r = parse_ifindex(identifier, &ifindex); if (r < 0) return 0; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 5dd14b1104..46979ffa12 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -23,18 +23,23 @@ #include <linux/if.h> #include <unistd.h> -#include "util.h" -#include "virt.h" -#include "fileio.h" -#include "socket-util.h" +#include "alloc-util.h" #include "bus-util.h" -#include "udev-util.h" -#include "netlink-util.h" #include "dhcp-lease-internal.h" +#include "event-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "netlink-util.h" #include "network-internal.h" - #include "networkd-link.h" #include "networkd-netdev.h" +#include "set.h" +#include "socket-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "udev-util.h" +#include "util.h" +#include "virt.h" bool link_dhcp6_enabled(Link *link) { if (link->flags & IFF_LOOPBACK) @@ -129,6 +134,57 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) { return link->network->ipv6_privacy_extensions; } +void link_update_operstate(Link *link) { + LinkOperationalState operstate; + assert(link); + + if (link->kernel_operstate == IF_OPER_DORMANT) + operstate = LINK_OPERSTATE_DORMANT; + else if (link_has_carrier(link)) { + Address *address; + uint8_t scope = RT_SCOPE_NOWHERE; + Iterator i; + + /* if we have carrier, check what addresses we have */ + SET_FOREACH(address, link->addresses, i) { + if (!address_is_ready(address)) + continue; + + if (address->scope < scope) + scope = address->scope; + } + + /* for operstate we also take foreign addresses into account */ + SET_FOREACH(address, link->addresses_foreign, i) { + if (!address_is_ready(address)) + continue; + + if (address->scope < scope) + scope = address->scope; + } + + if (scope < RT_SCOPE_SITE) + /* universally accessible addresses found */ + operstate = LINK_OPERSTATE_ROUTABLE; + else if (scope < RT_SCOPE_HOST) + /* only link or site local addresses found */ + operstate = LINK_OPERSTATE_DEGRADED; + else + /* no useful addresses found */ + operstate = LINK_OPERSTATE_CARRIER; + } else if (link->flags & IFF_UP) + operstate = LINK_OPERSTATE_NO_CARRIER; + else + operstate = LINK_OPERSTATE_OFF; + + if (link->operstate != operstate) { + link->operstate = operstate; + link_send_changed(link, "OperationalState", NULL); + link_dirty(link); + manager_dirty(link->manager); + } +} + #define FLAG_STRING(string, flag, old, new) \ (((old ^ new) & flag) \ ? ((old & flag) ? (" -" string) : (" +" string)) \ @@ -201,7 +257,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) { link->flags = flags; link->kernel_operstate = operstate; - link_save(link); + link_update_operstate(link); return 0; } @@ -291,10 +347,15 @@ static void link_free(Link *link) { if (!link) return; - while ((address = link->addresses)) { - LIST_REMOVE(addresses, link->addresses, address); - address_free(address); - } + while (!set_isempty(link->addresses)) + address_free(set_first(link->addresses)); + + while (!set_isempty(link->addresses_foreign)) + address_free(set_first(link->addresses_foreign)); + + link->addresses = set_free(link->addresses); + + link->addresses_foreign = set_free(link->addresses_foreign); while ((address = link->pool_addresses)) { LIST_REMOVE(addresses, link->pool_addresses, address); @@ -313,13 +374,14 @@ static void link_free(Link *link) { sd_ipv4ll_unref(link->ipv4ll); sd_dhcp6_client_unref(link->dhcp6_client); - sd_icmp6_nd_unref(link->icmp6_router_discovery); + sd_ndisc_unref(link->ndisc_router_discovery); if (link->manager) hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)); free(link->ifname); + (void)unlink(link->state_file); free(link->state_file); udev_device_unref(link->udev_device); @@ -336,15 +398,28 @@ static void link_free(Link *link) { } Link *link_unref(Link *link) { - if (link && (-- link->n_ref <= 0)) - link_free(link); + if (!link) + return NULL; + + assert(link->n_ref > 0); + + link->n_ref --; + + if (link->n_ref > 0) + return NULL; + + link_free(link); return NULL; } Link *link_ref(Link *link) { - if (link) - assert_se(++ link->n_ref >= 2); + if (!link) + return NULL; + + assert(link->n_ref > 0); + + link->n_ref ++; return link; } @@ -385,7 +460,7 @@ static void link_enter_unmanaged(Link *link) { link_set_state(link, LINK_STATE_UNMANAGED); - link_save(link); + link_dirty(link); } static int link_stop_clients(Link *link) { @@ -410,16 +485,16 @@ static int link_stop_clients(Link *link) { r = log_link_warning_errno(link, r, "Could not stop IPv4 link-local: %m"); } - if(link->icmp6_router_discovery) { + if(link->ndisc_router_discovery) { if (link->dhcp6_client) { k = sd_dhcp6_client_stop(link->dhcp6_client); if (k < 0) r = log_link_warning_errno(link, r, "Could not stop DHCPv6 client: %m"); } - k = sd_icmp6_nd_stop(link->icmp6_router_discovery); + k = sd_ndisc_stop(link->ndisc_router_discovery); if (k < 0) - r = log_link_warning_errno(link, r, "Could not stop ICMPv6 router discovery: %m"); + r = log_link_warning_errno(link, r, "Could not stop IPv6 Router Discovery: %m"); } if (link->lldp) { @@ -443,7 +518,7 @@ void link_enter_failed(Link *link) { link_stop_clients(link); - link_save(link); + link_dirty(link); } static Address* link_find_dhcp_server_address(Link *link) { @@ -484,14 +559,19 @@ static int link_enter_configured(Link *link) { link_set_state(link, LINK_STATE_CONFIGURED); - link_save(link); + link_dirty(link); return 0; } -void link_client_handler(Link *link) { +void link_check_ready(Link *link) { + Address *a; + Iterator i; + assert(link); - assert(link->network); + + if (!link->network) + return; if (!link->static_configured) return; @@ -501,12 +581,18 @@ void link_client_handler(Link *link) { !link->ipv4ll_route) return; - if (link_dhcp4_enabled(link) && !link->dhcp4_configured) - return; - - if (link_dhcp6_enabled(link) && !link->dhcp6_configured) + if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && + !link->dhcp4_configured) || + (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) && + !link->dhcp6_configured) || + (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) && + !link->dhcp4_configured && !link->dhcp6_configured)) return; + SET_FOREACH(a, link->addresses, i) + if (!address_is_ready(a)) + return; + if (link->state != LINK_STATE_CONFIGURED) link_enter_configured(link); @@ -529,12 +615,12 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) - log_link_warning_errno(link, r, "%-*s: could not set route: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not set route: %m"); if (link->link_messages == 0) { log_link_debug(link, "Routes set"); link->static_configured = true; - link_client_handler(link); + link_check_ready(link); } return 1; @@ -563,14 +649,14 @@ static int link_enter_set_routes(Link *link) { if (link->link_messages == 0) { link->static_configured = true; - link_client_handler(link); + link_check_ready(link); } else log_link_debug(link, "Setting routes"); return 0; } -int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { +int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -583,7 +669,7 @@ int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userd r = sd_netlink_message_get_errno(m); if (r < 0 && r != -ESRCH) - log_link_warning_errno(link, r, "%-*s: could not drop route: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not drop route: %m"); return 1; } @@ -607,9 +693,9 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) - log_link_warning_errno(link, r, "%-*s: could not set address: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "could not set address: %m"); else if (r >= 0) - link_rtnl_process_address(rtnl, m, link->manager); + manager_rtnl_process_address(rtnl, m, link->manager); if (link->link_messages == 0) { log_link_debug(link, "Addresses set"); @@ -720,7 +806,7 @@ static int link_enter_set_addresses(Link *link) { link_set_state(link, LINK_STATE_SETTING_ADDRESSES); LIST_FOREACH(addresses, ad, link->network->static_addresses) { - r = address_configure(ad, link, &address_handler); + r = address_configure(ad, link, &address_handler, false); if (r < 0) { log_link_warning_errno(link, r, "Could not set addresses: %m"); link_enter_failed(link); @@ -852,7 +938,7 @@ static int link_enter_set_addresses(Link *link) { return 0; } -int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { +int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -865,7 +951,7 @@ int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *use r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EADDRNOTAVAIL) - log_link_warning_errno(link, r, "%-*s: could not drop address: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not drop address: %m"); return 1; } @@ -1017,7 +1103,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda r = sd_netlink_message_get_errno(m); if (r < 0) - log_link_warning_errno(link, r, "%-*s: could not set MTU: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not set MTU: %m"); return 1; } @@ -1156,13 +1242,13 @@ static int link_acquire_conf(Link *link) { } if (link_dhcp6_enabled(link)) { - assert(link->icmp6_router_discovery); + assert(link->ndisc_router_discovery); log_link_debug(link, "Discovering IPv6 routers"); - r = sd_icmp6_router_solicitation_start(link->icmp6_router_discovery); + r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery); if (r < 0) - return log_link_warning_errno(link, r, "Could not start IPv6 router discovery: %m"); + return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m"); } if (link_lldp_enabled(link)) { @@ -1205,7 +1291,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda if (r < 0) /* we warn but don't fail the link, as it may be brought up later */ - log_link_warning_errno(link, r, "%-*s: could not bring up interface: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not bring up interface: %m"); return 1; } @@ -1292,7 +1378,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user r = sd_netlink_message_get_errno(m); if (r < 0) - log_link_warning_errno(link, r, "%-*s: could not bring down interface: %m", IFNAMSIZ, link->ifname); + log_link_warning_errno(link, r, "Could not bring down interface: %m"); return 1; } @@ -1430,14 +1516,14 @@ static int link_new_bound_by_list(Link *link) { } if (list_updated) - link_save(link); + link_dirty(link); HASHMAP_FOREACH (carrier, link->bound_by_links, i) { r = link_put_carrier(carrier, link, &carrier->bound_to_links); if (r < 0) return r; - link_save(carrier); + link_dirty(carrier); } return 0; @@ -1472,14 +1558,14 @@ static int link_new_bound_to_list(Link *link) { } if (list_updated) - link_save(link); + link_dirty(link); HASHMAP_FOREACH (carrier, link->bound_to_links, i) { r = link_put_carrier(carrier, link, &carrier->bound_by_links); if (r < 0) return r; - link_save(carrier); + link_dirty(carrier); } return 0; @@ -1515,7 +1601,7 @@ static void link_free_bound_to_list(Link *link) { hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex)); if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex))) - link_save(bound_to); + link_dirty(bound_to); } return; @@ -1529,7 +1615,7 @@ static void link_free_bound_by_list(Link *link) { hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex)); if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) { - link_save(bound_by); + link_dirty(bound_by); link_handle_bound_to_list(bound_by); } } @@ -1553,7 +1639,7 @@ static void link_free_carrier_maps(Link *link) { } if (list_updated) - link_save(link); + link_dirty(link); return; } @@ -1568,6 +1654,7 @@ void link_drop(Link *link) { log_link_debug(link, "Link removed"); + (void)unlink(link->state_file); link_unref(link); return; @@ -1614,7 +1701,7 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, void *us r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_error_errno(link, r, "%-*s: could not join netdev: %m", IFNAMSIZ, link->ifname); + log_link_error_errno(link, r, "Could not join netdev: %m"); link_enter_failed(link); return 1; } else @@ -1637,7 +1724,7 @@ static int link_enter_join_netdev(Link *link) { link_set_state(link, LINK_STATE_ENSLAVING); - link_save(link); + link_dirty(link); if (!link->network->bridge && !link->network->bond && @@ -1810,16 +1897,16 @@ static int link_set_ipv6_accept_ra(Link *link) { * disabled if local forwarding is enabled). * If set, ignore or enforce RA independent of local forwarding state. */ - if (link->network->ipv6_accept_ra < 0) { + if (link->network->ipv6_accept_ra < 0) /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */ v = "1"; - } else if (link->network->ipv6_accept_ra > 0) { + else if (link->network->ipv6_accept_ra > 0) /* "2" means accept RA even if ip_forward is enabled */ v = "2"; - } else { + else /* "0" means ignore RA */ v = "0"; - } + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra"); r = write_string_file(p, v, 0); @@ -1834,6 +1921,37 @@ static int link_set_ipv6_accept_ra(Link *link) { return 0; } +static int link_set_ipv6_dad_transmits(Link *link) { + char buf[DECIMAL_STR_MAX(unsigned) + 1]; + const char *p = NULL; + int r; + + /* Make this a NOP if IPv6 is not available */ + if (!socket_ipv6_is_supported()) + return 0; + + if (link->flags & IFF_LOOPBACK) + return 0; + + if (link->network->ipv6_dad_transmits < 0) + return 0; + + p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits"); + + xsprintf(buf, "%u", link->network->ipv6_dad_transmits); + + r = write_string_file(p, buf, 0); + if (r < 0) { + /* If the right value is set anyway, don't complain */ + if (verify_one_line_file(p, buf) > 0) + return 0; + + log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m"); + } + + return 0; +} + static int link_configure(Link *link) { int r; @@ -1861,6 +1979,10 @@ static int link_configure(Link *link) { if (r < 0) return r; + r = link_set_ipv6_dad_transmits(link); + if (r < 0) + return r; + if (link_ipv4ll_enabled(link)) { r = ipv4ll_configure(link); if (r < 0) @@ -1884,7 +2006,7 @@ static int link_configure(Link *link) { } if (link_dhcp6_enabled(link)) { - r = icmp6_configure(link); + r = ndisc_configure(link); if (r < 0) return r; } @@ -1936,28 +2058,30 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m, if (r < 0) return r; - r = network_get(link->manager, link->udev_device, link->ifname, - &link->mac, &network); - if (r == -ENOENT) { - link_enter_unmanaged(link); - return 1; - } else if (r < 0) - return r; + if (!link->network) { + r = network_get(link->manager, link->udev_device, link->ifname, + &link->mac, &network); + if (r == -ENOENT) { + link_enter_unmanaged(link); + return 1; + } else if (r < 0) + return r; - if (link->flags & IFF_LOOPBACK) { - if (network->link_local != ADDRESS_FAMILY_NO) - log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link"); + if (link->flags & IFF_LOOPBACK) { + if (network->link_local != ADDRESS_FAMILY_NO) + log_link_debug(link, "Ignoring link-local autoconfiguration for loopback link"); - if (network->dhcp != ADDRESS_FAMILY_NO) - log_link_debug(link, "Ignoring DHCP clients for loopback link"); + if (network->dhcp != ADDRESS_FAMILY_NO) + log_link_debug(link, "Ignoring DHCP clients for loopback link"); - if (network->dhcp_server) - log_link_debug(link, "Ignoring DHCP server for loopback link"); - } + if (network->dhcp_server) + log_link_debug(link, "Ignoring DHCP server for loopback link"); + } - r = network_apply(link->manager, network, link); - if (r < 0) - return r; + r = network_apply(link->manager, network, link); + if (r < 0) + return r; + } r = link_new_bound_to_list(link); if (r < 0) @@ -2009,177 +2133,191 @@ int link_initialized(Link *link, struct udev_device *device) { return 0; } -static Address* link_get_equal_address(Link *link, Address *needle) { - Address *i; +static int link_load(Link *link) { + _cleanup_free_ char *network_file = NULL, + *addresses = NULL, + *routes = NULL, + *dhcp4_address = NULL, + *ipv4ll_address = NULL; + union in_addr_union address; + union in_addr_union route_dst; + const char *p; + int r; assert(link); - assert(needle); - LIST_FOREACH(addresses, i, link->addresses) - if (address_equal(i, needle)) - return i; - - return NULL; -} - -int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { - Manager *m = userdata; - Link *link = NULL; - uint16_t type; - _cleanup_address_free_ Address *address = NULL; - unsigned char flags; - Address *existing; - char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX]; - const char *valid_str = NULL; - int r, ifindex; + r = parse_env_file(link->state_file, NEWLINE, + "NETWORK_FILE", &network_file, + "ADDRESSES", &addresses, + "ROUTES", &routes, + "DHCP4_ADDRESS", &dhcp4_address, + "IPV4LL_ADDRESS", &ipv4ll_address, + NULL); + if (r < 0 && r != -ENOENT) + return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file); + + if (network_file) { + Network *network; + char *suffix; + + /* drop suffix */ + suffix = strrchr(network_file, '.'); + if (!suffix) { + log_link_debug(link, "Failed to get network name from %s", network_file); + goto network_file_fail; + } + *suffix = '\0'; - assert(rtnl); - assert(message); - assert(m); + r = network_get_by_name(link->manager, basename(network_file), &network); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file)); + goto network_file_fail; + } - if (sd_netlink_message_is_error(message)) { - r = sd_netlink_message_get_errno(message); + r = network_apply(link->manager, network, link); if (r < 0) - log_warning_errno(r, "rtnl: failed to receive address: %m"); - - return 0; + return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file)); } - r = sd_netlink_message_get_type(message, &type); - if (r < 0) { - log_warning_errno(r, "rtnl: could not get message type: %m"); - return 0; - } else if (type != RTM_NEWADDR && type != RTM_DELADDR) { - log_warning("rtnl: received unexpected message type when processing address"); - return 0; - } - - r = sd_rtnl_message_addr_get_ifindex(message, &ifindex); - if (r < 0) { - log_warning_errno(r, "rtnl: could not get ifindex from address: %m"); - return 0; - } else if (ifindex <= 0) { - log_warning("rtnl: received address message with invalid ifindex: %d", ifindex); - return 0; - } else { - r = link_get(m, ifindex, &link); - if (r < 0 || !link) { - /* when enumerating we might be out of sync, but we will - * get the address again, so just ignore it */ - if (!m->enumerating) - log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex); - return 0; - } - } +network_file_fail: - r = address_new_dynamic(&address); - if (r < 0) - return r; + if (addresses) { + p = addresses; - r = sd_rtnl_message_addr_get_family(message, &address->family); - if (r < 0 || !IN_SET(address->family, AF_INET, AF_INET6)) { - log_link_warning(link, "rtnl: received address with invalid family, ignoring."); - return 0; - } + for (;;) { + _cleanup_free_ char *address_str = NULL; + char *prefixlen_str; + int family; + unsigned char prefixlen; - r = sd_rtnl_message_addr_get_prefixlen(message, &address->prefixlen); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m"); - return 0; - } + r = extract_first_word(&p, &address_str, NULL, 0); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to extract next address string: %m"); + continue; + } if (r == 0) + break; - r = sd_rtnl_message_addr_get_scope(message, &address->scope); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m"); - return 0; - } + prefixlen_str = strchr(address_str, '/'); + if (!prefixlen_str) { + log_link_debug(link, "Failed to parse address and prefix length %s", address_str); + continue; + } - r = sd_rtnl_message_addr_get_flags(message, &flags); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m"); - return 0; - } - address->flags = flags; + *prefixlen_str ++ = '\0'; - switch (address->family) { - case AF_INET: - r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &address->in_addr.in); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); - return 0; - } + r = sscanf(prefixlen_str, "%hhu", &prefixlen); + if (r != 1) { + log_link_error(link, "Failed to parse prefixlen %s", prefixlen_str); + continue; + } - break; + r = in_addr_from_string_auto(address_str, &family, &address); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to parse address %s: %m", address_str); + continue; + } - case AF_INET6: - r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &address->in_addr.in6); - if (r < 0) { - log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); - return 0; + r = address_add(link, family, &address, prefixlen, NULL); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add address: %m"); } - - break; - - default: - assert_not_reached("invalid address family"); } - if (!inet_ntop(address->family, &address->in_addr, buf, INET6_ADDRSTRLEN)) { - log_link_warning(link, "Could not print address"); - return 0; - } + if (routes) { + for (;;) { + Route *route; + _cleanup_free_ char *route_str = NULL; + _cleanup_event_source_unref_ sd_event_source *expire = NULL; + usec_t lifetime; + char *prefixlen_str; + int family; + unsigned char prefixlen, tos, table; + uint32_t priority; - r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &address->cinfo); - if (r >= 0) { - if (address->cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME) - valid_str = "ever"; - else - valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, - address->cinfo.ifa_valid * USEC_PER_SEC, - USEC_PER_SEC); - } + r = extract_first_word(&p, &route_str, NULL, 0); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to extract next route string: %m"); + continue; + } if (r == 0) + break; - existing = link_get_equal_address(link, address); + prefixlen_str = strchr(route_str, '/'); + if (!prefixlen_str) { + log_link_debug(link, "Failed to parse route %s", route_str); + continue; + } - switch (type) { - case RTM_NEWADDR: - if (existing) { - log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); + *prefixlen_str ++ = '\0'; + r = sscanf(prefixlen_str, "%hhu/%hhu/%"SCNu32"/%hhu/"USEC_FMT, &prefixlen, &tos, &priority, &table, &lifetime); + if (r != 5) { + log_link_debug(link, + "Failed to parse destination prefix length, tos, priority, table or expiration %s", + prefixlen_str); + continue; + } - existing->scope = address->scope; - existing->flags = address->flags; - existing->cinfo = address->cinfo; + r = in_addr_from_string_auto(route_str, &family, &route_dst); + if (r < 0) { + log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str); + continue; + } - } else { - log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); + r = route_add(link, family, &route_dst, prefixlen, tos, priority, table, &route); + if (r < 0) + return log_link_error_errno(link, r, "Failed to add route: %m"); - LIST_PREPEND(addresses, link->addresses, address); - address_establish(address, link); + if (lifetime != USEC_INFINITY) { + r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), lifetime, + 0, route_expire_handler, route); + if (r < 0) + log_link_warning_errno(link, r, "Could not arm route expiration handler: %m"); + } - address = NULL; + route->lifetime = lifetime; + sd_event_source_unref(route->expire); + route->expire = expire; + expire = NULL; + } + } - link_save(link); + if (dhcp4_address) { + r = in_addr_from_string(AF_INET, dhcp4_address, &address); + if (r < 0) { + log_link_debug_errno(link, r, "Falied to parse DHCPv4 address %s: %m", dhcp4_address); + goto dhcp4_address_fail; } - break; + r = sd_dhcp_client_new(&link->dhcp_client); + if (r < 0) + return log_link_error_errno(link, r, "Falied to create DHCPv4 client: %m"); + + r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in); + if (r < 0) + return log_link_error_errno(link, r, "Falied to set inital DHCPv4 address %s: %m", dhcp4_address); + } - case RTM_DELADDR: +dhcp4_address_fail: - if (existing) { - log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); - address_release(existing, link); - LIST_REMOVE(addresses, link->addresses, existing); - address_free(existing); - } else - log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, address->prefixlen, valid_str); + if (ipv4ll_address) { + r = in_addr_from_string(AF_INET, ipv4ll_address, &address); + if (r < 0) { + log_link_debug_errno(link, r, "Falied to parse IPv4LL address %s: %m", ipv4ll_address); + goto ipv4ll_address_fail; + } - break; - default: - assert_not_reached("Received invalid RTNL message type"); + r = sd_ipv4ll_new(&link->ipv4ll); + if (r < 0) + return log_link_error_errno(link, r, "Falied to create IPv4LL client: %m"); + + r = sd_ipv4ll_set_address(link->ipv4ll, &address.in); + if (r < 0) + return log_link_error_errno(link, r, "Falied to set inital IPv4LL address %s: %m", ipv4ll_address); } - return 1; +ipv4ll_address_fail: + + return 0; } int link_add(Manager *m, sd_netlink_message *message, Link **ret) { @@ -2201,12 +2339,18 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) { log_link_debug(link, "Link %d added", link->ifindex); + r = link_load(link); + if (r < 0) + return r; + if (detect_container() <= 0) { /* not in a container, udev will be around */ sprintf(ifindex_str, "n%d", link->ifindex); device = udev_device_new_from_device_id(m->udev, ifindex_str); - if (!device) - return log_link_warning_errno(link, errno, "Could not find udev device: %m"); + if (!device) { + r = log_link_warning_errno(link, errno, "Could not find udev device: %m"); + goto failed; + } if (udev_device_get_is_initialized(device) <= 0) { /* not yet ready */ @@ -2216,17 +2360,20 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) { r = link_initialized(link, device); if (r < 0) - return r; + goto failed; } else { /* we are calling a callback directly, so must take a ref */ link_ref(link); r = link_initialized_and_synced(m->rtnl, NULL, link); if (r < 0) - return r; + goto failed; } return 0; +failed: + link_enter_failed(link); + return r; } static int link_carrier_gained(Link *link) { @@ -2414,49 +2561,13 @@ int link_update(Link *link, sd_netlink_message *m) { return 0; } -static void link_update_operstate(Link *link) { - LinkOperationalState operstate; - assert(link); - - if (link->kernel_operstate == IF_OPER_DORMANT) - operstate = LINK_OPERSTATE_DORMANT; - else if (link_has_carrier(link)) { - Address *address; - uint8_t scope = RT_SCOPE_NOWHERE; - - /* if we have carrier, check what addresses we have */ - LIST_FOREACH(addresses, address, link->addresses) { - if (address->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) - continue; - - if (address->scope < scope) - scope = address->scope; - } - - if (scope < RT_SCOPE_SITE) - /* universally accessible addresses found */ - operstate = LINK_OPERSTATE_ROUTABLE; - else if (scope < RT_SCOPE_HOST) - /* only link or site local addresses found */ - operstate = LINK_OPERSTATE_DEGRADED; - else - /* no useful addresses found */ - operstate = LINK_OPERSTATE_CARRIER; - } else if (link->flags & IFF_UP) - operstate = LINK_OPERSTATE_NO_CARRIER; - else - operstate = LINK_OPERSTATE_OFF; - - if (link->operstate != operstate) { - link->operstate = operstate; - link_send_changed(link, "OperationalState", NULL); - } -} - int link_save(Link *link) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; const char *admin_state, *oper_state; + Address *a; + Route *route; + Iterator i; int r; assert(link); @@ -2464,12 +2575,6 @@ int link_save(Link *link) { assert(link->lease_file); assert(link->manager); - link_update_operstate(link); - - r = manager_save(link->manager); - if (r < 0) - return r; - if (link->state == LINK_STATE_LINGER) { unlink(link->state_file); return 0; @@ -2537,13 +2642,12 @@ int link_save(Link *link) { if (space) fputc(' ', f); serialize_in6_addrs(f, in6_addrs, r); - space = true; } } - fputs("\n", f); + fputc('\n', f); - fprintf(f, "NTP="); + fputs("NTP=", f); space = false; STRV_FOREACH(address, link->network->ntp) { if (space) @@ -2590,9 +2694,9 @@ int link_save(Link *link) { } } - fputs("\n", f); + fputc('\n', f); - fprintf(f, "DOMAINS="); + fputs("DOMAINS=", f); space = false; STRV_FOREACH(domain, link->network->domains) { if (space) @@ -2628,18 +2732,48 @@ int link_save(Link *link) { } } - fputs("\n", f); + fputc('\n', f); fprintf(f, "WILDCARD_DOMAIN=%s\n", yes_no(link->network->wildcard_domain)); fprintf(f, "LLMNR=%s\n", resolve_support_to_string(link->network->llmnr)); + + fputs("ADDRESSES=", f); + space = false; + SET_FOREACH(a, link->addresses, i) { + _cleanup_free_ char *address_str = NULL; + + r = in_addr_to_string(a->family, &a->in_addr, &address_str); + if (r < 0) + goto fail; + + fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen); + space = true; + } + + fputc('\n', f); + + fputs("ROUTES=", f); + space = false; + SET_FOREACH(route, link->routes, i) { + _cleanup_free_ char *route_str = NULL; + + r = in_addr_to_string(route->family, &route->dst, &route_str); + if (r < 0) + goto fail; + + fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%hhu/"USEC_FMT, space ? " " : "", route_str, + route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime); + space = true; + } + + fputc('\n', f); } if (!hashmap_isempty(link->bound_to_links)) { Link *carrier; - Iterator i; bool space = false; fputs("CARRIER_BOUND_TO=", f); @@ -2650,12 +2784,11 @@ int link_save(Link *link) { space = true; } - fputs("\n", f); + fputc('\n', f); } if (!hashmap_isempty(link->bound_by_links)) { Link *carrier; - Iterator i; bool space = false; fputs("CARRIER_BOUND_BY=", f); @@ -2666,19 +2799,25 @@ int link_save(Link *link) { space = true; } - fputs("\n", f); + fputc('\n', f); } if (link->dhcp_lease) { + struct in_addr address; const char *tz = NULL; + assert(link->network); + r = sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); if (r >= 0) fprintf(f, "TIMEZONE=%s\n", tz); - } - if (link->dhcp_lease) { - assert(link->network); + r = sd_dhcp_lease_get_address(link->dhcp_lease, &address); + if (r >= 0) { + fputs("DHCP4_ADDRESS=", f); + serialize_in_addrs(f, &address, 1); + fputc('\n', f); + } r = dhcp_lease_save(link->dhcp_lease, link->lease_file); if (r < 0) @@ -2690,6 +2829,17 @@ int link_save(Link *link) { } else unlink(link->lease_file); + if (link->ipv4ll) { + struct in_addr address; + + r = sd_ipv4ll_get_address(link->ipv4ll, &address); + if (r >= 0) { + fputs("IPV4LL_ADDRESS=", f); + serialize_in_addrs(f, &address, 1); + fputc('\n', f); + } + } + if (link->lldp) { assert(link->network); @@ -2722,6 +2872,34 @@ fail: return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file); } +/* The serialized state in /run is no longer up-to-date. */ +void link_dirty(Link *link) { + int r; + + assert(link); + + r = set_ensure_allocated(&link->manager->dirty_links, NULL); + if (r < 0) + /* allocation errors are ignored */ + return; + + r = set_put(link->manager->dirty_links, link); + if (r < 0) + /* allocation errors are ignored */ + return; + + link_ref(link); +} + +/* The serialized state in /run is up-to-date */ +void link_clean(Link *link) { + assert(link); + assert(link->manager); + + set_remove(link->manager->dirty_links, link); + link_unref(link); +} + static const char* const link_state_table[_LINK_STATE_MAX] = { [LINK_STATE_PENDING] = "pending", [LINK_STATE_ENSLAVING] = "configuring", diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 7b219c6854..a22041870e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -25,10 +25,10 @@ #include "sd-dhcp-client.h" #include "sd-dhcp-server.h" -#include "sd-ipv4ll.h" -#include "sd-icmp6-nd.h" #include "sd-dhcp6-client.h" +#include "sd-ipv4ll.h" #include "sd-lldp.h" +#include "sd-ndisc.h" typedef struct Link Link; @@ -83,7 +83,10 @@ struct Link { unsigned link_messages; unsigned enslaving; - LIST_HEAD(Address, addresses); + Set *addresses; + Set *addresses_foreign; + Set *routes; + Set *routes_foreign; sd_dhcp_client *dhcp_client; sd_dhcp_lease *dhcp_lease; @@ -103,7 +106,7 @@ struct Link { sd_dhcp_server *dhcp_server; - sd_icmp6_nd *icmp6_router_discovery; + sd_ndisc *ndisc_router_discovery; sd_dhcp6_client *dhcp6_client; bool rtnl_extended_attrs; @@ -120,17 +123,19 @@ int link_get(Manager *m, int ifindex, Link **ret); int link_add(Manager *manager, sd_netlink_message *message, Link **ret); void link_drop(Link *link); -int link_address_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); -int link_route_drop_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); +int link_address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); +int link_route_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata); void link_enter_failed(Link *link); int link_initialized(Link *link, struct udev_device *device); -void link_client_handler(Link *link); +void link_check_ready(Link *link); +void link_update_operstate(Link *link); int link_update(Link *link, sd_netlink_message *message); -int link_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata); +void link_dirty(Link *link); +void link_clean(Link *link); int link_save(Link *link); int link_carrier_reset(Link *link); @@ -142,7 +147,8 @@ int link_set_timezone(Link *link, const char *timezone); int ipv4ll_configure(Link *link); int dhcp4_configure(Link *link); -int icmp6_configure(Link *link); +int dhcp6_configure(Link *link, bool information_request); +int ndisc_configure(Link *link); bool link_lldp_enabled(Link *link); bool link_ipv4ll_enabled(Link *link); diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index b281f4fdb6..dafaf2daea 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-util.h" - #include "networkd.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState); diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index b4259cafef..a5701001c1 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -22,21 +22,23 @@ #include <sys/socket.h> #include <linux/if.h> -#include "sd-netlink.h" #include "sd-daemon.h" +#include "sd-netlink.h" -#include "conf-parser.h" -#include "path-util.h" -#include "libudev-private.h" -#include "udev-util.h" -#include "netlink-util.h" +#include "alloc-util.h" #include "bus-util.h" +#include "conf-parser.h" #include "def.h" -#include "virt.h" -#include "set.h" +#include "fd-util.h" +#include "fileio.h" +#include "libudev-private.h" #include "local-addresses.h" - +#include "netlink-util.h" #include "networkd.h" +#include "path-util.h" +#include "set.h" +#include "udev-util.h" +#include "virt.h" /* use 8 MB for receive socket kernel queue. */ #define RCVBUF_SIZE (8*1024*1024) @@ -277,6 +279,348 @@ static int manager_connect_udev(Manager *m) { return 0; } +int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { + Manager *m = userdata; + Link *link = NULL; + uint16_t type; + uint32_t ifindex, priority = 0; + unsigned char protocol, scope, tos, table; + int family; + unsigned char dst_prefixlen, src_prefixlen; + union in_addr_union dst = {}, gw = {}, src = {}, prefsrc = {}; + Route *route = NULL; + int r; + + assert(rtnl); + assert(message); + assert(m); + + if (sd_netlink_message_is_error(message)) { + r = sd_netlink_message_get_errno(message); + if (r < 0) + log_warning_errno(r, "rtnl: failed to receive route: %m"); + + return 0; + } + + r = sd_netlink_message_get_type(message, &type); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get message type: %m"); + return 0; + } else if (type != RTM_NEWROUTE && type != RTM_DELROUTE) { + log_warning("rtnl: received unexpected message type when processing route"); + return 0; + } + + r = sd_netlink_message_read_u32(message, RTA_OIF, &ifindex); + if (r == -ENODATA) { + log_debug("rtnl: received route without ifindex, ignoring"); + return 0; + } else if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex from route, ignoring: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received route message with invalid ifindex, ignoring: %d", ifindex); + return 0; + } else { + r = link_get(m, ifindex, &link); + if (r < 0 || !link) { + /* when enumerating we might be out of sync, but we will + * get the route again, so just ignore it */ + if (!m->enumerating) + log_warning("rtnl: received route for nonexistent link (%d), ignoring", ifindex); + return 0; + } + } + + r = sd_rtnl_message_route_get_family(message, &family); + if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) { + log_link_warning(link, "rtnl: received address with invalid family, ignoring."); + return 0; + } + + r = sd_rtnl_message_route_get_protocol(message, &protocol); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get route protocol: %m"); + return 0; + } + + switch (family) { + case AF_INET: + r = sd_netlink_message_read_in_addr(message, RTA_DST, &dst.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &gw.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in_addr(message, RTA_SRC, &src.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &prefsrc.in); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m"); + return 0; + } + + break; + + case AF_INET6: + r = sd_netlink_message_read_in6_addr(message, RTA_DST, &dst.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route without valid destination, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &gw.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid gateway, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &src.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid source, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &prefsrc.in6); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid preferred source, ignoring: %m"); + return 0; + } + + break; + + default: + log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family); + return 0; + } + + r = sd_rtnl_message_route_get_dst_prefixlen(message, &dst_prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid destination prefixlen, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_src_prefixlen(message, &src_prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid source prefixlen, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_scope(message, &scope); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid scope, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_tos(message, &tos); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid tos, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_route_get_table(message, &table); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received route with invalid table, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_u32(message, RTA_PRIORITY, &priority); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route with invalid priority, ignoring: %m"); + return 0; + } + + route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route); + + switch (type) { + case RTM_NEWROUTE: + if (!route) { + /* A route appeared that we did not request */ + r = route_add_foreign(link, family, &dst, dst_prefixlen, tos, priority, table, &route); + if (r < 0) + return 0; + } + + route_update(route, &src, src_prefixlen, &gw, &prefsrc, scope, protocol); + + break; + + case RTM_DELROUTE: + + if (route) + route_drop(route); + + break; + default: + assert_not_reached("Received invalid RTNL message type"); + } + + return 1; +} + +int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { + Manager *m = userdata; + Link *link = NULL; + uint16_t type; + unsigned char flags; + int family; + unsigned char prefixlen; + unsigned char scope; + union in_addr_union in_addr; + struct ifa_cacheinfo cinfo; + Address *address = NULL; + char buf[INET6_ADDRSTRLEN], valid_buf[FORMAT_TIMESPAN_MAX]; + const char *valid_str = NULL; + int r, ifindex; + + assert(rtnl); + assert(message); + assert(m); + + if (sd_netlink_message_is_error(message)) { + r = sd_netlink_message_get_errno(message); + if (r < 0) + log_warning_errno(r, "rtnl: failed to receive address: %m"); + + return 0; + } + + r = sd_netlink_message_get_type(message, &type); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get message type: %m"); + return 0; + } else if (type != RTM_NEWADDR && type != RTM_DELADDR) { + log_warning("rtnl: received unexpected message type when processing address"); + return 0; + } + + r = sd_rtnl_message_addr_get_ifindex(message, &ifindex); + if (r < 0) { + log_warning_errno(r, "rtnl: could not get ifindex from address: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received address message with invalid ifindex: %d", ifindex); + return 0; + } else { + r = link_get(m, ifindex, &link); + if (r < 0 || !link) { + /* when enumerating we might be out of sync, but we will + * get the address again, so just ignore it */ + if (!m->enumerating) + log_warning("rtnl: received address for nonexistent link (%d), ignoring", ifindex); + return 0; + } + } + + r = sd_rtnl_message_addr_get_family(message, &family); + if (r < 0 || !IN_SET(family, AF_INET, AF_INET6)) { + log_link_warning(link, "rtnl: received address with invalid family, ignoring."); + return 0; + } + + r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address with invalid prefixlen, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_addr_get_scope(message, &scope); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address with invalid scope, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_addr_get_flags(message, &flags); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address with invalid flags, ignoring: %m"); + return 0; + } + + switch (family) { + case AF_INET: + r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); + return 0; + } + + break; + + case AF_INET6: + r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: received address without valid address, ignoring: %m"); + return 0; + } + + break; + + default: + log_link_debug(link, "rtnl: ignoring unsupported address family: %d", family); + } + + if (!inet_ntop(family, &in_addr, buf, INET6_ADDRSTRLEN)) { + log_link_warning(link, "Could not print address"); + return 0; + } + + r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo); + if (r >= 0) { + if (cinfo.ifa_valid == CACHE_INFO_INFINITY_LIFE_TIME) + valid_str = "ever"; + else + valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, + cinfo.ifa_valid * USEC_PER_SEC, + USEC_PER_SEC); + } + + address_get(link, family, &in_addr, prefixlen, &address); + + switch (type) { + case RTM_NEWADDR: + if (address) + log_link_debug(link, "Updating address: %s/%u (valid for %s)", buf, prefixlen, valid_str); + else { + /* An address appeared that we did not request */ + r = address_add_foreign(link, family, &in_addr, prefixlen, &address); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to add address %s/%u: %m", buf, prefixlen); + return 0; + } else + log_link_debug(link, "Adding address: %s/%u (valid for %s)", buf, prefixlen, valid_str); + } + + address_update(address, flags, scope, &cinfo); + + break; + + case RTM_DELADDR: + + if (address) { + log_link_debug(link, "Removing address: %s/%u (valid for %s)", buf, prefixlen, valid_str); + address_drop(address); + } else + log_link_warning(link, "Removing non-existent address: %s/%u (valid for %s)", buf, prefixlen, valid_str); + + break; + default: + assert_not_reached("Received invalid RTNL message type"); + } + + return 1; +} + static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) { Manager *m = userdata; Link *link = NULL; @@ -410,17 +754,232 @@ static int manager_connect_rtnl(Manager *m) { if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m); + r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &manager_rtnl_process_address, m); + if (r < 0) + return r; + + r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &manager_rtnl_process_address, m); if (r < 0) return r; - r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m); + r = sd_netlink_add_match(m->rtnl, RTM_NEWROUTE, &manager_rtnl_process_route, m); + if (r < 0) + return r; + + r = sd_netlink_add_match(m->rtnl, RTM_DELROUTE, &manager_rtnl_process_route, m); if (r < 0) return r; return 0; } +static int set_put_in_addr(Set *s, const struct in_addr *address) { + char *p; + int r; + + assert(s); + + r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); + if (r < 0) + return r; + + r = set_consume(s, p); + if (r == -EEXIST) + return 0; + + return r; +} + +static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) { + int r, i, c = 0; + + assert(s); + assert(n <= 0 || addresses); + + for (i = 0; i < n; i++) { + r = set_put_in_addr(s, addresses+i); + if (r < 0) + return r; + + c += r; + } + + return c; +} + +static void print_string_set(FILE *f, const char *field, Set *s) { + bool space = false; + Iterator i; + char *p; + + if (set_isempty(s)) + return; + + fputs(field, f); + + SET_FOREACH(p, s, i) { + if (space) + fputc(' ', f); + fputs(p, f); + space = true; + } + fputc('\n', f); +} + +static int manager_save(Manager *m) { + _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL; + Link *link; + Iterator i; + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + LinkOperationalState operstate = LINK_OPERSTATE_OFF; + const char *operstate_str; + int r; + + assert(m); + assert(m->state_file); + + /* We add all NTP and DNS server to a set, to filter out duplicates */ + dns = set_new(&string_hash_ops); + if (!dns) + return -ENOMEM; + + ntp = set_new(&string_hash_ops); + if (!ntp) + return -ENOMEM; + + domains = set_new(&string_hash_ops); + if (!domains) + return -ENOMEM; + + HASHMAP_FOREACH(link, m->links, i) { + if (link->flags & IFF_LOOPBACK) + continue; + + if (link->operstate > operstate) + operstate = link->operstate; + + if (!link->network) + continue; + + /* First add the static configured entries */ + r = set_put_strdupv(dns, link->network->dns); + if (r < 0) + return r; + + r = set_put_strdupv(ntp, link->network->ntp); + if (r < 0) + return r; + + r = set_put_strdupv(domains, link->network->domains); + if (r < 0) + return r; + + if (!link->dhcp_lease) + continue; + + /* Secondly, add the entries acquired via DHCP */ + if (link->network->dhcp_dns) { + const struct in_addr *addresses; + + r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); + if (r > 0) { + r = set_put_in_addrv(dns, addresses, r); + if (r < 0) + return r; + } else if (r < 0 && r != -ENODATA) + return r; + } + + if (link->network->dhcp_ntp) { + const struct in_addr *addresses; + + r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); + if (r > 0) { + r = set_put_in_addrv(ntp, addresses, r); + if (r < 0) + return r; + } else if (r < 0 && r != -ENODATA) + return r; + } + + if (link->network->dhcp_domains) { + const char *domainname; + + r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); + if (r >= 0) { + r = set_put_strdup(domains, domainname); + if (r < 0) + return r; + } else if (r != -ENODATA) + return r; + } + } + + operstate_str = link_operstate_to_string(operstate); + assert(operstate_str); + + r = fopen_temporary(m->state_file, &f, &temp_path); + if (r < 0) + return r; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "OPER_STATE=%s\n", operstate_str); + + print_string_set(f, "DNS=", dns); + print_string_set(f, "NTP=", ntp); + print_string_set(f, "DOMAINS=", domains); + + r = fflush_and_check(f); + if (r < 0) + goto fail; + + if (rename(temp_path, m->state_file) < 0) { + r = -errno; + goto fail; + } + + if (m->operational_state != operstate) { + m->operational_state = operstate; + r = manager_send_changed(m, "OperationalState", NULL); + if (r < 0) + log_error_errno(r, "Could not emit changed OperationalState: %m"); + } + + m->dirty = false; + + return 0; + +fail: + (void) unlink(m->state_file); + (void) unlink(temp_path); + + return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); +} + +static int manager_dirty_handler(sd_event_source *s, void *userdata) { + Manager *m = userdata; + Link *link; + Iterator i; + int r; + + assert(m); + + if (m->dirty) + manager_save(m); + + SET_FOREACH(link, m->dirty_links, i) { + r = link_save(link); + if (r >= 0) + link_clean(link); + } + + return 1; +} + int manager_new(Manager **ret) { _cleanup_manager_free_ Manager *m = NULL; int r; @@ -442,6 +1001,10 @@ int manager_new(Manager **ret) { sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL); sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL); + r = sd_event_add_post(m->event, NULL, manager_dirty_handler, m); + if (r < 0) + return r; + r = manager_connect_rtnl(m); if (r < 0) return r; @@ -477,14 +1040,6 @@ void manager_free(Manager *m) { free(m->state_file); - sd_event_source_unref(m->udev_event_source); - udev_monitor_unref(m->udev_monitor); - udev_unref(m->udev); - - sd_bus_unref(m->bus); - sd_bus_slot_unref(m->prepare_for_sleep_slot); - sd_event_source_unref(m->bus_retry_event_source); - while ((link = hashmap_first(m->links))) link_unref(link); hashmap_free(m->links); @@ -504,6 +1059,14 @@ void manager_free(Manager *m) { sd_netlink_unref(m->rtnl); sd_event_unref(m->event); + sd_event_source_unref(m->udev_event_source); + udev_monitor_unref(m->udev_monitor); + udev_unref(m->udev); + + sd_bus_unref(m->bus); + sd_bus_slot_unref(m->prepare_for_sleep_slot); + sd_event_source_unref(m->bus_retry_event_source); + free(m); } @@ -536,8 +1099,19 @@ static bool manager_check_idle(void *userdata) { } int manager_run(Manager *m) { + Link *link; + Iterator i; + assert(m); + /* The dirty handler will deal with future serialization, but the first one + must be done explicitly. */ + + manager_save(m); + + HASHMAP_FOREACH(link, m->links, i) + link_save(link); + if (m->bus) return bus_event_loop_with_idle( m->event, @@ -633,7 +1207,7 @@ int manager_rtnl_enumerate_addresses(Manager *m) { m->enumerating = true; - k = link_rtnl_process_address(m->rtnl, addr, m); + k = manager_rtnl_process_address(m->rtnl, addr, m); if (k < 0) r = k; @@ -643,189 +1217,39 @@ int manager_rtnl_enumerate_addresses(Manager *m) { return r; } -static int set_put_in_addr(Set *s, const struct in_addr *address) { - char *p; +int manager_rtnl_enumerate_routes(Manager *m) { + _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + sd_netlink_message *route; int r; - assert(s); + assert(m); + assert(m->rtnl); - r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); + r = sd_rtnl_message_new_route(m->rtnl, &req, RTM_GETROUTE, 0, 0); if (r < 0) return r; - r = set_consume(s, p); - if (r == -EEXIST) - return 0; - - return r; -} - -static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) { - int r, i, c = 0; - - assert(s); - assert(n <= 0 || addresses); - - for (i = 0; i < n; i++) { - r = set_put_in_addr(s, addresses+i); - if (r < 0) - return r; - - c += r; - } - - return c; -} - -static void print_string_set(FILE *f, const char *field, Set *s) { - bool space = false; - Iterator i; - char *p; - - if (set_isempty(s)) - return; - - fputs(field, f); - - SET_FOREACH(p, s, i) { - if (space) - fputc(' ', f); - fputs(p, f); - space = true; - } - fputc('\n', f); -} - -int manager_save(Manager *m) { - _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL; - Link *link; - Iterator i; - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - LinkOperationalState operstate = LINK_OPERSTATE_OFF; - const char *operstate_str; - int r; - - assert(m); - assert(m->state_file); - - /* We add all NTP and DNS server to a set, to filter out duplicates */ - dns = set_new(&string_hash_ops); - if (!dns) - return -ENOMEM; - - ntp = set_new(&string_hash_ops); - if (!ntp) - return -ENOMEM; - - domains = set_new(&string_hash_ops); - if (!domains) - return -ENOMEM; - - HASHMAP_FOREACH(link, m->links, i) { - if (link->flags & IFF_LOOPBACK) - continue; - - if (link->operstate > operstate) - operstate = link->operstate; - - if (!link->network) - continue; - - /* First add the static configured entries */ - r = set_put_strdupv(dns, link->network->dns); - if (r < 0) - return r; - - r = set_put_strdupv(ntp, link->network->ntp); - if (r < 0) - return r; - - r = set_put_strdupv(domains, link->network->domains); - if (r < 0) - return r; - - if (!link->dhcp_lease) - continue; - - /* Secondly, add the entries acquired via DHCP */ - if (link->network->dhcp_dns) { - const struct in_addr *addresses; - - r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); - if (r > 0) { - r = set_put_in_addrv(dns, addresses, r); - if (r < 0) - return r; - } else if (r < 0 && r != -ENODATA) - return r; - } - - if (link->network->dhcp_ntp) { - const struct in_addr *addresses; - - r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); - if (r > 0) { - r = set_put_in_addrv(ntp, addresses, r); - if (r < 0) - return r; - } else if (r < 0 && r != -ENODATA) - return r; - } - - if (link->network->dhcp_domains) { - const char *domainname; - - r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); - if (r >= 0) { - r = set_put_strdup(domains, domainname); - if (r < 0) - return r; - } else if (r != -ENODATA) - return r; - } - } - - operstate_str = link_operstate_to_string(operstate); - assert(operstate_str); - - r = fopen_temporary(m->state_file, &f, &temp_path); + r = sd_netlink_message_request_dump(req, true); if (r < 0) return r; - fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n" - "OPER_STATE=%s\n", operstate_str); - - print_string_set(f, "DNS=", dns); - print_string_set(f, "NTP=", ntp); - print_string_set(f, "DOMAINS=", domains); - - r = fflush_and_check(f); + r = sd_netlink_call(m->rtnl, req, 0, &reply); if (r < 0) - goto fail; + return r; - if (rename(temp_path, m->state_file) < 0) { - r = -errno; - goto fail; - } + for (route = reply; route; route = sd_netlink_message_next(route)) { + int k; - if (m->operational_state != operstate) { - m->operational_state = operstate; - r = manager_send_changed(m, "OperationalState", NULL); - if (r < 0) - log_error_errno(r, "Could not emit changed OperationalState: %m"); - } + m->enumerating = true; - return 0; + k = manager_rtnl_process_route(m->rtnl, route, m); + if (k < 0) + r = k; -fail: - (void) unlink(m->state_file); - (void) unlink(temp_path); + m->enumerating = false; + } - return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); + return r; } int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) { @@ -884,3 +1308,10 @@ Link* manager_find_uplink(Manager *m, Link *exclude) { return NULL; } + +void manager_dirty(Manager *manager) { + assert(manager); + + /* the serialized state in /run is no longer up-to-date */ + manager->dirty = true; +} diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c new file mode 100644 index 0000000000..33e692f97f --- /dev/null +++ b/src/network/networkd-ndisc.c @@ -0,0 +1,88 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <netinet/ether.h> +#include <linux/if.h> + +#include "sd-ndisc.h" + +#include "networkd-link.h" + +static void ndisc_router_handler(sd_ndisc *nd, int event, void *userdata) { + Link *link = userdata; + + assert(link); + assert(link->network); + assert(link->manager); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + + switch(event) { + case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE: + return; + + case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER: + dhcp6_configure(link, true); + + break; + case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT: + case SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED: + dhcp6_configure(link, false); + + break; + + default: + if (event < 0) + log_link_warning_errno(link, event, "IPv6 Neighbor Discover error: %m"); + else + log_link_warning(link, "IPv6 Neighbor Discovery unknown event: %d", event); + + break; + } +} + +int ndisc_configure(Link *link) { + int r; + + assert_return(link, -EINVAL); + + r = sd_ndisc_new(&link->ndisc_router_discovery); + if (r < 0) + return r; + + r = sd_ndisc_attach_event(link->ndisc_router_discovery, NULL, 0); + if (r < 0) + return r; + + r = sd_ndisc_set_mac(link->ndisc_router_discovery, &link->mac); + if (r < 0) + return r; + + r = sd_ndisc_set_index(link->ndisc_router_discovery, link->ifindex); + if (r < 0) + return r; + + r = sd_ndisc_set_callback(link->ndisc_router_discovery, + ndisc_router_handler, link); + + return r; +} diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index 12e2321674..70105b8aa0 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -23,10 +23,14 @@ #include <netinet/ether.h> #include <linux/if_bonding.h> -#include "conf-parser.h" #include "sd-netlink.h" -#include "networkd-netdev-bond.h" + +#include "alloc-util.h" +#include "conf-parser.h" #include "missing.h" +#include "networkd-netdev-bond.h" +#include "string-util.h" +#include "string-table.h" /* * Number of seconds between instances where the bonding @@ -178,15 +182,18 @@ static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) { } static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { - Bond *b = BOND(netdev); + Bond *b; ArpIpTarget *target = NULL; int r, i = 0; assert(netdev); assert(!link); - assert(b); assert(m); + b = BOND(netdev); + + assert(b); + if (b->mode != _NETDEV_BOND_MODE_INVALID) { r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, bond_mode_to_kernel(b->mode)); @@ -357,12 +364,12 @@ int config_parse_arp_ip_target_address(const char *unit, r = in_addr_from_string_auto(n, &f, &buffer->ip); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); + log_syntax(unit, LOG_ERR, filename, line, r, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); return 0; } if (f != AF_INET) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); + log_syntax(unit, LOG_ERR, filename, line, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n); return 0; } @@ -373,16 +380,19 @@ int config_parse_arp_ip_target_address(const char *unit, } if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX) - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX); + log_syntax(unit, LOG_WARNING, filename, line, 0, "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d", b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX); return 0; } static void bond_done(NetDev *netdev) { ArpIpTarget *t = NULL, *n = NULL; - Bond *b = BOND(netdev); + Bond *b; assert(netdev); + + b = BOND(netdev); + assert(b); LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets) @@ -392,9 +402,12 @@ static void bond_done(NetDev *netdev) { } static void bond_init(NetDev *netdev) { - Bond *b = BOND(netdev); + Bond *b; assert(netdev); + + b = BOND(netdev); + assert(b); b->mode = _NETDEV_BOND_MODE_INVALID; diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index fd6af7e99b..57c58d83b4 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -20,12 +20,97 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <net/if.h> #include "networkd-netdev-bridge.h" #include "missing.h" +#include "netlink-util.h" + +/* callback for brige netdev's parameter set */ +static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { + _cleanup_netdev_unref_ NetDev *netdev = userdata; + int r; + + assert(netdev); + assert(m); + + r = sd_netlink_message_get_errno(m); + if (r < 0) { + log_netdev_warning_errno(netdev, r, "Bridge parameters could not be set: %m"); + return 1; + } + + log_netdev_debug(netdev, "Bridge parametres set success"); + + return 1; +} + +static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) { + _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + Bridge *b; + int r; + + assert(netdev); + + b = BRIDGE(netdev); + + assert(b); + + r = sd_rtnl_message_new_link(netdev->manager->rtnl, &req, RTM_NEWLINK, netdev->ifindex); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not allocate RTM_SETLINK message: %m"); + + r = sd_netlink_message_set_flags(req, NLM_F_REQUEST | NLM_F_ACK); + if (r < 0) + return log_link_error_errno(link, r, "Could not set netlink flags: %m"); + + r = sd_netlink_message_open_container(req, IFLA_LINKINFO); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_PROTINFO attribute: %m"); + + r = sd_netlink_message_open_container_union(req, IFLA_INFO_DATA, netdev_kind_to_string(netdev->kind)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); + + /* convert to jiffes */ + if (b->forward_delay > 0) { + r = sd_netlink_message_append_u32(req, IFLA_BR_FORWARD_DELAY, usec_to_jiffies(b->forward_delay)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_FORWARD_DELAY attribute: %m"); + } + + if (b->hello_time > 0) { + r = sd_netlink_message_append_u32(req, IFLA_BR_HELLO_TIME, usec_to_jiffies(b->hello_time)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_HELLO_TIME attribute: %m"); + } + + if (b->max_age > 0) { + r = sd_netlink_message_append_u32(req, IFLA_BR_MAX_AGE, usec_to_jiffies(b->max_age)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_MAX_AGE attribute: %m"); + } + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m"); + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_INFO_DATA attribute: %m"); + + r = sd_netlink_call_async(netdev->manager->rtnl, req, netdev_bridge_set_handler, netdev, 0, NULL); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m"); + + netdev_ref(netdev); + + return r; +} const NetDevVTable bridge_vtable = { .object_size = sizeof(Bridge), - .sections = "Match\0NetDev\0", + .sections = "Match\0NetDev\0Bridge\0", + .post_create = netdev_bridge_post_create, .create_type = NETDEV_CREATE_MASTER, }; diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index a7d02b1c91..d3bd15e0d6 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -27,6 +27,10 @@ typedef struct Bridge Bridge; struct Bridge { NetDev meta; + + usec_t forward_delay; + usec_t hello_time; + usec_t max_age; }; extern const NetDevVTable bridge_vtable; diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index e0bd0e024a..4aac239850 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -86,3 +86,6 @@ Bond.UpDelaySec, config_parse_sec, 0, Bond.DownDelaySec, config_parse_sec, 0, offsetof(Bond, downdelay) Bond.ARPIntervalSec, config_parse_sec, 0, offsetof(Bond, arp_interval) Bond.LearnPacketIntervalSec, config_parse_sec, 0, offsetof(Bond, lp_interval) +Bridge.HelloTimeSec, config_parse_sec, 0, offsetof(Bridge, hello_time) +Bridge.MaxAgeSec, config_parse_sec, 0, offsetof(Bridge, max_age) +Bridge.ForwardDelaySec, config_parse_sec, 0, offsetof(Bridge, forward_delay) diff --git a/src/network/networkd-netdev-ipvlan.c b/src/network/networkd-netdev-ipvlan.c index 5eb4a1eb36..27cb7d1bf0 100644 --- a/src/network/networkd-netdev-ipvlan.c +++ b/src/network/networkd-netdev-ipvlan.c @@ -21,8 +21,9 @@ #include <net/if.h> -#include "networkd-netdev-ipvlan.h" #include "conf-parser.h" +#include "networkd-netdev-ipvlan.h" +#include "string-table.h" static const char* const ipvlan_mode_table[_NETDEV_IPVLAN_MODE_MAX] = { [NETDEV_IPVLAN_MODE_L2] = "L2", @@ -33,14 +34,17 @@ DEFINE_STRING_TABLE_LOOKUP(ipvlan_mode, IPVlanMode); DEFINE_CONFIG_PARSE_ENUM(config_parse_ipvlan_mode, ipvlan_mode, IPVlanMode, "Failed to parse ipvlan mode"); static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { - IPVlan *m = IPVLAN(netdev); + IPVlan *m; int r; assert(netdev); - assert(m); assert(link); assert(netdev->ifname); + m = IPVLAN(netdev); + + assert(m); + if (m->mode != _NETDEV_IPVLAN_MODE_INVALID) { r = sd_netlink_message_append_u16(req, IFLA_IPVLAN_MODE, m->mode); if (r < 0) @@ -51,9 +55,12 @@ static int netdev_ipvlan_fill_message_create(NetDev *netdev, Link *link, sd_netl } static void ipvlan_init(NetDev *n) { - IPVlan *m = IPVLAN(n); + IPVlan *m; assert(n); + + m = IPVLAN(n); + assert(m); m->mode = _NETDEV_IPVLAN_MODE_INVALID; diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c index e17de793ce..7144823b2d 100644 --- a/src/network/networkd-netdev-macvlan.c +++ b/src/network/networkd-netdev-macvlan.c @@ -21,8 +21,9 @@ #include <net/if.h> -#include "networkd-netdev-macvlan.h" #include "conf-parser.h" +#include "networkd-netdev-macvlan.h" +#include "string-table.h" static const char* const macvlan_mode_table[_NETDEV_MACVLAN_MODE_MAX] = { [NETDEV_MACVLAN_MODE_PRIVATE] = "private", diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index a906e473b6..385338849f 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -26,11 +26,15 @@ #include <linux/ip6_tunnel.h> #include "sd-netlink.h" -#include "networkd-netdev-tunnel.h" + +#include "conf-parser.h" +#include "missing.h" #include "networkd-link.h" +#include "networkd-netdev-tunnel.h" +#include "parse-util.h" +#include "string-table.h" +#include "string-util.h" #include "util.h" -#include "missing.h" -#include "conf-parser.h" #define DEFAULT_TNL_HOP_LIMIT 64 #define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF) @@ -395,12 +399,12 @@ int config_parse_tunnel_address(const char *unit, r = in_addr_from_string_auto(rvalue, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel address is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue); return 0; } if (t->family != AF_UNSPEC && t->family != f) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue); return 0; } @@ -435,13 +439,14 @@ int config_parse_ipv6_flowlabel(const char* unit, t->flags |= IP6_TNL_F_USE_ORIG_FLOWLABEL; } else { r = config_parse_int(unit, filename, line, section, section_line, lvalue, ltype, rvalue, &k, userdata); - if (r >= 0) { - if (k > 0xFFFFF) - log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue); - else { - *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL; - t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; - } + if (r < 0) + return r; + + if (k > 0xFFFFF) + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 flowlabel option, ignoring: %s", rvalue); + else { + *ipv6_flowlabel = htonl(k) & IP6_FLOWINFO_FLOWLABEL; + t->flags &= ~IP6_TNL_F_USE_ORIG_FLOWLABEL; } } @@ -471,13 +476,12 @@ int config_parse_encap_limit(const char* unit, else { r = safe_atoi(rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Tunnel Encapsulation Limit option, ignoring: %s", rvalue); return 0; } if (k > 255 || k < 0) - log_syntax(unit, LOG_ERR, filename, line, k, "Invalid Tunnel Encapsulation value, ignoring: %d", k); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid Tunnel Encapsulation value, ignoring: %d", k); else { t->encap_limit = k; t->flags &= ~IP6_TNL_F_IGN_ENCAP_LIMIT; diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index 6a808b6205..851e83537e 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -23,7 +23,10 @@ #include <net/if.h> #include <linux/if_tun.h> +#include "alloc-util.h" +#include "fd-util.h" #include "networkd-netdev-tuntap.h" +#include "user-util.h" #define TUN_DEV "/dev/net/tun" diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c index e20f9f74e2..bee1a16726 100644 --- a/src/network/networkd-netdev-veth.c +++ b/src/network/networkd-netdev-veth.c @@ -26,14 +26,17 @@ #include "networkd-netdev-veth.h" static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { - Veth *v = VETH(netdev); + Veth *v; int r; assert(netdev); assert(!link); - assert(v); assert(m); + v = VETH(netdev); + + assert(v); + r = sd_netlink_message_open_container(m, VETH_INFO_PEER); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append VETH_INFO_PEER attribute: %m"); @@ -58,13 +61,16 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlin } static int netdev_veth_verify(NetDev *netdev, const char *filename) { - Veth *v = VETH(netdev); + Veth *v; int r; assert(netdev); - assert(v); assert(filename); + v = VETH(netdev); + + assert(v); + if (!v->ifname_peer) { log_warning("Veth NetDev without peer name configured in %s. Ignoring", filename); @@ -84,9 +90,12 @@ static int netdev_veth_verify(NetDev *netdev, const char *filename) { } static void veth_done(NetDev *n) { - Veth *v = VETH(n); + Veth *v; assert(n); + + v = VETH(n); + assert(v); free(v->ifname_peer); diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c index 195d1a944e..75fbdd355e 100644 --- a/src/network/networkd-netdev-vlan.c +++ b/src/network/networkd-netdev-vlan.c @@ -24,14 +24,17 @@ #include "networkd-netdev-vlan.h" static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *req) { - VLan *v = VLAN(netdev); + VLan *v; int r; assert(netdev); - assert(v); assert(link); assert(req); + v = VLAN(netdev); + + assert(v); + if (v->id <= VLANID_MAX) { r = sd_netlink_message_append_u16(req, IFLA_VLAN_ID, v->id); if (r < 0) @@ -42,12 +45,15 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin } static int netdev_vlan_verify(NetDev *netdev, const char *filename) { - VLan *v = VLAN(netdev); + VLan *v; assert(netdev); - assert(v); assert(filename); + v = VLAN(netdev); + + assert(v); + if (v->id > VLANID_MAX) { log_warning("VLAN without valid Id (%"PRIu64") configured in %s. Ignoring", v->id, filename); return -EINVAL; diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index 2518e2732b..baf6dd6623 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -28,14 +28,16 @@ #include "missing.h" static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { - VxLan *v = VXLAN(netdev); + VxLan *v; int r; assert(netdev); - assert(v); assert(link); assert(m); + v = VXLAN(netdev); + + assert(v); if (v->id <= VXLAN_VID_MAX) { r = sd_netlink_message_append_u32(m, IFLA_VXLAN_ID, v->id); @@ -131,14 +133,12 @@ int config_parse_vxlan_group_address(const char *unit, r = in_addr_from_string_auto(rvalue, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "vxlan multicast group address is invalid, ignoring assignment: %s", rvalue); return 0; } - if(v->family != AF_UNSPEC && v->family != f) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "vxlan multicast group incompatible, ignoring assignment: %s", rvalue); + if (v->family != AF_UNSPEC && v->family != f) { + log_syntax(unit, LOG_ERR, filename, line, 0, "vxlan multicast group incompatible, ignoring assignment: %s", rvalue); return 0; } @@ -164,9 +164,12 @@ static int netdev_vxlan_verify(NetDev *netdev, const char *filename) { } static void vxlan_init(NetDev *netdev) { - VxLan *v = VXLAN(netdev); + VxLan *v; assert(netdev); + + v = VXLAN(netdev); + assert(v); v->id = VXLAN_VID_MAX + 1; diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index ff1edf2c39..dd0b400c6a 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -21,15 +21,19 @@ #include <net/if.h> +#include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" +#include "fd-util.h" #include "list.h" -#include "siphash24.h" #include "netlink-util.h" #include "network-internal.h" - -#include "networkd.h" #include "networkd-netdev.h" +#include "networkd.h" +#include "siphash24.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { @@ -245,6 +249,9 @@ static int netdev_enter_ready(NetDev *netdev) { free(callback); } + if (NETDEV_VTABLE(netdev)->post_create) + NETDEV_VTABLE(netdev)->post_create(netdev, NULL, NULL); + return 0; } diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 1f8510c4f7..3b9ab27b67 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -141,6 +141,9 @@ struct NetDevVTable { /* create netdev, if not done via rtnl */ int (*create)(NetDev *netdev); + /* perform additional configuration after netdev has been createad */ + int (*post_create)(NetDev *netdev, Link *link, sd_netlink_message *message); + /* verify that compulsory configuration options were specified */ int (*config_verify)(NetDev *netdev, const char *filename); }; diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c index 5717a15327..120760a986 100644 --- a/src/network/networkd-network-bus.c +++ b/src/network/networkd-network-bus.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "strv.h" - +#include "alloc-util.h" #include "networkd.h" +#include "string-util.h" +#include "strv.h" static int property_get_ether_addrs( sd_bus *bus, diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 8257ab45da..cc01dc24c9 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -51,6 +51,7 @@ Network.IPForward, config_parse_address_family_boolean_with Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) +Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits) Network.BindCarrier, config_parse_strv, 0, offsetof(Network, bind_carrier) Address.Address, config_parse_address, 0, 0 Address.Peer, config_parse_address, 0, 0 @@ -61,6 +62,7 @@ Route.Destination, config_parse_destination, Route.Source, config_parse_destination, 0, 0 Route.Metric, config_parse_route_priority, 0, 0 Route.Scope, config_parse_route_scope, 0, 0 +Route.PreferredSource, config_parse_preferred_src, 0, 0 DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 57495b58e0..0188cb6fe5 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -22,15 +22,20 @@ #include <ctype.h> #include <net/if.h> +#include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" -#include "util.h" -#include "hostname-util.h" #include "dns-domain.h" +#include "fd-util.h" +#include "hostname-util.h" #include "network-internal.h" - -#include "networkd.h" #include "networkd-network.h" +#include "networkd.h" +#include "parse-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" static int network_load_one(Manager *manager, const char *filename) { _cleanup_network_free_ Network *network = NULL; @@ -121,6 +126,7 @@ static int network_load_one(Manager *manager, const char *filename) { network->ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO; network->ipv6_accept_ra = -1; + network->ipv6_dad_transmits = -1; r = config_parse(NULL, filename, file, "Match\0" @@ -326,12 +332,12 @@ int network_get(Manager *manager, struct udev_device *device, (void) safe_atou8(attr, &name_assign_type); if (name_assign_type == NET_NAME_ENUM) - log_warning("%-*s: found matching network '%s', based on potentially unpredictable ifname", - IFNAMSIZ, ifname, network->filename); + log_warning("%s: found matching network '%s', based on potentially unpredictable ifname", + ifname, network->filename); else - log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename); + log_debug("%s: found matching network '%s'", ifname, network->filename); } else - log_debug("%-*s: found matching network '%s'", IFNAMSIZ, ifname, network->filename); + log_debug("%s: found matching network '%s'", ifname, network->filename); *ret = network; return 0; @@ -346,6 +352,10 @@ int network_get(Manager *manager, struct udev_device *device, int network_apply(Manager *manager, Network *network, Link *link) { int r; + assert(manager); + assert(network); + assert(link); + link->network = network; if (network->ipv4ll_route) { @@ -355,7 +365,7 @@ int network_apply(Manager *manager, Network *network, Link *link) { if (r < 0) return r; - r = inet_pton(AF_INET, "169.254.0.0", &route->dst_addr.in); + r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in); if (r == 0) return -EINVAL; if (r < 0) @@ -364,14 +374,13 @@ int network_apply(Manager *manager, Network *network, Link *link) { route->family = AF_INET; route->dst_prefixlen = 16; route->scope = RT_SCOPE_LINK; - route->metrics = IPV4LL_ROUTE_METRIC; + route->priority = IPV4LL_ROUTE_METRIC; route->protocol = RTPROT_STATIC; } - if (network->dns || network->ntp) { - r = link_save(link); - if (r < 0) - return r; + if (network->dns || network->ntp || network->domains) { + manager_dirty(manager); + link_dirty(link); } return 0; @@ -409,21 +418,18 @@ int config_parse_netdev(const char *unit, kind = netdev_kind_from_string(kind_string); if (kind == _NETDEV_KIND_INVALID) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Invalid NetDev kind: %s", lvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue); return 0; } r = netdev_get(network->manager, rvalue, &netdev); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "%s could not be found, ignoring assignment: %s", lvalue, rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue); return 0; } if (netdev->kind != kind) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue); return 0; } @@ -443,9 +449,7 @@ int config_parse_netdev(const char *unit, case NETDEV_KIND_VXLAN: r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Can not add VLAN '%s' to network: %m", - rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Can not add VLAN '%s' to network: %m", rvalue); return 0; } @@ -484,7 +488,7 @@ int config_parse_domains(const char *unit, STRV_FOREACH(domain, *domains) { if (is_localhost(*domain)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain); + log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain); else { r = dns_name_is_valid(*domain); if (r <= 0 && !streq(*domain, "*")) { @@ -540,7 +544,7 @@ int config_parse_tunnel(const char *unit, netdev->kind != NETDEV_KIND_VTI6 && netdev->kind != NETDEV_KIND_IP6TNL ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, + log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a tunnel, ignoring assignment: %s", rvalue); return 0; } @@ -625,7 +629,7 @@ int config_parse_dhcp( else if (streq(rvalue, "both")) s = ADDRESS_FAMILY_YES; else { - log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue); return 0; } } @@ -670,13 +674,13 @@ int config_parse_ipv6token( } r = in_addr_is_null(AF_INET6, &buffer); - if (r < 0) { + if (r != 0) { log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token can not be the ANY address, ignoring: %s", rvalue); return 0; } if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token can not be longer than 64 bits, ignoring: %s", rvalue); return 0; } @@ -730,7 +734,7 @@ int config_parse_ipv6_privacy_extensions( if (streq(rvalue, "kernel")) s = _IPV6_PRIVACY_EXTENSIONS_INVALID; else { - log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue); return 0; } } @@ -765,7 +769,7 @@ int config_parse_hostname( return r; if (!hostname_is_valid(hn, false)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Hostname is not valid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue); free(hn); return 0; } @@ -799,7 +803,7 @@ int config_parse_timezone( return r; if (!timezone_is_valid(tz)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Timezone is not valid, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue); free(tz); return 0; } @@ -844,7 +848,7 @@ int config_parse_dhcp_server_dns( return 0; if (inet_pton(AF_INET, w, &a) <= 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server address, ignoring: %s", w); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w); continue; } @@ -883,7 +887,7 @@ int config_parse_dhcp_server_ntp( r = extract_first_word(&p, &w, NULL, 0); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, r, line, "Failed to extract word, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue); return 0; } @@ -891,7 +895,7 @@ int config_parse_dhcp_server_ntp( return 0; if (inet_pton(AF_INET, w, &a) <= 0) { - log_syntax(unit, LOG_ERR, filename, r, line, "Failed to parse NTP server address, ignoring: %s", w); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w); continue; } diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 2a43b6b347..c2872908b5 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -121,6 +121,7 @@ struct Network { bool ip_masquerade; int ipv6_accept_ra; + int ipv6_dad_transmits; union in_addr_union ipv6_token; IPv6PrivacyExtensions ipv6_privacy_extensions; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index fbaad40579..f4bbd06af1 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -19,15 +19,40 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" #include "conf-parser.h" +#include "event-util.h" +#include "in-addr-util.h" #include "netlink-util.h" - -#include "networkd.h" #include "networkd-route.h" +#include "networkd.h" +#include "parse-util.h" +#include "set.h" +#include "string-util.h" +#include "util.h" + +int route_new(Route **ret) { + _cleanup_route_free_ Route *route = NULL; + + route = new0(Route, 1); + if (!route) + return -ENOMEM; + + route->family = AF_UNSPEC; + route->scope = RT_SCOPE_UNIVERSE; + route->protocol = RTPROT_UNSPEC; + route->table = RT_TABLE_DEFAULT; + route->lifetime = USEC_INFINITY; + + *ret = route; + route = NULL; + + return 0; +} int route_new_static(Network *network, unsigned section, Route **ret) { _cleanup_route_free_ Route *route = NULL; + int r; if (section) { route = hashmap_get(network->routes_by_section, @@ -40,14 +65,11 @@ int route_new_static(Network *network, unsigned section, Route **ret) { } } - route = new0(Route, 1); - if (!route) - return -ENOMEM; + r = route_new(&route); + if (r < 0) + return r; - route->family = AF_UNSPEC; - route->scope = RT_SCOPE_UNIVERSE; route->protocol = RTPROT_STATIC; - route->network = network; LIST_PREPEND(routes, network->static_routes, route); @@ -64,23 +86,6 @@ int route_new_static(Network *network, unsigned section, Route **ret) { return 0; } -int route_new_dynamic(Route **ret, unsigned char rtm_protocol) { - _cleanup_route_free_ Route *route = NULL; - - route = new0(Route, 1); - if (!route) - return -ENOMEM; - - route->family = AF_UNSPEC; - route->scope = RT_SCOPE_UNIVERSE; - route->protocol = rtm_protocol; - - *ret = route; - route = NULL; - - return 0; -} - void route_free(Route *route) { if (!route) return; @@ -93,10 +98,241 @@ void route_free(Route *route) { UINT_TO_PTR(route->section)); } + if (route->link) { + set_remove(route->link->routes, route); + set_remove(route->link->routes_foreign, route); + } + + sd_event_source_unref(route->expire); + free(route); } -int route_drop(Route *route, Link *link, +static void route_hash_func(const void *b, struct siphash *state) { + const Route *route = b; + + assert(route); + + siphash24_compress(&route->family, sizeof(route->family), state); + + switch (route->family) { + case AF_INET: + case AF_INET6: + /* Equality of routes are given by the 4-touple + (dst_prefix,dst_prefixlen,tos,priority,table) */ + siphash24_compress(&route->dst, FAMILY_ADDRESS_SIZE(route->family), state); + siphash24_compress(&route->dst_prefixlen, sizeof(route->dst_prefixlen), state); + siphash24_compress(&route->tos, sizeof(route->tos), state); + siphash24_compress(&route->priority, sizeof(route->priority), state); + siphash24_compress(&route->table, sizeof(route->table), state); + + break; + default: + /* treat any other address family as AF_UNSPEC */ + break; + } +} + +static int route_compare_func(const void *_a, const void *_b) { + const Route *a = _a, *b = _b; + + if (a->family < b->family) + return -1; + if (a->family > b->family) + return 1; + + switch (a->family) { + case AF_INET: + case AF_INET6: + if (a->dst_prefixlen < b->dst_prefixlen) + return -1; + if (a->dst_prefixlen > b->dst_prefixlen) + return 1; + + if (a->tos < b->tos) + return -1; + if (a->tos > b->tos) + return 1; + + if (a->priority < b->priority) + return -1; + if (a->priority > b->priority) + return 1; + + if (a->table < b->table) + return -1; + if (a->table > b->table) + return 1; + + return memcmp(&a->dst, &b->dst, FAMILY_ADDRESS_SIZE(a->family)); + default: + /* treat any other address family as AF_UNSPEC */ + return 0; + } +} + +static const struct hash_ops route_hash_ops = { + .hash = route_hash_func, + .compare = route_compare_func +}; + +int route_get(Link *link, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, + Route **ret) { + Route route = { + .family = family, + .dst_prefixlen = dst_prefixlen, + .tos = tos, + .priority = priority, + .table = table, + }, *existing; + + assert(link); + assert(dst); + assert(ret); + + route.dst = *dst; + + existing = set_get(link->routes, &route); + if (existing) { + *ret = existing; + return 1; + } else { + existing = set_get(link->routes_foreign, &route); + if (!existing) + return -ENOENT; + } + + *ret = existing; + + return 0; +} + +static int route_add_internal(Link *link, Set **routes, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, Route **ret) { + _cleanup_route_free_ Route *route = NULL; + int r; + + assert(link); + assert(routes); + assert(dst); + + r = route_new(&route); + if (r < 0) + return r; + + route->family = family; + route->dst = *dst; + route->dst_prefixlen = dst_prefixlen; + route->tos = tos; + route->priority = priority; + route->table = table; + + r = set_ensure_allocated(routes, &route_hash_ops); + if (r < 0) + return r; + + r = set_put(*routes, route); + if (r < 0) + return r; + + route->link = link; + + if (ret) + *ret = route; + + route = NULL; + + return 0; +} + +int route_add_foreign(Link *link, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, Route **ret) { + return route_add_internal(link, &link->routes_foreign, family, dst, dst_prefixlen, tos, priority, table, ret); +} + +int route_add(Link *link, + int family, + union in_addr_union *dst, + unsigned char dst_prefixlen, + unsigned char tos, + uint32_t priority, + unsigned char table, Route **ret) { + Route *route; + int r; + + r = route_get(link, family, dst, dst_prefixlen, tos, priority, table, &route); + if (r == -ENOENT) { + /* Route does not exist, create a new one */ + r = route_add_internal(link, &link->routes, family, dst, dst_prefixlen, tos, priority, table, &route); + if (r < 0) + return r; + } else if (r == 0) { + /* Take over a foreign route */ + r = set_ensure_allocated(&link->routes, &route_hash_ops); + if (r < 0) + return r; + + r = set_put(link->routes, route); + if (r < 0) + return r; + + set_remove(link->routes_foreign, route); + } else if (r == 1) { + /* Route exists, do nothing */ + ; + } else + return r; + + *ret = route; + + return 0; +} + +int route_update(Route *route, + union in_addr_union *src, + unsigned char src_prefixlen, + union in_addr_union *gw, + union in_addr_union *prefsrc, + unsigned char scope, + unsigned char protocol) { + assert(route); + assert(src); + assert(gw); + assert(prefsrc); + + route->src = *src; + route->src_prefixlen = src_prefixlen; + route->gw = *gw; + route->prefsrc = *prefsrc; + route->scope = scope; + route->protocol = protocol; + + return 0; +} + +void route_drop(Route *route) { + assert(route); + + route_free(route); +} + +int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; int r; @@ -113,20 +349,20 @@ int route_drop(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not create RTM_DELROUTE message: %m"); - if (!in_addr_is_null(route->family, &route->in_addr)) { + if (!in_addr_is_null(route->family, &route->gw)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); } if (route->dst_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST attribute: %m"); @@ -137,9 +373,9 @@ int route_drop(Route *route, Link *link, if (route->src_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST attribute: %m"); @@ -148,11 +384,11 @@ int route_drop(Route *route, Link *link, return log_error_errno(r, "Could not set source prefix length: %m"); } - if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { + if (!in_addr_is_null(route->family, &route->prefsrc)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m"); } @@ -161,7 +397,7 @@ int route_drop(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not set scope: %m"); - r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics); + r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); @@ -178,9 +414,24 @@ int route_drop(Route *route, Link *link, return 0; } +int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) { + Route *route = userdata; + int r; + + assert(route); + + r = route_remove(route, route->link, NULL); + if (r < 0) + log_warning_errno(r, "Could not remove route: %m"); + + return 1; +} + int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback) { _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_event_source_unref_ sd_event_source *expire = NULL; + usec_t lifetime; int r; assert(link); @@ -195,20 +446,20 @@ int route_configure(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m"); - if (!in_addr_is_null(route->family, &route->in_addr)) { + if (!in_addr_is_null(route->family, &route->gw)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->in_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->in_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m"); } if (route->dst_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_DST attribute: %m"); @@ -219,9 +470,9 @@ int route_configure(Route *route, Link *link, if (route->src_prefixlen) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_SRC attribute: %m"); @@ -230,11 +481,11 @@ int route_configure(Route *route, Link *link, return log_error_errno(r, "Could not set source prefix length: %m"); } - if (!in_addr_is_null(route->family, &route->prefsrc_addr)) { + if (!in_addr_is_null(route->family, &route->prefsrc)) { if (route->family == AF_INET) - r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in); + r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in); else if (route->family == AF_INET6) - r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc_addr.in6); + r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6); if (r < 0) return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m"); } @@ -243,7 +494,7 @@ int route_configure(Route *route, Link *link, if (r < 0) return log_error_errno(r, "Could not set scope: %m"); - r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->metrics); + r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority); if (r < 0) return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m"); @@ -257,6 +508,26 @@ int route_configure(Route *route, Link *link, link_ref(link); + lifetime = route->lifetime; + + r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route); + if (r < 0) + return log_error_errno(r, "Could not add route: %m"); + + /* TODO: drop expiration handling once it can be pushed into the kernel */ + route->lifetime = lifetime; + + if (route->lifetime != USEC_INFINITY) { + r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(), + route->lifetime, 0, route_expire_handler, route); + if (r < 0) + return log_error_errno(r, "Could not arm expiration timer: %m"); + } + + sd_event_source_unref(route->expire); + route->expire = expire; + expire = NULL; + return 0; } @@ -294,13 +565,52 @@ int config_parse_gateway(const char *unit, r = in_addr_from_string_auto(rvalue, &f, &buffer); if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + n->family = f; + n->gw = buffer; + n = NULL; + + return 0; +} + +int config_parse_preferred_src(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *network = userdata; + _cleanup_route_free_ Route *n = NULL; + union in_addr_union buffer; + int r, f; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, section_line, &n); + if (r < 0) + return r; + + r = in_addr_from_string_auto(rvalue, &f, &buffer); + if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Route is invalid, ignoring assignment: %s", rvalue); + "Preferred source is invalid, ignoring assignment: %s", rvalue); return 0; } n->family = f; - n->in_addr = buffer; + n->prefsrc = buffer; n = NULL; return 0; @@ -345,14 +655,12 @@ int config_parse_destination(const char *unit, r = in_addr_from_string_auto(address, &f, &buffer); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Destination is invalid, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, r, "Destination is invalid, ignoring assignment: %s", address); return 0; } if (f != AF_INET && f != AF_INET6) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unknown address family, ignoring assignment: %s", address); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown address family, ignoring assignment: %s", address); return 0; } @@ -360,8 +668,7 @@ int config_parse_destination(const char *unit, if (e) { r = safe_atou8(e + 1, &prefixlen); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Route destination prefix length is invalid, ignoring assignment: %s", e + 1); + log_syntax(unit, LOG_ERR, filename, line, r, "Route destination prefix length is invalid, ignoring assignment: %s", e + 1); return 0; } } else { @@ -377,10 +684,10 @@ int config_parse_destination(const char *unit, n->family = f; if (streq(lvalue, "Destination")) { - n->dst_addr = buffer; + n->dst = buffer; n->dst_prefixlen = prefixlen; } else if (streq(lvalue, "Source")) { - n->src_addr = buffer; + n->src = buffer; n->src_prefixlen = prefixlen; } else assert_not_reached(lvalue); @@ -414,9 +721,9 @@ int config_parse_route_priority(const char *unit, if (r < 0) return r; - r = config_parse_unsigned(unit, filename, line, section, - section_line, lvalue, ltype, - rvalue, &n->metrics, userdata); + r = config_parse_uint32(unit, filename, line, section, + section_line, lvalue, ltype, + rvalue, &n->priority, userdata); if (r < 0) return r; @@ -456,8 +763,7 @@ int config_parse_route_scope(const char *unit, else if (streq(rvalue, "global")) n->scope = RT_SCOPE_UNIVERSE; else { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Unknown route scope: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Unknown route scope: %s", rvalue); return 0; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index d090b9c91e..d0a51838ed 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -30,31 +30,47 @@ struct Route { Network *network; unsigned section; + Link *link; + int family; unsigned char dst_prefixlen; unsigned char src_prefixlen; unsigned char scope; - uint32_t metrics; unsigned char protocol; /* RTPROT_* */ + unsigned char tos; + uint32_t priority; /* note that ip(8) calls this 'metric' */ + unsigned char table; + + union in_addr_union gw; + union in_addr_union dst; + union in_addr_union src; + union in_addr_union prefsrc; - union in_addr_union in_addr; - union in_addr_union dst_addr; - union in_addr_union src_addr; - union in_addr_union prefsrc_addr; + usec_t lifetime; + sd_event_source *expire; LIST_FIELDS(Route, routes); }; int route_new_static(Network *network, unsigned section, Route **ret); -int route_new_dynamic(Route **ret, unsigned char rtm_protocol); +int route_new(Route **ret); void route_free(Route *route); int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback); -int route_drop(Route *route, Link *link, sd_netlink_message_handler_t callback); +int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback); + +int route_get(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_add(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_add_foreign(Link *link, int family, union in_addr_union *dst, unsigned char dst_prefixlen, unsigned char tos, uint32_t priority, unsigned char table, Route **ret); +int route_update(Route *route, union in_addr_union *src, unsigned char src_prefixlen, union in_addr_union *gw, union in_addr_union *prefsrc, unsigned char scope, unsigned char protocol); +void route_drop(Route *route); + +int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata); DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free); #define _cleanup_route_free_ _cleanup_(route_freep) int config_parse_gateway(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_preferred_src(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_destination(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_route_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_route_scope(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index a41cd86239..df091393f6 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -19,10 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "conf-parser.h" - #include "networkd-util.h" +#include "parse-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" const char *address_family_boolean_to_string(AddressFamilyBoolean b) { if (b == ADDRESS_FAMILY_YES || @@ -82,7 +84,7 @@ int config_parse_address_family_boolean_with_kernel( if (streq(rvalue, "kernel")) s = _ADDRESS_FAMILY_BOOLEAN_INVALID; else { - log_syntax(unit, LOG_ERR, filename, line, s, "Failed to parse IPForwarding= option, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPForward= option, ignoring: %s", rvalue); return 0; } } @@ -133,7 +135,7 @@ int config_parse_resolve( s = resolve_support_from_string(rvalue); if (s < 0){ - log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue); return 0; } diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c index cacb4c257e..c2779ff773 100644 --- a/src/network/networkd-wait-online-link.c +++ b/src/network/networkd-wait-online-link.c @@ -20,10 +20,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - #include "sd-network.h" +#include "alloc-util.h" #include "networkd-wait-online-link.h" +#include "string-util.h" int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) { _cleanup_(link_freep) Link *l = NULL; diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c index 112d92a568..0c40ab2bb8 100644 --- a/src/network/networkd-wait-online-manager.c +++ b/src/network/networkd-wait-online-manager.c @@ -23,14 +23,13 @@ #include <linux/if.h> #include <fnmatch.h> +#include "alloc-util.h" #include "netlink-util.h" - #include "network-internal.h" #include "networkd-wait-online-link.h" #include "networkd-wait-online.h" - -#include "util.h" #include "time-util.h" +#include "util.h" bool manager_ignore_link(Manager *m, Link *link) { char **ignore; diff --git a/src/network/networkd-wait-online.c b/src/network/networkd-wait-online.c index d958b48771..3220c4b7ef 100644 --- a/src/network/networkd-wait-online.c +++ b/src/network/networkd-wait-online.c @@ -21,10 +21,10 @@ #include <getopt.h> #include "sd-daemon.h" -#include "strv.h" -#include "build.h" -#include "signal-util.h" + #include "networkd-wait-online.h" +#include "signal-util.h" +#include "strv.h" static bool arg_quiet = false; static usec_t arg_timeout = 120 * USEC_PER_SEC; @@ -79,9 +79,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'i': if (strv_extend(&arg_interfaces, optarg) < 0) diff --git a/src/network/networkd.c b/src/network/networkd.c index e6259043fa..ef394e0c04 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -20,9 +20,11 @@ ***/ #include "sd-daemon.h" -#include "capability.h" -#include "signal-util.h" + +#include "capability-util.h" #include "networkd.h" +#include "signal-util.h" +#include "user-util.h" int main(int argc, char *argv[]) { _cleanup_manager_free_ Manager *m = NULL; @@ -107,6 +109,12 @@ int main(int argc, char *argv[]) { goto out; } + r = manager_rtnl_enumerate_routes(m); + if (r < 0) { + log_error_errno(r, "Could not enumerate routes: %m"); + goto out; + } + log_info("Enumeration completed"); sd_notify(false, diff --git a/src/network/networkd.h b/src/network/networkd.h index eea57ac158..97665fac7a 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -48,7 +48,10 @@ struct Manager { struct udev_monitor *udev_monitor; sd_event_source *udev_event_source; - bool enumerating; + bool enumerating:1; + bool dirty:1; + + Set *dirty_links; char *state_file; LinkOperationalState operational_state; @@ -79,9 +82,13 @@ bool manager_should_reload(Manager *m); int manager_rtnl_enumerate_links(Manager *m); int manager_rtnl_enumerate_addresses(Manager *m); +int manager_rtnl_enumerate_routes(Manager *m); + +int manager_rtnl_process_address(sd_netlink *nl, sd_netlink_message *message, void *userdata); +int manager_rtnl_process_route(sd_netlink *nl, sd_netlink_message *message, void *userdata); int manager_send_changed(Manager *m, const char *property, ...) _sentinel_; -int manager_save(Manager *m); +void manager_dirty(Manager *m); int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found); diff --git a/src/network/test-network.c b/src/network/test-network.c index 5909cc790e..dbed3795e3 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "networkd.h" #include "network-internal.h" #include "dhcp-lease-internal.h" @@ -143,8 +144,8 @@ static void test_network_get(Manager *manager, struct udev_device *loopback) { static void test_address_equality(void) { _cleanup_address_free_ Address *a1 = NULL, *a2 = NULL; - assert_se(address_new_dynamic(&a1) >= 0); - assert_se(address_new_dynamic(&a2) >= 0); + assert_se(address_new(&a1) >= 0); + assert_se(address_new(&a2) >= 0); assert_se(address_equal(NULL, NULL)); assert_se(!address_equal(a1, NULL)); @@ -158,17 +159,18 @@ static void test_address_equality(void) { assert_se(address_equal(a1, a2)); assert_se(inet_pton(AF_INET, "192.168.3.9", &a1->in_addr.in)); - assert_se(address_equal(a1, a2)); + assert_se(!address_equal(a1, a2)); assert_se(inet_pton(AF_INET, "192.168.3.9", &a2->in_addr.in)); assert_se(address_equal(a1, a2)); + assert_se(inet_pton(AF_INET, "192.168.3.10", &a1->in_addr_peer.in)); + assert_se(address_equal(a1, a2)); + assert_se(inet_pton(AF_INET, "192.168.3.11", &a2->in_addr_peer.in)); + assert_se(address_equal(a1, a2)); a1->prefixlen = 10; assert_se(!address_equal(a1, a2)); a2->prefixlen = 10; assert_se(address_equal(a1, a2)); - assert_se(inet_pton(AF_INET, "192.168.3.10", &a2->in_addr.in)); - assert_se(address_equal(a1, a2)); - a1->family = AF_INET6; assert_se(!address_equal(a1, a2)); diff --git a/src/notify/notify.c b/src/notify/notify.c index 7d53cb6d75..b144554702 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -27,10 +27,12 @@ #include "sd-daemon.h" -#include "build.h" +#include "alloc-util.h" #include "env-util.h" #include "formats-util.h" #include "log.h" +#include "parse-util.h" +#include "string-util.h" #include "strv.h" #include "util.h" @@ -85,9 +87,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_READY: arg_ready = true; diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index c0e9ccd7a4..270bcf010f 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -21,13 +21,15 @@ #include <sys/mount.h> -#include "util.h" -#include "strv.h" -#include "mkdir.h" -#include "fileio.h" +#include "alloc-util.h" #include "cgroup-util.h" - +#include "fd-util.h" +#include "fileio.h" +#include "mkdir.h" #include "nspawn-cgroup.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" int chown_cgroup(pid_t pid, uid_t uid_shift) { _cleanup_free_ char *path = NULL, *fs = NULL; diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c index 9e63d88b69..38245434da 100644 --- a/src/nspawn/nspawn-expose-ports.c +++ b/src/nspawn/nspawn-expose-ports.c @@ -21,13 +21,17 @@ #include "sd-netlink.h" -#include "util.h" -#include "in-addr-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "firewall-util.h" +#include "in-addr-util.h" #include "local-addresses.h" #include "netlink-util.h" - #include "nspawn-expose-ports.h" +#include "parse-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" int expose_port_parse(ExposePort **l, const char *s) { @@ -194,7 +198,7 @@ int expose_port_send_rtnl(int send_fd) { /* Store away the fd in the socket, so that it stays open as * long as we run the child */ - r = send_one_fd(send_fd, fd); + r = send_one_fd(send_fd, fd, 0); if (r < 0) return log_error_errno(r, "Failed to send netlink fd: %m"); @@ -214,7 +218,7 @@ int expose_port_watch_rtnl( assert(recv_fd >= 0); assert(ret); - fd = receive_one_fd(recv_fd); + fd = receive_one_fd(recv_fd, 0); if (fd < 0) return log_error_errno(fd, "Failed to recv netlink fd: %m"); diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 2bca39f45d..c8e627ac78 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -20,17 +20,25 @@ ***/ #include <sys/mount.h> +#include <linux/magic.h> -#include "util.h" -#include "rm-rf.h" -#include "strv.h" -#include "path-util.h" -#include "mkdir.h" -#include "label.h" -#include "set.h" +#include "alloc-util.h" #include "cgroup-util.h" - +#include "escape.h" +#include "fs-util.h" +#include "label.h" +#include "mkdir.h" +#include "mount-util.h" #include "nspawn-mount.h" +#include "parse-util.h" +#include "path-util.h" +#include "rm-rf.h" +#include "set.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" CustomMount* custom_mount_add(CustomMount **l, unsigned *n, CustomMountType t) { CustomMount *c, *ret; @@ -216,8 +224,67 @@ static int tmpfs_patch_options( return !!buf; } +int mount_sysfs(const char *dest) { + const char *full, *top, *x; + int r; + + top = prefix_roota(dest, "/sys"); + r = path_check_fstype(top, SYSFS_MAGIC); + if (r < 0) + return log_error_errno(r, "Failed to determine filesystem type of %s: %m", top); + /* /sys might already be mounted as sysfs by the outer child in the + * !netns case. In this case, it's all good. Don't touch it because we + * don't have the right to do so, see https://github.com/systemd/systemd/issues/1555. + */ + if (r > 0) + return 0; + + full = prefix_roota(top, "/full"); + + (void) mkdir(full, 0755); + + if (mount("sysfs", full, "sysfs", MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0) + return log_error_errno(errno, "Failed to mount sysfs to %s: %m", full); + + FOREACH_STRING(x, "block", "bus", "class", "dev", "devices", "kernel") { + _cleanup_free_ char *from = NULL, *to = NULL; + + from = prefix_root(full, x); + if (!from) + return log_oom(); + + to = prefix_root(top, x); + if (!to) + return log_oom(); + + (void) mkdir(to, 0755); + + if (mount(from, to, NULL, MS_BIND, NULL) < 0) + return log_error_errno(errno, "Failed to mount /sys/%s into place: %m", x); + + if (mount(NULL, to, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL) < 0) + return log_error_errno(errno, "Failed to mount /sys/%s read-only: %m", x); + } + + if (umount(full) < 0) + return log_error_errno(errno, "Failed to unmount %s: %m", full); + + if (rmdir(full) < 0) + return log_error_errno(errno, "Failed to remove %s: %m", full); + + x = prefix_roota(top, "/fs/kdbus"); + (void) mkdir(x, 0755); + + if (mount(NULL, top, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, NULL) < 0) + return log_error_errno(errno, "Failed to make %s read-only: %m", top); + + return 0; +} + int mount_all(const char *dest, - bool userns, uid_t uid_shift, uid_t uid_range, + bool use_userns, bool in_userns, + bool use_netns, + uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context) { typedef struct MountPoint { @@ -227,21 +294,23 @@ int mount_all(const char *dest, const char *options; unsigned long flags; bool fatal; - bool userns; + bool in_userns; + bool use_netns; } MountPoint; static const MountPoint mount_table[] = { - { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true }, - { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true }, /* Bind mount first */ - { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true }, /* Then, make it r/o */ - { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false }, - { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false }, - { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false }, - { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false }, - { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false }, + { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true, false }, + { "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true, false }, /* Bind mount first */ + { NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true, false }, /* Then, make it r/o */ + { "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, true }, + { "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, false }, + { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false }, + { "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false, false }, #ifdef HAVE_SELINUX - { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false }, /* Bind mount first */ - { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false }, /* Then, make it r/o */ + { "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false, false }, /* Bind mount first */ + { NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false, false }, /* Then, make it r/o */ #endif }; @@ -252,7 +321,10 @@ int mount_all(const char *dest, _cleanup_free_ char *where = NULL, *options = NULL; const char *o; - if (userns != mount_table[k].userns) + if (in_userns != mount_table[k].in_userns) + continue; + + if (!use_netns && mount_table[k].use_netns) continue; where = prefix_root(dest, mount_table[k].where); @@ -278,7 +350,7 @@ int mount_all(const char *dest, o = mount_table[k].options; if (streq_ptr(mount_table[k].type, "tmpfs")) { - r = tmpfs_patch_options(o, userns, uid_shift, uid_range, selinux_apifs_context, &options); + r = tmpfs_patch_options(o, use_userns, uid_shift, uid_range, selinux_apifs_context, &options); if (r < 0) return log_oom(); if (r > 0) @@ -369,8 +441,7 @@ static int mount_bind(const char *dest, CustomMount *m) { if (r < 0) return log_error_errno(r, "Failed to make parents of %s: %m", where); } else { - log_error_errno(errno, "Failed to stat %s: %m", where); - return -errno; + return log_error_errno(errno, "Failed to stat %s: %m", where); } /* Create the mount point. Any non-directory file can be @@ -534,7 +605,7 @@ static int mount_legacy_cgroup_hierarchy(const char *dest, const char *controlle char *to; int r; - to = strjoina(dest, "/sys/fs/cgroup/", hierarchy); + to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy); r = path_is_mount_point(to, 0); if (r < 0 && r != -ENOENT) @@ -569,6 +640,8 @@ static int mount_legacy_cgroups( cgroup_root = prefix_roota(dest, "/sys/fs/cgroup"); + (void) mkdir_p(cgroup_root, 0755); + /* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */ r = path_is_mount_point(cgroup_root, AT_SYMLINK_FOLLOW); if (r < 0) @@ -661,13 +734,15 @@ static int mount_unified_cgroups(const char *dest) { assert(dest); - p = strjoina(dest, "/sys/fs/cgroup"); + p = prefix_roota(dest, "/sys/fs/cgroup"); + + (void) mkdir_p(p, 0755); r = path_is_mount_point(p, AT_SYMLINK_FOLLOW); if (r < 0) return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p); if (r > 0) { - p = strjoina(dest, "/sys/fs/cgroup/cgroup.procs"); + p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs"); if (access(p, F_OK) >= 0) return 0; if (errno != ENOENT) diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h index 5abd44cc4b..bdab23bcca 100644 --- a/src/nspawn/nspawn-mount.h +++ b/src/nspawn/nspawn-mount.h @@ -57,7 +57,8 @@ int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s); int custom_mount_compare(const void *a, const void *b); -int mount_all(const char *dest, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); +int mount_all(const char *dest, bool use_userns, bool in_userns, bool use_netns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); +int mount_sysfs(const char *dest); int mount_cgroups(const char *dest, bool unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context); int mount_systemd_cgroup_writable(const char *dest, bool unified_requested); diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 74abe5379a..29384b60b2 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -22,16 +22,17 @@ #include <linux/veth.h> #include <net/if.h> +#include "libudev.h" #include "sd-id128.h" #include "sd-netlink.h" -#include "libudev.h" -#include "util.h" +#include "alloc-util.h" #include "ether-addr-util.h" -#include "siphash24.h" #include "netlink-util.h" +#include "siphash24.h" +#include "string-util.h" #include "udev-util.h" - +#include "util.h" #include "nspawn-network.h" #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1) diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index b2776a61c2..374f958c20 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -21,12 +21,12 @@ #include "sd-bus.h" -#include "util.h" -#include "strv.h" -#include "bus-util.h" #include "bus-error.h" - +#include "bus-util.h" #include "nspawn-register.h" +#include "stat-util.h" +#include "strv.h" +#include "util.h" int register_machine( const char *machine_name, @@ -39,7 +39,8 @@ int register_machine( unsigned n_mounts, int kill_signal, char **properties, - bool keep_unit) { + bool keep_unit, + const char *service) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; @@ -61,7 +62,7 @@ int register_machine( "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), - "nspawn", + service, "container", (uint32_t) pid, strempty(directory), @@ -86,7 +87,7 @@ int register_machine( "sayssusai", machine_name, SD_BUS_MESSAGE_APPEND_ID128(uuid), - "nspawn", + service, "container", (uint32_t) pid, strempty(directory), diff --git a/src/nspawn/nspawn-register.h b/src/nspawn/nspawn-register.h index b27841ff59..d3bfd84e5e 100644 --- a/src/nspawn/nspawn-register.h +++ b/src/nspawn/nspawn-register.h @@ -27,5 +27,5 @@ #include "nspawn-mount.h" -int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit); +int register_machine(const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit, const char *service); int terminate_machine(pid_t pid); diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 419f5d1c40..6885d0641e 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -19,12 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "conf-parser.h" -#include "strv.h" +#include "alloc-util.h" #include "cap-list.h" - +#include "conf-parser.h" #include "nspawn-settings.h" +#include "process-util.h" +#include "strv.h" +#include "util.h" int settings_load(FILE *f, const char *path, Settings **ret) { _cleanup_(settings_freep) Settings *s = NULL; @@ -85,6 +86,26 @@ Settings* settings_free(Settings *s) { return NULL; } +bool settings_private_network(Settings *s) { + assert(s); + + return + s->private_network > 0 || + s->network_veth > 0 || + s->network_bridge || + s->network_interfaces || + s->network_macvlan || + s->network_ipvlan; +} + +bool settings_network_veth(Settings *s) { + assert(s); + + return + s->network_veth > 0 || + s->network_bridge; +} + DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode"); int config_parse_expose_port( @@ -152,7 +173,7 @@ int config_parse_capability( cap = capability_from_name(word); if (cap < 0) { - log_syntax(unit, LOG_ERR, filename, line, cap, "Failed to parse capability, ignoring: %s", word); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability, ignoring: %s", word); continue; } diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 4cec40c1b7..16e8c54508 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -75,6 +75,9 @@ typedef struct Settings { int settings_load(FILE *f, const char *path, Settings **ret); Settings* settings_free(Settings *s); +bool settings_network_veth(Settings *s); +bool settings_private_network(Settings *s); + DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free); const struct ConfigPerfItem* nspawn_gperf_lookup(const char *key, unsigned length); diff --git a/src/nspawn/nspawn-setuid.c b/src/nspawn/nspawn-setuid.c index eda7f62900..aa6a16309c 100644 --- a/src/nspawn/nspawn-setuid.c +++ b/src/nspawn/nspawn-setuid.c @@ -19,16 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <grp.h> #include <sys/types.h> #include <unistd.h> -#include <grp.h> -#include "util.h" -#include "signal-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "mkdir.h" -#include "process-util.h" - #include "nspawn-setuid.h" +#include "process-util.h" +#include "signal-util.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" static int spawn_getent(const char *database, const char *key, pid_t *rpid) { int pipe_fds[2]; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 7451c2bf64..4c48681f17 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -46,21 +46,23 @@ #include "sd-daemon.h" #include "sd-id128.h" +#include "alloc-util.h" #include "barrier.h" #include "base-filesystem.h" #include "blkid-util.h" #include "btrfs-util.h" -#include "build.h" #include "cap-list.h" -#include "capability.h" +#include "capability-util.h" #include "cgroup-util.h" #include "copy.h" #include "dev-setup.h" #include "env-util.h" #include "event-util.h" +#include "fd-util.h" #include "fdset.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" #include "gpt.h" #include "hostname-util.h" #include "log.h" @@ -69,7 +71,16 @@ #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" #include "netlink-util.h" +#include "nspawn-cgroup.h" +#include "nspawn-expose-ports.h" +#include "nspawn-mount.h" +#include "nspawn-network.h" +#include "nspawn-register.h" +#include "nspawn-settings.h" +#include "nspawn-setuid.h" +#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "ptyfwd.h" @@ -79,19 +90,17 @@ #include "seccomp-util.h" #endif #include "signal-util.h" +#include "socket-util.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-util.h" #include "strv.h" #include "terminal-util.h" #include "udev-util.h" +#include "umask-util.h" +#include "user-util.h" #include "util.h" -#include "nspawn-settings.h" -#include "nspawn-mount.h" -#include "nspawn-network.h" -#include "nspawn-expose-ports.h" -#include "nspawn-cgroup.h" -#include "nspawn-register.h" -#include "nspawn-setuid.h" - typedef enum ContainerStatus { CONTAINER_TERMINATED, CONTAINER_REBOOTED @@ -169,6 +178,7 @@ static bool arg_unified_cgroup_hierarchy = false; static SettingsMask arg_settings_mask = 0; static int arg_settings_trusted = -1; static char **arg_parameters = NULL; +static const char *arg_container_service_name = "systemd-nspawn"; static void help(void) { printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n" @@ -200,10 +210,10 @@ static void help(void) { " --network-ipvlan=INTERFACE\n" " Create a ipvlan network interface based on an\n" " existing network interface to the container\n" - " -n --network-veth Add a virtual ethernet connection between host\n" + " -n --network-veth Add a virtual Ethernet connection between host\n" " and container\n" " --network-bridge=INTERFACE\n" - " Add a virtual ethernet connection between host\n" + " Add a virtual Ethernet connection between host\n" " and container and add it to an existing bridge on\n" " the host\n" " -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n" @@ -277,27 +287,6 @@ static int custom_mounts_prepare(void) { return 0; } -static int set_sanitized_path(char **b, const char *path) { - char *p; - - assert(b); - assert(path); - - p = canonicalize_file_name(path); - if (!p) { - if (errno != ENOENT) - return -errno; - - p = path_make_absolute_cwd(path); - if (!p) - return -ENOMEM; - } - - free(*b); - *b = path_kill_slashes(p); - return 0; -} - static int detect_unified_cgroup_hierarchy(void) { const char *e; int r; @@ -399,6 +388,7 @@ static int parse_argv(int argc, char *argv[]) { }; int c, r; + const char *p, *e; uint64_t plus = 0, minus = 0; bool mask_all_settings = false, mask_no_settings = false; @@ -414,29 +404,24 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'D': - r = set_sanitized_path(&arg_directory, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_directory); if (r < 0) - return log_error_errno(r, "Invalid root directory: %m"); - + return r; break; case ARG_TEMPLATE: - r = set_sanitized_path(&arg_template, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_template); if (r < 0) - return log_error_errno(r, "Invalid template directory: %m"); - + return r; break; case 'i': - r = set_sanitized_path(&arg_image, optarg); + r = parse_path_argument_and_warn(optarg, false, &arg_image); if (r < 0) - return log_error_errno(r, "Invalid image path: %m"); - + return r; break; case 'x': @@ -541,15 +526,16 @@ static int parse_argv(int argc, char *argv[]) { case ARG_CAPABILITY: case ARG_DROP_CAPABILITY: { - const char *state, *word; - size_t length; + p = optarg; + for(;;) { + _cleanup_free_ char *t = NULL; - FOREACH_WORD_SEPARATOR(word, length, optarg, ",", state) { - _cleanup_free_ char *t; + r = extract_first_word(&p, &t, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse capability %s.", t); - t = strndup(word, length); - if (!t) - return log_oom(); + if (r == 0) + break; if (streq(t, "all")) { if (c == ARG_CAPABILITY) @@ -924,6 +910,10 @@ static int parse_argv(int argc, char *argv[]) { if (r < 0) return r; + e = getenv("SYSTEMD_NSPAWN_CONTAINER_SERVICE"); + if (e) + arg_container_service_name = e; + return 1; } @@ -1192,6 +1182,7 @@ static int copy_devnodes(const char *dest) { static int setup_pts(const char *dest) { _cleanup_free_ char *options = NULL; const char *p; + int r; #ifdef HAVE_SELINUX if (arg_selinux_apifs_context) @@ -1214,20 +1205,23 @@ static int setup_pts(const char *dest) { return log_error_errno(errno, "Failed to create /dev/pts: %m"); if (mount("devpts", p, "devpts", MS_NOSUID|MS_NOEXEC, options) < 0) return log_error_errno(errno, "Failed to mount /dev/pts: %m"); - if (userns_lchown(p, 0, 0) < 0) - return log_error_errno(errno, "Failed to chown /dev/pts: %m"); + r = userns_lchown(p, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to chown /dev/pts: %m"); /* Create /dev/ptmx symlink */ p = prefix_roota(dest, "/dev/ptmx"); if (symlink("pts/ptmx", p) < 0) return log_error_errno(errno, "Failed to create /dev/ptmx symlink: %m"); - if (userns_lchown(p, 0, 0) < 0) - return log_error_errno(errno, "Failed to chown /dev/ptmx: %m"); + r = userns_lchown(p, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to chown /dev/ptmx: %m"); /* And fix /dev/pts/ptmx ownership */ p = prefix_roota(dest, "/dev/pts/ptmx"); - if (userns_lchown(p, 0, 0) < 0) - return log_error_errno(errno, "Failed to chown /dev/pts/ptmx: %m"); + r = userns_lchown(p, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to chown /dev/pts/ptmx: %m"); return 0; } @@ -1291,7 +1285,7 @@ static int setup_kmsg(const char *dest, int kmsg_socket) { /* Store away the fd in the socket, so that it stays open as * long as we run the child */ - r = send_one_fd(kmsg_socket, fd); + r = send_one_fd(kmsg_socket, fd, 0); safe_close(fd); if (r < 0) @@ -1409,7 +1403,7 @@ static int setup_journal(const char *directory) { r = userns_mkdir(directory, p, 0755, 0, 0); if (r < 0) - log_warning_errno(errno, "Failed to create directory %s: %m", q); + log_warning_errno(r, "Failed to create directory %s: %m", q); return 0; } @@ -1423,15 +1417,11 @@ static int setup_journal(const char *directory) { if (errno == ENOTDIR) { log_error("%s already exists and is neither a symlink nor a directory", p); return r; - } else { - log_error_errno(errno, "Failed to remove %s: %m", p); - return -errno; - } + } else + return log_error_errno(errno, "Failed to remove %s: %m", p); } - } else if (r != -ENOENT) { - log_error_errno(errno, "readlink(%s) failed: %m", p); - return r; - } + } else if (r != -ENOENT) + return log_error_errno(r, "readlink(%s) failed: %m", p); if (arg_link_journal == LINK_GUEST) { @@ -1439,15 +1429,13 @@ static int setup_journal(const char *directory) { if (arg_link_journal_try) { log_debug_errno(errno, "Failed to symlink %s to %s, skipping journal setup: %m", q, p); return 0; - } else { - log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p); - return -errno; - } + } else + return log_error_errno(errno, "Failed to symlink %s to %s: %m", q, p); } r = userns_mkdir(directory, p, 0755, 0, 0); if (r < 0) - log_warning_errno(errno, "Failed to create directory %s: %m", q); + log_warning_errno(r, "Failed to create directory %s: %m", q); return 0; } @@ -1459,10 +1447,8 @@ static int setup_journal(const char *directory) { if (arg_link_journal_try) { log_debug_errno(errno, "Failed to create %s, skipping journal setup: %m", p); return 0; - } else { - log_error_errno(errno, "Failed to create %s: %m", p); - return r; - } + } else + return log_error_errno(errno, "Failed to create %s: %m", p); } } else if (access(p, F_OK) < 0) @@ -1472,10 +1458,8 @@ static int setup_journal(const char *directory) { log_warning("%s is not empty, proceeding anyway.", q); r = userns_mkdir(directory, p, 0755, 0, 0); - if (r < 0) { - log_error_errno(errno, "Failed to create %s: %m", q); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to create %s: %m", q); if (mount(p, q, NULL, MS_BIND, NULL) < 0) return log_error_errno(errno, "Failed to bind mount journal from host into guest: %m"); @@ -1616,20 +1600,24 @@ finish: static int setup_propagate(const char *root) { const char *p, *q; + int r; (void) mkdir_p("/run/systemd/nspawn/", 0755); (void) mkdir_p("/run/systemd/nspawn/propagate", 0600); p = strjoina("/run/systemd/nspawn/propagate/", arg_machine); (void) mkdir_p(p, 0600); - if (userns_mkdir(root, "/run/systemd", 0755, 0, 0) < 0) - return log_error_errno(errno, "Failed to create /run/systemd: %m"); + r = userns_mkdir(root, "/run/systemd", 0755, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd: %m"); - if (userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0) < 0) - return log_error_errno(errno, "Failed to create /run/systemd/nspawn: %m"); + r = userns_mkdir(root, "/run/systemd/nspawn", 0755, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd/nspawn: %m"); - if (userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0) < 0) - return log_error_errno(errno, "Failed to create /run/systemd/nspawn/incoming: %m"); + r = userns_mkdir(root, "/run/systemd/nspawn/incoming", 0600, 0, 0); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd/nspawn/incoming: %m"); q = prefix_roota(root, "/run/systemd/nspawn/incoming"); if (mount(p, q, NULL, MS_BIND, NULL) < 0) @@ -1679,7 +1667,7 @@ static int setup_image(char **device_path, int *loop_nr) { } if (!S_ISREG(st.st_mode)) { - log_error_errno(errno, "%s is not a regular file or block device: %m", arg_image); + log_error("%s is not a regular file or block device.", arg_image); return -EINVAL; } @@ -1771,8 +1759,7 @@ static int dissect_image( if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to set device on blkid probe: %m"); - return -errno; + return log_error_errno(errno, "Failed to set device on blkid probe: %m"); } blkid_probe_enable_partitions(b, 1); @@ -1788,8 +1775,7 @@ static int dissect_image( } else if (r != 0) { if (errno == 0) errno = EIO; - log_error_errno(errno, "Failed to probe: %m"); - return -errno; + return log_error_errno(errno, "Failed to probe: %m"); } (void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); @@ -1912,8 +1898,7 @@ static int dissect_image( if (!errno) errno = ENOMEM; - log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image); - return -errno; + return log_error_errno(errno, "Failed to get partition device of %s: %m", arg_image); } qn = udev_device_get_devnum(q); @@ -2120,8 +2105,7 @@ static int mount_device(const char *what, const char *where, const char *directo if (!b) { if (errno == 0) return log_oom(); - log_error_errno(errno, "Failed to allocate prober for %s: %m", what); - return -errno; + return log_error_errno(errno, "Failed to allocate prober for %s: %m", what); } blkid_probe_enable_superblocks(b, 1); @@ -2135,8 +2119,7 @@ static int mount_device(const char *what, const char *where, const char *directo } else if (r != 0) { if (errno == 0) errno = EIO; - log_error_errno(errno, "Failed to probe %s: %m", what); - return -errno; + return log_error_errno(errno, "Failed to probe %s: %m", what); } errno = 0; @@ -2282,8 +2265,6 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { return r; } -static void nop_handler(int sig) {} - static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { pid_t pid; @@ -2327,9 +2308,9 @@ static int determine_names(void) { } if (i->type == IMAGE_RAW) - r = set_sanitized_path(&arg_image, i->path); + r = free_and_strdup(&arg_image, i->path); else - r = set_sanitized_path(&arg_directory, i->path); + r = free_and_strdup(&arg_directory, i->path); if (r < 0) return log_error_errno(r, "Invalid image directory: %m"); @@ -2421,10 +2402,10 @@ static int inner_child( FDSet *fds) { _cleanup_free_ char *home = NULL; - unsigned n_env = 2; + unsigned n_env = 1; const char *envp[] = { "PATH=" DEFAULT_PATH_SPLIT_USR, - "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */ + NULL, /* container */ NULL, /* TERM */ NULL, /* HOME */ NULL, /* USER */ @@ -2455,7 +2436,11 @@ static int inner_child( } } - r = mount_all(NULL, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context); + if (r < 0) + return r; + + r = mount_sysfs(NULL); if (r < 0) return r; @@ -2498,8 +2483,9 @@ static int inner_child( rtnl_socket = safe_close(rtnl_socket); } - if (drop_capabilities() < 0) - return log_error_errno(errno, "drop_capabilities() failed: %m"); + r = drop_capabilities(); + if (r < 0) + return log_error_errno(r, "drop_capabilities() failed: %m"); setup_hostname(); @@ -2521,6 +2507,9 @@ static int inner_child( if (r < 0) return r; + /* LXC sets container=lxc, so follow the scheme here */ + envp[n_env++] = strjoina("container=", arg_container_service_name); + envp[n_env] = strv_find_prefix(environ, "TERM="); if (envp[n_env]) n_env ++; @@ -2599,8 +2588,9 @@ static int inner_child( execle("/bin/sh", "-sh", NULL, env_use); } + r = -errno; (void) log_open(); - return log_error_errno(errno, "execv() failed: %m"); + return log_error_errno(r, "execv() failed: %m"); } static int outer_child( @@ -2706,7 +2696,7 @@ static int outer_child( return log_error_errno(r, "Failed to make tree read-only: %m"); } - r = mount_all(directory, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); + r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context); if (r < 0) return r; @@ -2841,7 +2831,7 @@ static int load_settings(void) { p = j; j = NULL; - /* By default we trust configuration from /etc and /run */ + /* By default, we trust configuration from /etc and /run */ if (arg_settings_trusted < 0) arg_settings_trusted = true; @@ -2871,7 +2861,7 @@ static int load_settings(void) { if (!f && errno != ENOENT) return log_error_errno(errno, "Failed to open %s: %m", p); - /* By default we do not trust configuration from /var/lib/machines */ + /* By default, we do not trust configuration from /var/lib/machines */ if (arg_settings_trusted < 0) arg_settings_trusted = false; } @@ -2913,11 +2903,17 @@ static int load_settings(void) { } if ((arg_settings_mask & SETTING_CAPABILITY) == 0) { + uint64_t plus; - if (!arg_settings_trusted && settings->capability != 0) - log_warning("Ignoring Capability= setting, file %s is not trusted.", p); - else - arg_retain |= settings->capability; + plus = settings->capability; + if (settings_private_network(settings)) + plus |= (1ULL << CAP_NET_ADMIN); + + if (!arg_settings_trusted && plus != 0) { + if (settings->capability != 0) + log_warning("Ignoring Capability= setting, file %s is not trusted.", p); + } else + arg_retain |= plus; arg_retain &= ~settings->drop_capability; } @@ -2973,6 +2969,9 @@ static int load_settings(void) { if (!arg_settings_trusted) log_warning("Ignoring network settings, file %s is not trusted.", p); else { + arg_network_veth = settings_private_network(settings); + arg_private_network = settings_private_network(settings); + strv_free(arg_network_interfaces); arg_network_interfaces = settings->network_interfaces; settings->network_interfaces = NULL; @@ -2988,10 +2987,6 @@ static int load_settings(void) { free(arg_network_bridge); arg_network_bridge = settings->network_bridge; settings->network_bridge = NULL; - - arg_network_veth = settings->network_veth > 0 || settings->network_bridge; - - arg_private_network = true; /* all these settings imply private networking */ } } @@ -3097,7 +3092,7 @@ int main(int argc, char *argv[]) { goto finish; } - r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot(arg_directory, np, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); if (r < 0) { log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory); goto finish; @@ -3121,7 +3116,7 @@ int main(int argc, char *argv[]) { } if (arg_template) { - r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE); + r = btrfs_subvol_snapshot(arg_template, arg_directory, (arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) | BTRFS_SNAPSHOT_FALLBACK_COPY | BTRFS_SNAPSHOT_RECURSIVE | BTRFS_SNAPSHOT_QUOTA); if (r == -EEXIST) { if (!arg_quiet) log_info("Directory %s already exists, not populating from template %s.", arg_directory, arg_template); @@ -3144,10 +3139,9 @@ int main(int argc, char *argv[]) { } else { const char *p; - p = strjoina(arg_directory, - argc > optind && path_is_absolute(argv[optind]) ? argv[optind] : "/usr/bin/"); - if (access(p, F_OK) < 0) { - log_error("Directory %s lacks the binary to execute or doesn't look like a binary tree. Refusing.", arg_directory); + p = strjoina(arg_directory, "/usr/"); + if (laccess(p, F_OK) < 0) { + log_error("Directory %s doesn't look like it has an OS tree. Refusing.", arg_directory); r = -EINVAL; goto finish; } @@ -3236,12 +3230,11 @@ int main(int argc, char *argv[]) { } for (;;) { - _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, - uid_shift_socket_pair[2] = { -1, -1 }; + _cleanup_close_pair_ int kmsg_socket_pair[2] = { -1, -1 }, rtnl_socket_pair[2] = { -1, -1 }, pid_socket_pair[2] = { -1, -1 }, uid_shift_socket_pair[2] = { -1, -1 }; ContainerStatus container_status; _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; static const struct sigaction sa = { - .sa_handler = nop_handler, + .sa_handler = nop_signal_handler, .sa_flags = SA_NOCLDSTOP, }; int ifi = 0; @@ -3338,8 +3331,7 @@ int main(int argc, char *argv[]) { barrier_set_role(&barrier, BARRIER_PARENT); - fdset_free(fds); - fds = NULL; + fds = fdset_free(fds); kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]); rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]); @@ -3437,7 +3429,8 @@ int main(int argc, char *argv[]) { arg_custom_mounts, arg_n_custom_mounts, arg_kill_signal, arg_property, - arg_keep_unit); + arg_keep_unit, + arg_container_service_name); if (r < 0) goto finish; } @@ -3514,7 +3507,7 @@ int main(int argc, char *argv[]) { rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); - r = pty_forward_new(event, master, true, !interactive, &forward); + r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_VHANGUP | (interactive ? 0 : PTY_FORWARD_READ_ONLY), &forward); if (r < 0) { log_error_errno(r, "Failed to create PTY forwarder: %m"); goto finish; @@ -3593,7 +3586,7 @@ finish: if (remove_subvol && arg_directory) { int k; - k = btrfs_subvol_remove(arg_directory, true); + k = btrfs_subvol_remove(arg_directory, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA); if (k < 0) log_warning_errno(k, "Cannot remove subvolume '%s', ignoring: %m", arg_directory); } diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index 0dca891447..ee10b105ea 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -19,17 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <nss.h> -#include <netdb.h> #include <errno.h> -#include <string.h> #include <net/if.h> +#include <netdb.h> +#include <nss.h> #include <stdlib.h> +#include <string.h> +#include "alloc-util.h" +#include "hostname-util.h" #include "local-addresses.h" #include "macro.h" #include "nss-util.h" -#include "hostname-util.h" +#include "string-util.h" #include "util.h" /* We use 127.0.0.2 as IPv4 address. This has the advantage over diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 604130ed25..969fa9619e 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -19,18 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <nss.h> #include <netdb.h> +#include <nss.h> #include "sd-bus.h" #include "sd-login.h" -#include "macro.h" -#include "util.h" -#include "nss-util.h" -#include "bus-util.h" + +#include "alloc-util.h" #include "bus-common-errors.h" -#include "in-addr-util.h" +#include "bus-util.h" #include "hostname-util.h" +#include "in-addr-util.h" +#include "macro.h" +#include "nss-util.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); NSS_GETPW_PROTOTYPES(mymachines); diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index ef5eb7b4cf..ed59a71e3d 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -19,20 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <nss.h> -#include <netdb.h> +#include <dlfcn.h> #include <errno.h> -#include <string.h> +#include <netdb.h> +#include <nss.h> #include <stdlib.h> -#include <dlfcn.h> +#include <string.h> #include "sd-bus.h" -#include "bus-util.h" + #include "bus-common-errors.h" +#include "bus-util.h" +#include "in-addr-util.h" #include "macro.h" #include "nss-util.h" +#include "string-util.h" #include "util.h" -#include "in-addr-util.h" NSS_GETHOSTBYNAME_PROTOTYPES(resolve); NSS_GETHOSTBYADDR_PROTOTYPES(resolve); diff --git a/src/path/path.c b/src/path/path.c index f7736a4202..0ece72f6fe 100644 --- a/src/path/path.c +++ b/src/path/path.c @@ -19,16 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <getopt.h> #include <errno.h> +#include <getopt.h> +#include <stdio.h> #include <stdlib.h> #include "sd-path.h" -#include "build.h" + +#include "alloc-util.h" +#include "log.h" #include "macro.h" +#include "string-util.h" #include "util.h" -#include "log.h" static const char *arg_suffix = NULL; @@ -155,9 +157,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_SUFFIX: arg_suffix = optarg; diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index cf6a239402..dc2911e4e8 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -19,15 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdbool.h> #include <errno.h> -#include <unistd.h> +#include <stdbool.h> +#include <stdio.h> #include <sys/prctl.h> +#include <unistd.h> -#include "util.h" #include "process-util.h" #include "signal-util.h" +#include "string-util.h" +#include "util.h" +#include "proc-cmdline.h" static bool arg_skip = false; static bool arg_force = false; diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c index f4778fc16a..d857ade36a 100644 --- a/src/random-seed/random-seed.c +++ b/src/random-seed/random-seed.c @@ -19,15 +19,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <fcntl.h> #include <errno.h> +#include <fcntl.h> #include <string.h> #include <sys/stat.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "log.h" -#include "util.h" #include "mkdir.h" +#include "string-util.h" +#include "util.h" #define POOL_SIZE_MIN 512 diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c index d4e6ba4bf9..6ecadbf3e5 100644 --- a/src/rc-local-generator/rc-local-generator.c +++ b/src/rc-local-generator/rc-local-generator.c @@ -24,9 +24,11 @@ #include <stdio.h> #include <unistd.h> +#include "alloc-util.h" #include "log.h" -#include "util.h" #include "mkdir.h" +#include "string-util.h" +#include "util.h" #ifndef RC_LOCAL_SCRIPT_PATH_START #define RC_LOCAL_SCRIPT_PATH_START "/etc/rc.d/rc.local" @@ -60,8 +62,7 @@ static int add_symlink(const char *service, const char *where) { if (errno == EEXIST) return 0; - log_error_errno(errno, "Failed to create symlink %s: %m", to); - return -errno; + return log_error_errno(errno, "Failed to create symlink %s: %m", to); } return 1; diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index f904e48e75..57f99c9ef0 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -26,12 +26,13 @@ #include <sys/wait.h> #include <mntent.h> +#include "exit-status.h" #include "log.h" -#include "util.h" +#include "mount-setup.h" +#include "mount-util.h" #include "path-util.h" #include "signal-util.h" -#include "mount-setup.h" -#include "exit-status.h" +#include "util.h" /* Goes through /etc/fstab and remounts all API file systems, applying * options that are in /etc/fstab that systemd might not have diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c index d0d61b98ed..166ab470ed 100644 --- a/src/reply-password/reply-password.c +++ b/src/reply-password/reply-password.c @@ -19,14 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <string.h> #include <errno.h> -#include <sys/un.h> #include <stddef.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/un.h> +#include "fd-util.h" #include "log.h" #include "macro.h" +#include "string-util.h" #include "util.h" static int send_on_socket(int fd, const char *socket_name, const void *packet, size_t size) { @@ -50,9 +52,10 @@ static int send_on_socket(int fd, const char *socket_name, const void *packet, s } int main(int argc, char *argv[]) { - int fd = -1, r = EXIT_FAILURE; + _cleanup_close_ int fd = -1; char packet[LINE_MAX]; size_t length; + int r; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); @@ -60,14 +63,14 @@ int main(int argc, char *argv[]) { if (argc != 3) { log_error("Wrong number of arguments."); - goto finish; + return EXIT_FAILURE; } if (streq(argv[1], "1")) { packet[0] = '+'; if (!fgets(packet+1, sizeof(packet)-1, stdin)) { - log_error_errno(errno, "Failed to read password: %m"); + r = log_error_errno(errno, "Failed to read password: %m"); goto finish; } @@ -78,22 +81,20 @@ int main(int argc, char *argv[]) { length = 1; } else { log_error("Invalid first argument %s", argv[1]); + r = -EINVAL; goto finish; } fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (fd < 0) { - log_error_errno(errno, "socket() failed: %m"); + r = log_error_errno(errno, "socket() failed: %m"); goto finish; } - if (send_on_socket(fd, argv[2], packet, length) < 0) - goto finish; - - r = EXIT_SUCCESS; + r = send_on_socket(fd, argv[2], packet, length); finish: - safe_close(fd); + memory_erase(packet, sizeof(packet)); - return r; + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c index 22af092cc0..432e62dd9f 100644 --- a/src/resolve-host/resolve-host.c +++ b/src/resolve-host/resolve-host.c @@ -23,14 +23,15 @@ #include <getopt.h> #include "sd-bus.h" -#include "bus-util.h" + +#include "af-list.h" +#include "alloc-util.h" #include "bus-error.h" +#include "bus-util.h" #include "in-addr-util.h" -#include "af-list.h" -#include "build.h" - -#include "resolved-dns-packet.h" +#include "parse-util.h" #include "resolved-def.h" +#include "resolved-dns-packet.h" #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC) @@ -299,8 +300,7 @@ static int parse_address(const char *s, int *family, union in_addr_union *addres percent = strchr(s, '%'); if (percent) { - r = safe_atoi(percent+1, &ifi); - if (r < 0 || ifi <= 0) { + if (parse_ifindex(percent+1, &ifi) < 0) { ifi = if_nametoindex(percent+1); if (ifi <= 0) return -EINVAL; @@ -507,9 +507,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; /* done */; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0 /* done */; + return version(); case '4': arg_family = AF_INET; @@ -522,7 +520,7 @@ static int parse_argv(int argc, char *argv[]) { case 'i': { int ifi; - if (safe_atoi(optarg, &ifi) >= 0 && ifi > 0) + if (parse_ifindex(optarg, &ifi) >= 0) arg_ifindex = ifi; else { ifi = if_nametoindex(optarg); diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index bf1b7c8ab4..f0a3b607d4 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-util.h" - #include "dns-domain.h" #include "resolved-bus.h" #include "resolved-def.h" diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 7af63b0a82..de1bd26174 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -19,13 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "conf-parser.h" - +#include "def.h" +#include "extract-word.h" +#include "parse-util.h" #include "resolved-conf.h" +#include "string-util.h" int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) { - const char *word, *state; - size_t length; DnsServer *first; int r; @@ -34,19 +36,22 @@ int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers; - FOREACH_WORD_QUOTED(word, length, string, state) { - char buffer[length+1]; - int family; + for(;;) { + _cleanup_free_ char *word = NULL; union in_addr_union addr; bool found = false; DnsServer *s; + int family; - memcpy(buffer, word, length); - buffer[length] = 0; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse resolved dns server syntax \"%s\": %m", string); + if (r == 0) + break; - r = in_addr_from_string_auto(buffer, &family, &addr); + r = in_addr_from_string_auto(word, &family, &addr); if (r < 0) { - log_warning("Ignoring invalid DNS address '%s'", buffer); + log_warning("Ignoring invalid DNS address '%s'", word); continue; } @@ -92,10 +97,10 @@ int config_parse_dnsv( /* Empty assignment means clear the list */ manager_flush_dns_servers(m, ltype); else { - /* Otherwise add to the list */ + /* Otherwise, add to the list */ r = manager_parse_dns_server(m, ltype, rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue); return 0; } } @@ -131,7 +136,7 @@ int config_parse_support( if (support < 0) { r = parse_boolean(rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse support level '%s'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse support level '%s'. Ignoring.", rvalue); return 0; } diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 89b9b0e1ea..3cf9c68074 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "resolved-dns-answer.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "resolved-dns-answer.h" +#include "string-util.h" DnsAnswer *dns_answer_new(unsigned n) { DnsAnswer *a; diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index ab13636bc1..04f64022e0 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "resolved-dns-cache.h" #include "resolved-dns-packet.h" diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index bebd1ee4a6..f23b3cf893 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -19,12 +19,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "utf8.h" -#include "util.h" -#include "strv.h" -#include "unaligned.h" +#include "alloc-util.h" #include "dns-domain.h" #include "resolved-dns-packet.h" +#include "string-table.h" +#include "strv.h" +#include "unaligned.h" +#include "utf8.h" +#include "util.h" int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 4b1d18b2ef..f7cb84e2a6 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "hostname-util.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "hostname-util.h" #include "local-addresses.h" - #include "resolved-dns-query.h" /* How long to wait for the query in total */ diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c index 1507f22da0..48951221dc 100644 --- a/src/resolve/resolved-dns-question.c +++ b/src/resolve/resolved-dns-question.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "resolved-dns-question.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "resolved-dns-question.h" DnsQuestion *dns_question_new(unsigned n) { DnsQuestion *q; diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index fd2f53f40b..ba2ea686f3 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -21,12 +21,14 @@ #include <math.h> -#include "strv.h" - +#include "alloc-util.h" #include "dns-domain.h" -#include "resolved-dns-rr.h" -#include "resolved-dns-packet.h" #include "dns-type.h" +#include "hexdecoct.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-rr.h" +#include "string-util.h" +#include "strv.h" DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) { DnsResourceKey *k; @@ -146,15 +148,14 @@ int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRec return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); } -static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void dns_resource_key_hash_func(const void *i, struct siphash *state) { const DnsResourceKey *k = i; - unsigned long ul; - ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key); - ul = ul * hash_key[0] + ul + k->class; - ul = ul * hash_key[1] + ul + k->type; + assert(k); - return ul; + dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state); + siphash24_compress(&k->class, sizeof(k->class), state); + siphash24_compress(&k->type, sizeof(k->type), state); } static int dns_resource_key_compare_func(const void *a, const void *b) { diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 9e6f595a1b..b15370b017 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -21,15 +21,17 @@ #include <netinet/tcp.h> -#include "missing.h" -#include "strv.h" -#include "socket-util.h" #include "af-list.h" -#include "random-util.h" -#include "hostname-util.h" +#include "alloc-util.h" #include "dns-domain.h" -#include "resolved-llmnr.h" +#include "fd-util.h" +#include "hostname-util.h" +#include "missing.h" +#include "random-util.h" #include "resolved-dns-scope.h" +#include "resolved-llmnr.h" +#include "socket-util.h" +#include "strv.h" #define MULTICAST_RATELIMIT_INTERVAL_USEC (1*USEC_PER_SEC) #define MULTICAST_RATELIMIT_BURST 1000 diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 2ff5b192df..e803f635ab 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "siphash24.h" - +#include "alloc-util.h" #include "resolved-dns-server.h" +#include "siphash24.h" /* After how much time to repeat classic DNS requests */ #define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC) @@ -137,14 +137,13 @@ void dns_server_packet_lost(DnsServer *s, usec_t usec) { s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC); } -static unsigned long dns_server_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void dns_server_hash_func(const void *p, struct siphash *state) { const DnsServer *s = p; - uint64_t u; - siphash24((uint8_t*) &u, &s->address, FAMILY_ADDRESS_SIZE(s->family), hash_key); - u = u * hash_key[0] + u + s->family; + assert(s); - return u; + siphash24_compress(&s->family, sizeof(s->family), state); + siphash24_compress(&s->address, FAMILY_ADDRESS_SIZE(s->family), state); } static int dns_server_compare_func(const void *a, const void *b) { diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index 7f47e7223a..1c501182fb 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -21,6 +21,9 @@ #include <netinet/tcp.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "io-util.h" #include "missing.h" #include "resolved-dns-stream.h" diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index b30473dd7e..6545f6cd8a 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -20,11 +20,13 @@ ***/ #include "af-list.h" - -#include "resolved-llmnr.h" -#include "resolved-dns-transaction.h" -#include "random-util.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "fd-util.h" +#include "random-util.h" +#include "resolved-dns-transaction.h" +#include "resolved-llmnr.h" +#include "string-table.h" DnsTransaction* dns_transaction_free(DnsTransaction *t) { DnsQuery *q; diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 8a59bd1c3c..48dcf76daa 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -19,11 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "list.h" - -#include "resolved-dns-zone.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "list.h" #include "resolved-dns-packet.h" +#include "resolved-dns-zone.h" +#include "string-util.h" /* Never allow more than 1K entries */ #define ZONE_MAX 1024 diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index b9fd8e3dbc..2892641075 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -22,9 +22,13 @@ #include <net/if.h> #include "sd-network.h" -#include "strv.h" + +#include "alloc-util.h" #include "missing.h" +#include "parse-util.h" #include "resolved-link.h" +#include "string-util.h" +#include "strv.h" int link_new(Manager *m, Link **ret, int ifindex) { _cleanup_(link_freep) Link *l = NULL; diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 8afaf8db6e..5c3a4a00c3 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -22,8 +22,9 @@ #include <resolv.h> #include <netinet/in.h> -#include "resolved-manager.h" +#include "fd-util.h" #include "resolved-llmnr.h" +#include "resolved-manager.h" void manager_llmnr_stop(Manager *m) { assert(m); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index de924e3ed9..a588538b52 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -19,26 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <netinet/in.h> +#include <poll.h> #include <resolv.h> #include <sys/ioctl.h> -#include <poll.h> -#include <netinet/in.h> -#include "netlink-util.h" -#include "network-internal.h" -#include "socket-util.h" #include "af-list.h" -#include "utf8.h" +#include "alloc-util.h" +#include "dns-domain.h" +#include "fd-util.h" #include "fileio-label.h" +#include "hostname-util.h" +#include "io-util.h" +#include "netlink-util.h" +#include "network-internal.h" #include "ordered-set.h" +#include "parse-util.h" #include "random-util.h" -#include "hostname-util.h" - -#include "dns-domain.h" -#include "resolved-conf.h" #include "resolved-bus.h" -#include "resolved-manager.h" +#include "resolved-conf.h" #include "resolved-llmnr.h" +#include "resolved-manager.h" +#include "socket-util.h" +#include "string-table.h" +#include "string-util.h" +#include "utf8.h" #define SEND_TIMEOUT_USEC (200 * USEC_PER_MSEC) diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 32e61af925..7ba0546f4a 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -19,15 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-event.h" #include "sd-daemon.h" +#include "sd-event.h" + +#include "capability-util.h" #include "mkdir.h" -#include "capability.h" +#include "resolved-conf.h" +#include "resolved-manager.h" #include "selinux-util.h" #include "signal-util.h" - -#include "resolved-manager.h" -#include "resolved-conf.h" +#include "user-util.h" int main(int argc, char *argv[]) { _cleanup_(manager_freep) Manager *m = NULL; diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index 904dec6bfc..5c45a3ae6c 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -19,124 +19,410 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "mkdir.h" -#include "fileio.h" +#include <linux/rfkill.h> +#include <poll.h> + #include "libudev.h" +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "io-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "string-table.h" +#include "string-util.h" #include "udev-util.h" +#include "util.h" -int main(int argc, char *argv[]) { - _cleanup_udev_unref_ struct udev *udev = NULL; - _cleanup_udev_device_unref_ struct udev_device *device = NULL; - _cleanup_free_ char *saved = NULL, *escaped_type = NULL, *escaped_path_id = NULL; - const char *name, *type, *path_id; - int r; +#define EXIT_USEC (5 * USEC_PER_SEC) - if (argc != 3) { - log_error("This program requires two arguments."); - return EXIT_FAILURE; - } +static const char* const rfkill_type_table[NUM_RFKILL_TYPES] = { + [RFKILL_TYPE_ALL] = "all", + [RFKILL_TYPE_WLAN] = "wlan", + [RFKILL_TYPE_BLUETOOTH] = "bluetooth", + [RFKILL_TYPE_UWB] = "uwb", + [RFKILL_TYPE_WIMAX] = "wimax", + [RFKILL_TYPE_WWAN] = "wwan", + [RFKILL_TYPE_GPS] = "gps", + [RFKILL_TYPE_FM] = "fm", + [RFKILL_TYPE_NFC] = "nfc", +}; - log_set_target(LOG_TARGET_AUTO); - log_parse_environment(); - log_open(); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(rfkill_type, int); - umask(0022); +static int find_device( + struct udev *udev, + const struct rfkill_event *event, + struct udev_device **ret) { - r = mkdir_p("/var/lib/systemd/rfkill", 0755); - if (r < 0) { - log_error_errno(r, "Failed to create rfkill directory: %m"); - return EXIT_FAILURE; - } + _cleanup_free_ char *sysname = NULL; + struct udev_device *device; + const char *name; - udev = udev_new(); - if (!udev) { - log_oom(); - return EXIT_FAILURE; - } + assert(udev); + assert(event); + assert(ret); - device = udev_device_new_from_subsystem_sysname(udev, "rfkill", argv[2]); - if (!device) { - log_debug_errno(errno, "Failed to get rfkill device '%s', ignoring: %m", argv[2]); - return EXIT_SUCCESS; - } + if (asprintf(&sysname, "rfkill%i", event->idx) < 0) + return log_oom(); + + device = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname); + if (!device) + return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m"); name = udev_device_get_sysattr_value(device, "name"); if (!name) { - log_error("rfkill device has no name? Ignoring device."); - return EXIT_SUCCESS; + log_debug("Device has no name, ignoring."); + udev_device_unref(device); + return -ENOENT; } log_debug("Operating on rfkill device '%s'.", name); - type = udev_device_get_sysattr_value(device, "type"); - if (!type) { - log_error("rfkill device has no type? Ignoring device."); - return EXIT_SUCCESS; + *ret = device; + return 0; +} + +static int wait_for_initialized( + struct udev *udev, + struct udev_device *device, + struct udev_device **ret) { + + _cleanup_udev_monitor_unref_ struct udev_monitor *monitor = NULL; + struct udev_device *d; + const char *sysname; + int watch_fd, r; + + assert(udev); + assert(device); + assert(ret); + + if (udev_device_get_is_initialized(device) != 0) { + *ret = udev_device_ref(device); + return 0; } - escaped_type = cescape(type); - if (!escaped_type) { - log_oom(); - return EXIT_FAILURE; + assert_se(sysname = udev_device_get_sysname(device)); + + /* Wait until the device is initialized, so that we can get + * access to the ID_PATH property */ + + monitor = udev_monitor_new_from_netlink(udev, "udev"); + if (!monitor) + return log_error_errno(errno, "Failed to acquire monitor: %m"); + + r = udev_monitor_filter_add_match_subsystem_devtype(monitor, "rfkill", NULL); + if (r < 0) + return log_error_errno(r, "Failed to add rfkill udev match to monitor: %m"); + + r = udev_monitor_enable_receiving(monitor); + if (r < 0) + return log_error_errno(r, "Failed to enable udev receiving: %m"); + + watch_fd = udev_monitor_get_fd(monitor); + if (watch_fd < 0) + return log_error_errno(watch_fd, "Failed to get watch fd: %m"); + + /* Check again, maybe things changed */ + d = udev_device_new_from_subsystem_sysname(udev, "rfkill", sysname); + if (!d) + return log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open device: %m"); + + if (udev_device_get_is_initialized(d) != 0) { + *ret = d; + return 0; + } + + for (;;) { + _cleanup_udev_device_unref_ struct udev_device *t = NULL; + + r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY); + if (r == -EINTR) + continue; + if (r < 0) + return log_error_errno(r, "Failed to watch udev monitor: %m"); + + t = udev_monitor_receive_device(monitor); + if (!t) + continue; + + if (streq_ptr(udev_device_get_sysname(device), sysname)) { + *ret = udev_device_ref(t); + return 0; + } } +} + +static int determine_state_file( + struct udev *udev, + const struct rfkill_event *event, + struct udev_device *d, + char **ret) { + + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + const char *path_id, *type; + char *state_file; + int r; + + assert(event); + assert(d); + assert(ret); + + r = wait_for_initialized(udev, d, &device); + if (r < 0) + return r; + + assert_se(type = rfkill_type_to_string(event->type)); path_id = udev_device_get_property_value(device, "ID_PATH"); if (path_id) { + _cleanup_free_ char *escaped_path_id = NULL; + escaped_path_id = cescape(path_id); - if (!escaped_path_id) { - log_oom(); - return EXIT_FAILURE; - } + if (!escaped_path_id) + return log_oom(); - saved = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", escaped_type, NULL); + state_file = strjoin("/var/lib/systemd/rfkill/", escaped_path_id, ":", type, NULL); } else - saved = strjoin("/var/lib/systemd/rfkill/", escaped_type, NULL); + state_file = strjoin("/var/lib/systemd/rfkill/", type, NULL); + + if (!state_file) + return log_oom(); + + *ret = state_file; + return 0; +} + +static int load_state( + int rfkill_fd, + struct udev *udev, + const struct rfkill_event *event) { + + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + _cleanup_free_ char *state_file = NULL, *value = NULL; + struct rfkill_event we; + ssize_t l; + int b, r; - if (!saved) { - log_oom(); + assert(rfkill_fd >= 0); + assert(udev); + assert(event); + + if (shall_restore_state() == 0) + return 0; + + r = find_device(udev, event, &device); + if (r < 0) + return r; + + r = determine_state_file(udev, event, device, &state_file); + if (r < 0) + return r; + + r = read_one_line_file(state_file, &value); + if (r == -ENOENT) { + /* No state file? Then save the current state */ + + r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); + if (r < 0) + return log_error_errno(r, "Failed to write state file %s: %m", state_file); + + log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to read state file %s: %m", state_file); + + b = parse_boolean(value); + if (b < 0) + return log_error_errno(b, "Failed to parse state file %s: %m", state_file); + + we = (struct rfkill_event) { + .op = RFKILL_OP_CHANGE, + .idx = event->idx, + .soft = b, + }; + + l = write(rfkill_fd, &we, sizeof(we)); + if (l < 0) + return log_error_errno(errno, "Failed to restore rfkill state for %i: %m", event->idx); + if (l != sizeof(we)) { + log_error("Couldn't write rfkill event structure, too short."); + return -EIO; + } + + log_debug("Loaded state '%s' from %s.", one_zero(b), state_file); + return 0; +} + +static int save_state( + int rfkill_fd, + struct udev *udev, + const struct rfkill_event *event) { + + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + _cleanup_free_ char *state_file = NULL; + int r; + + assert(rfkill_fd >= 0); + assert(udev); + assert(event); + + r = find_device(udev, event, &device); + if (r < 0) + return r; + + r = determine_state_file(udev, event, device, &state_file); + if (r < 0) + return r; + + r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); + if (r < 0) + return log_error_errno(r, "Failed to write state file %s: %m", state_file); + + log_debug("Saved state '%s' to %s.", one_zero(event->soft), state_file); + return 0; +} + +int main(int argc, char *argv[]) { + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_close_ int rfkill_fd = -1; + bool ready = false; + int r, n; + + if (argc > 1) { + log_error("This program requires no arguments."); return EXIT_FAILURE; } - if (streq(argv[1], "load")) { - _cleanup_free_ char *value = NULL; + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); - if (!shall_restore_state()) - return EXIT_SUCCESS; + umask(0022); - r = read_one_line_file(saved, &value); - if (r == -ENOENT) - return EXIT_SUCCESS; - if (r < 0) { - log_error_errno(r, "Failed to read %s: %m", saved); - return EXIT_FAILURE; + udev = udev_new(); + if (!udev) { + r = log_oom(); + goto finish; + } + + r = mkdir_p("/var/lib/systemd/rfkill", 0755); + if (r < 0) { + log_error_errno(r, "Failed to create rfkill directory: %m"); + goto finish; + } + + n = sd_listen_fds(false); + if (n < 0) { + r = log_error_errno(n, "Failed to determine whether we got any file descriptors passed: %m"); + goto finish; + } + if (n > 1) { + log_error("Got too many file descriptors."); + r = -EINVAL; + goto finish; + } + + if (n == 0) { + rfkill_fd = open("/dev/rfkill", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); + if (rfkill_fd < 0) { + if (errno == ENOENT) { + log_debug_errno(errno, "Missing rfkill subsystem, or no device present, exiting."); + r = 0; + goto finish; + } + + r = log_error_errno(errno, "Failed to open /dev/rfkill: %m"); + goto finish; } + } else { + rfkill_fd = SD_LISTEN_FDS_START; - r = udev_device_set_sysattr_value(device, "soft", value); + r = fd_nonblock(rfkill_fd, 1); if (r < 0) { - log_debug_errno(r, "Failed to write 'soft' attribute on rfkill device, ignoring: %m"); - return EXIT_SUCCESS; + log_error_errno(r, "Failed to make /dev/rfkill socket non-blocking: %m"); + goto finish; } + } + + for (;;) { + struct rfkill_event event; + const char *type; + ssize_t l; - } else if (streq(argv[1], "save")) { - const char *value; + l = read(rfkill_fd, &event, sizeof(event)); + if (l < 0) { + if (errno == EAGAIN) { - value = udev_device_get_sysattr_value(device, "soft"); - if (!value) { - log_debug_errno(r, "Failed to read system attribute, ignoring device: %m"); - return EXIT_SUCCESS; + if (!ready) { + /* Notify manager that we are + * now finished with + * processing whatever was + * queued */ + (void) sd_notify(false, "READY=1"); + ready = true; + } + + /* Hang around for a bit, maybe there's more coming */ + + r = fd_wait_for_event(rfkill_fd, POLLIN, EXIT_USEC); + if (r == -EINTR) + continue; + if (r < 0) { + log_error_errno(r, "Failed to poll() on device: %m"); + goto finish; + } + if (r > 0) + continue; + + log_debug("All events read and idle, exiting."); + break; + } + + log_error_errno(errno, "Failed to read from /dev/rfkill: %m"); } - r = write_string_file(saved, value, WRITE_STRING_FILE_CREATE); - if (r < 0) { - log_error_errno(r, "Failed to write %s: %m", saved); - return EXIT_FAILURE; + if (l != RFKILL_EVENT_SIZE_V1) { + log_error("Read event structure of invalid size."); + r = -EIO; + goto finish; } - } else { - log_error("Unknown verb %s.", argv[1]); - return EXIT_FAILURE; + type = rfkill_type_to_string(event.type); + if (!type) { + log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type); + continue; + } + + switch (event.op) { + + case RFKILL_OP_ADD: + log_debug("A new rfkill device has been added with index %i and type %s.", event.idx, type); + (void) load_state(rfkill_fd, udev, &event); + break; + + case RFKILL_OP_DEL: + log_debug("An rfkill device has been removed with index %i and type %s", event.idx, type); + break; + + case RFKILL_OP_CHANGE: + log_debug("An rfkill device has changed state with index %i and type %s", event.idx, type); + (void) save_state(rfkill_fd, udev, &event); + break; + + default: + log_debug("Unknown event %i from /dev/rfkill for index %i and type %s, ignoring.", event.op, event.idx, type); + break; + } } - return EXIT_SUCCESS; + r = 0; + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/run/run.c b/src/run/run.c index 657c6fcaf1..38a482bb11 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -19,24 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <getopt.h> +#include <stdio.h> #include "sd-bus.h" #include "sd-event.h" + +#include "alloc-util.h" +#include "bus-error.h" #include "bus-util.h" -#include "event-util.h" -#include "strv.h" -#include "build.h" -#include "unit-name.h" +#include "calendarspec.h" #include "env-util.h" +#include "event-util.h" +#include "fd-util.h" +#include "formats-util.h" #include "path-util.h" -#include "bus-error.h" -#include "calendarspec.h" #include "ptyfwd.h" -#include "formats-util.h" #include "signal-util.h" #include "spawn-polkit-agent.h" +#include "strv.h" +#include "terminal-util.h" +#include "unit-name.h" +#include "user-util.h" +#include "parse-util.h" static bool arg_ask_password = true; static bool arg_scope = false; @@ -62,7 +67,7 @@ static usec_t arg_on_boot = 0; static usec_t arg_on_startup = 0; static usec_t arg_on_unit_active = 0; static usec_t arg_on_unit_inactive = 0; -static char *arg_on_calendar = NULL; +static const char *arg_on_calendar = NULL; static char **arg_timer_property = NULL; static bool arg_quiet = false; @@ -181,7 +186,6 @@ static int parse_argv(int argc, char *argv[]) { }; int r, c; - CalendarSpec *spec = NULL; assert(argc >= 0); assert(argv); @@ -199,9 +203,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_USER: arg_user = true; @@ -337,16 +339,19 @@ static int parse_argv(int argc, char *argv[]) { break; - case ARG_ON_CALENDAR: + case ARG_ON_CALENDAR: { + CalendarSpec *spec = NULL; r = calendar_spec_from_string(optarg, &spec); if (r < 0) { log_error("Invalid calendar spec: %s", optarg); return r; } - free(spec); + + calendar_spec_free(spec); arg_on_calendar = optarg; break; + } case ARG_TIMER_PROPERTY: @@ -391,6 +396,11 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } + if (arg_pty && arg_transport == BUS_TRANSPORT_REMOTE) { + log_error("--pty is only supported when connecting to the local system or containers."); + return -EINVAL; + } + if (arg_scope && with_timer()) { log_error("Timer options are not supported in --scope mode."); return -EINVAL; @@ -709,9 +719,9 @@ static int start_transient_service( _cleanup_bus_unref_ sd_bus *system_bus = NULL; const char *s; - r = sd_bus_open_system(&system_bus); + r = sd_bus_default_system(&system_bus); if (r < 0) - log_error_errno(r, "Failed to connect to system bus: %m"); + return log_error_errno(r, "Failed to connect to system bus: %m"); r = sd_bus_call_method(system_bus, "org.freedesktop.machine1", @@ -796,10 +806,8 @@ static int start_transient_service( polkit_agent_open_if_enabled(); r = sd_bus_call(bus, m, 0, &error, &reply); - if (r < 0) { - log_error("Failed to start transient service unit: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r)); if (w) { const char *object; @@ -830,7 +838,7 @@ static int start_transient_service( if (!arg_quiet) log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service); - r = pty_forward_new(event, master, false, false, &forward); + r = pty_forward_new(event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &forward); if (r < 0) return log_error_errno(r, "Failed to create PTY forwarder: %m"); @@ -1149,14 +1157,15 @@ int main(int argc, char* argv[]) { if (r <= 0) goto finish; - if (argc > optind) { - r = find_binary(argv[optind], arg_transport == BUS_TRANSPORT_LOCAL, &command); + if (argc > optind && arg_transport == BUS_TRANSPORT_LOCAL) { + /* Patch in an absolute path */ + + r = find_binary(argv[optind], &command); if (r < 0) { - log_error_errno(r, "Failed to find executable %s%s: %m", - argv[optind], - arg_transport == BUS_TRANSPORT_LOCAL ? "" : " on local system"); + log_error_errno(r, "Failed to find executable %s: %m", argv[optind]); goto finish; } + argv[optind] = command; } @@ -1176,7 +1185,7 @@ int main(int argc, char* argv[]) { arg_description = description; } - r = bus_open_transport_systemd(arg_transport, arg_host, arg_user, &bus); + r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index bd8c988751..79f5a60579 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -22,9 +22,12 @@ #include <errno.h> #include <stdbool.h> +#include "alloc-util.h" #include "acl-util.h" -#include "util.h" +#include "string-util.h" #include "strv.h" +#include "user-util.h" +#include "util.h" int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { acl_entry_t i; diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 64e50401b9..8e36067f74 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -19,16 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <fcntl.h> #include <stdint.h> +#include <stdio.h> #include <string.h> #include <unistd.h> -#include <fcntl.h> -#include <util.h> -#include <fileio.h> -#include <time-util.h> -#include <acpi-fpdt.h> +#include "alloc-util.h" +#include "acpi-fpdt.h" +#include "fd-util.h" +#include "fileio.h" +#include "time-util.h" +#include "util.h" struct acpi_table_header { char signature[4]; diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c index c2bbd330bd..f6ac43adfe 100644 --- a/src/shared/apparmor-util.c +++ b/src/shared/apparmor-util.c @@ -19,10 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -#include "util.h" -#include "fileio.h" +#include "alloc-util.h" #include "apparmor-util.h" +#include "fileio.h" +#include "parse-util.h" +#include "util.h" bool mac_apparmor_use(void) { static int cached_use = -1; diff --git a/src/shared/architecture.c b/src/shared/architecture.c index 8e72e7a36a..e2efa4272b 100644 --- a/src/shared/architecture.c +++ b/src/shared/architecture.c @@ -21,6 +21,8 @@ #include <sys/utsname.h> +#include "string-table.h" +#include "string-util.h" #include "architecture.h" int uname_architecture(void) { diff --git a/src/shared/architecture.h b/src/shared/architecture.h index f5bbf65a90..61d067cad7 100644 --- a/src/shared/architecture.h +++ b/src/shared/architecture.h @@ -78,9 +78,11 @@ int uname_architecture(void); #if defined(__x86_64__) # define native_architecture() ARCHITECTURE_X86_64 # define LIB_ARCH_TUPLE "x86_64-linux-gnu" +# define PROC_CPUINFO_MODEL "model name" #elif defined(__i386__) # define native_architecture() ARCHITECTURE_X86 # define LIB_ARCH_TUPLE "i386-linux-gnu" +# define PROC_CPUINFO_MODEL "model name" #elif defined(__powerpc64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC64 @@ -89,6 +91,7 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_PPC64_LE # define LIB_ARCH_TUPLE "powerpc64le-linux-gnu" # endif +# define PROC_CPUINFO_MODEL "cpu" #elif defined(__powerpc__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_PPC @@ -97,15 +100,18 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_PPC_LE # error "Missing LIB_ARCH_TUPLE for PPCLE" # endif +# define PROC_CPUINFO_MODEL "cpu" #elif defined(__ia64__) # define native_architecture() ARCHITECTURE_IA64 # define LIB_ARCH_TUPLE "ia64-linux-gnu" #elif defined(__hppa64__) # define native_architecture() ARCHITECTURE_PARISC64 # error "Missing LIB_ARCH_TUPLE for HPPA64" +# define PROC_CPUINFO_MODEL "cpu" #elif defined(__hppa__) # define native_architecture() ARCHITECTURE_PARISC # define LIB_ARCH_TUPLE "hppa‑linux‑gnu" +# define PROC_CPUINFO_MODEL "cpu" #elif defined(__s390x__) # define native_architecture() ARCHITECTURE_S390X # define LIB_ARCH_TUPLE "s390x-linux-gnu" @@ -115,9 +121,11 @@ int uname_architecture(void); #elif defined(__sparc64__) # define native_architecture() ARCHITECTURE_SPARC64 # define LIB_ARCH_TUPLE "sparc64-linux-gnu" +# define PROC_CPUINFO_MODEL "cpu" #elif defined(__sparc__) # define native_architecture() ARCHITECTURE_SPARC # define LIB_ARCH_TUPLE "sparc-linux-gnu" +# define PROC_CPUINFO_MODEL "cpu" #elif defined(__mips64__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS64 @@ -126,6 +134,7 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_MIPS64_LE # error "Missing LIB_ARCH_TUPLE for MIPS64_LE" # endif +# define PROC_CPUINFO_MODEL "cpu model" #elif defined(__mips__) # if __BYTE_ORDER == __BIG_ENDIAN # define native_architecture() ARCHITECTURE_MIPS @@ -134,6 +143,7 @@ int uname_architecture(void); # define native_architecture() ARCHITECTURE_MIPS_LE # define LIB_ARCH_TUPLE "mipsel-linux-gnu" # endif +# define PROC_CPUINFO_MODEL "cpu model" #elif defined(__alpha__) # define native_architecture() ARCHITECTURE_ALPHA # define LIB_ARCH_TUPLE "alpha-linux-gnu" @@ -169,6 +179,7 @@ int uname_architecture(void); # define LIB_ARCH_TUPLE "arm-linux-gnu" # endif # endif +# define PROC_CPUINFO_MODEL "model name" #elif defined(__sh64__) # define native_architecture() ARCHITECTURE_SH64 # error "Missing LIB_ARCH_TUPLE for SH64" @@ -188,5 +199,10 @@ int uname_architecture(void); # error "Please register your architecture here!" #endif +#ifndef PROC_CPUINFO_MODEL +#warning "PROC_CPUINFO_MODEL not defined for your architecture" +#define PROC_CPUINFO_MODEL "model name" +#endif + const char *architecture_to_string(int a) _const_; int architecture_from_string(const char *s) _pure_; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index b02cdf9a17..fbe2b6fecb 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -18,27 +18,167 @@ You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> -#include <termios.h> -#include <unistd.h> -#include <poll.h> -#include <sys/inotify.h> + #include <errno.h> #include <fcntl.h> -#include <sys/socket.h> -#include <string.h> -#include <sys/un.h> +#include <poll.h> +#include <stdbool.h> #include <stddef.h> +#include <string.h> +#include <sys/inotify.h> #include <sys/signalfd.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <termios.h> +#include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "ask-password-api.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "io-util.h" +#include "missing.h" #include "mkdir.h" -#include "strv.h" #include "random-util.h" -#include "terminal-util.h" #include "signal-util.h" -#include "ask-password-api.h" +#include "socket-util.h" +#include "string-util.h" +#include "strv.h" +#include "terminal-util.h" +#include "umask-util.h" +#include "util.h" + +#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2) + +static int lookup_key(const char *keyname, key_serial_t *ret) { + key_serial_t serial; + + assert(keyname); + assert(ret); + + serial = request_key("user", keyname, NULL, 0); + if (serial == -1) + return -errno; + + *ret = serial; + return 0; +} + +static int retrieve_key(key_serial_t serial, char ***ret) { + _cleanup_free_ char *p = NULL; + long m = 100, n; + char **l; + + assert(ret); + + for (;;) { + p = new(char, m); + if (!p) + return -ENOMEM; + + n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0); + if (n < 0) + return -errno; + + if (n < m) + break; + + memory_erase(p, n); + free(p); + m *= 2; + } + + l = strv_parse_nulstr(p, n); + if (!l) + return -ENOMEM; + + memory_erase(p, n); + + *ret = l; + return 0; +} + +static int add_to_keyring(const char *keyname, AskPasswordFlags flags, char **passwords) { + _cleanup_strv_free_erase_ char **l = NULL; + _cleanup_free_ char *p = NULL; + key_serial_t serial; + size_t n; + int r; + + assert(keyname); + assert(passwords); + + if (!(flags & ASK_PASSWORD_PUSH_CACHE)) + return 0; + + r = lookup_key(keyname, &serial); + if (r >= 0) { + r = retrieve_key(serial, &l); + if (r < 0) + return r; + } else if (r != -ENOKEY) + return r; + + r = strv_extend_strv(&l, passwords, true); + if (r <= 0) + return r; + + r = strv_make_nulstr(l, &p, &n); + if (r < 0) + return r; + + /* Truncate trailing NUL */ + assert(n > 0); + assert(p[n-1] == 0); + + serial = add_key("user", keyname, p, n-1, KEY_SPEC_USER_KEYRING); + memory_erase(p, n); + if (serial == -1) + return -errno; + + if (keyctl(KEYCTL_SET_TIMEOUT, + (unsigned long) serial, + (unsigned long) DIV_ROUND_UP(KEYRING_TIMEOUT_USEC, USEC_PER_SEC), 0, 0) < 0) + log_debug_errno(errno, "Failed to adjust timeout: %m"); + + log_debug("Added key to keyring as %" PRIi32 ".", serial); + + return 1; +} + +static int add_to_keyring_and_log(const char *keyname, AskPasswordFlags flags, char **passwords) { + int r; + + assert(keyname); + assert(passwords); + + r = add_to_keyring(keyname, flags, passwords); + if (r < 0) + return log_debug_errno(r, "Failed to add password to keyring: %m"); + + return 0; +} + +int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret) { + + key_serial_t serial; + int r; + + assert(keyname); + assert(ret); + + if (!(flags & ASK_PASSWORD_ACCEPT_CACHED)) + return -EUNATCH; + + r = lookup_key(keyname, &serial); + if (r == -ENOSYS) /* when retrieving the distinction doesn't matter */ + return -ENOKEY; + if (r < 0) + return r; + + return retrieve_key(serial, ret); +} static void backspace_chars(int ttyfd, size_t p) { @@ -54,10 +194,11 @@ static void backspace_chars(int ttyfd, size_t p) { int ask_password_tty( const char *message, + const char *keyname, usec_t until, - bool echo, + AskPasswordFlags flags, const char *flag_file, - char **_passphrase) { + char **ret) { struct termios old_termios, new_termios; char passphrase[LINE_MAX], *x; @@ -66,15 +207,19 @@ int ask_password_tty( _cleanup_close_ int ttyfd = -1, notify = -1; struct pollfd pollfd[2]; bool reset_tty = false; - bool silent_mode = false; bool dirty = false; enum { POLL_TTY, POLL_INOTIFY }; - assert(message); - assert(_passphrase); + assert(ret); + + if (flags & ASK_PASSWORD_NO_TTY) + return -EUNATCH; + + if (!message) + message = "Password:"; if (flag_file) { notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); @@ -97,10 +242,10 @@ int ask_password_tty( goto finish; } - loop_write(ttyfd, ANSI_HIGHLIGHT, sizeof(ANSI_HIGHLIGHT)-1, false); + loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false); loop_write(ttyfd, message, strlen(message), false); loop_write(ttyfd, " ", 1, false); - loop_write(ttyfd, ANSI_NORMAL, sizeof(ANSI_NORMAL)-1, false); + loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false); new_termios = old_termios; new_termios.c_lflag &= ~(ICANON|ECHO); @@ -145,7 +290,7 @@ int ask_password_tty( goto finish; } - k = poll(pollfd, notify > 0 ? 2 : 1, sleep_for); + k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); if (k < 0) { if (errno == EINTR) continue; @@ -157,7 +302,7 @@ int ask_password_tty( goto finish; } - if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) + if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) flush_fd(notify); if (pollfd[POLL_TTY].revents == 0) @@ -178,7 +323,7 @@ int ask_password_tty( break; else if (c == 21) { /* C-u */ - if (!silent_mode) + if (!(flags & ASK_PASSWORD_SILENT)) backspace_chars(ttyfd, p); p = 0; @@ -186,28 +331,28 @@ int ask_password_tty( if (p > 0) { - if (!silent_mode) + if (!(flags & ASK_PASSWORD_SILENT)) backspace_chars(ttyfd, 1); p--; - } else if (!dirty && !silent_mode) { + } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) { - silent_mode = true; + flags |= ASK_PASSWORD_SILENT; /* There are two ways to enter silent * mode. Either by pressing backspace - * as first key (and only as first key), - * or ... */ + * as first key (and only as first + * key), or ... */ if (ttyfd >= 0) loop_write(ttyfd, "(no echo) ", 10, false); } else if (ttyfd >= 0) loop_write(ttyfd, "\a", 1, false); - } else if (c == '\t' && !silent_mode) { + } else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) { backspace_chars(ttyfd, p); - silent_mode = true; + flags |= ASK_PASSWORD_SILENT; /* ... or by pressing TAB at any time. */ @@ -221,20 +366,26 @@ int ask_password_tty( passphrase[p++] = c; - if (!silent_mode && ttyfd >= 0) - loop_write(ttyfd, echo ? &c : "*", 1, false); + if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) + loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false); dirty = true; } + + c = 'x'; } x = strndup(passphrase, p); + memory_erase(passphrase, p); if (!x) { r = -ENOMEM; goto finish; } - *_passphrase = x; + if (keyname) + (void) add_to_keyring_and_log(keyname, flags, STRV_MAKE(x)); + + *ret = x; r = 0; finish: @@ -247,52 +398,38 @@ finish: } static int create_socket(char **name) { - int fd; - union { - struct sockaddr sa; - struct sockaddr_un un; - } sa = { + union sockaddr_union sa = { .un.sun_family = AF_UNIX, }; - int one = 1; - int r = 0; + _cleanup_close_ int fd = -1; + static const int one = 1; char *c; + int r; assert(name); fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (fd < 0) - return log_error_errno(errno, "socket() failed: %m"); + return -errno; snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%" PRIx64, random_u64()); RUN_WITH_UMASK(0177) { - r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)); - } - - if (r < 0) { - r = -errno; - log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path); - goto fail; + if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) + return -errno; } - if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) { - r = -errno; - log_error_errno(errno, "SO_PASSCRED failed: %m"); - goto fail; - } + if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) + return -errno; c = strdup(sa.un.sun_path); - if (!c) { - r = log_oom(); - goto fail; - } + if (!c) + return -ENOMEM; *name = c; - return fd; -fail: - safe_close(fd); + r = fd; + fd = -1; return r; } @@ -301,10 +438,10 @@ int ask_password_agent( const char *message, const char *icon, const char *id, + const char *keyname, usec_t until, - bool echo, - bool accept_cached, - char ***_passphrases) { + AskPasswordFlags flags, + char ***ret) { enum { FD_SOCKET, @@ -312,35 +449,38 @@ int ask_password_agent( _FD_MAX }; + _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1; char temp[] = "/run/systemd/ask-password/tmp.XXXXXX"; char final[sizeof(temp)] = ""; - _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *socket_name = NULL; - _cleanup_close_ int socket_fd = -1, signal_fd = -1, fd = -1; - sigset_t mask, oldmask; + _cleanup_strv_free_ char **l = NULL; + _cleanup_fclose_ FILE *f = NULL; struct pollfd pollfd[_FD_MAX]; + sigset_t mask, oldmask; int r; - assert(_passphrases); + assert(ret); + + if (flags & ASK_PASSWORD_NO_AGENT) + return -EUNATCH; assert_se(sigemptyset(&mask) >= 0); assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0); assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) >= 0); - mkdir_p_label("/run/systemd/ask-password", 0755); + (void) mkdir_p_label("/run/systemd/ask-password", 0755); fd = mkostemp_safe(temp, O_WRONLY|O_CLOEXEC); if (fd < 0) { - r = log_error_errno(errno, - "Failed to create password file: %m"); + r = fd; goto finish; } - fchmod(fd, 0644); + (void) fchmod(fd, 0644); f = fdopen(fd, "w"); if (!f) { - r = log_error_errno(errno, "Failed to allocate FILE: %m"); + r = -errno; goto finish; } @@ -348,7 +488,7 @@ int ask_password_agent( signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); if (signal_fd < 0) { - r = log_error_errno(errno, "signalfd(): %m"); + r = -errno; goto finish; } @@ -367,8 +507,8 @@ int ask_password_agent( "NotAfter="USEC_FMT"\n", getpid(), socket_name, - accept_cached ? 1 : 0, - echo ? 1 : 0, + (flags & ASK_PASSWORD_ACCEPT_CACHED) ? 1 : 0, + (flags & ASK_PASSWORD_ECHO) ? 1 : 0, until); if (message) @@ -381,10 +521,8 @@ int ask_password_agent( fprintf(f, "Id=%s\n", id); r = fflush_and_check(f); - if (r < 0) { - log_error_errno(r, "Failed to write query file: %m"); + if (r < 0) goto finish; - } memcpy(final, temp, sizeof(temp)); @@ -393,7 +531,7 @@ int ask_password_agent( final[sizeof(final)-9] = 'k'; if (rename(temp, final) < 0) { - r = log_error_errno(errno, "Failed to rename query file: %m"); + r = -errno; goto finish; } @@ -419,7 +557,6 @@ int ask_password_agent( t = now(CLOCK_MONOTONIC); if (until > 0 && until <= t) { - log_notice("Timed out"); r = -ETIME; goto finish; } @@ -429,12 +566,11 @@ int ask_password_agent( if (errno == EINTR) continue; - r = log_error_errno(errno, "poll() failed: %m"); + r = -errno; goto finish; } if (k <= 0) { - log_notice("Timed out"); r = -ETIME; goto finish; } @@ -445,7 +581,6 @@ int ask_password_agent( } if (pollfd[FD_SOCKET].revents != POLLIN) { - log_error("Unexpected poll() event."); r = -EIO; goto finish; } @@ -467,14 +602,14 @@ int ask_password_agent( errno == EINTR) continue; - r = log_error_errno(errno, "recvmsg() failed: %m"); + r = -errno; goto finish; } cmsg_close_all(&msghdr); if (n <= 0) { - log_error("Message too short"); + log_debug("Message too short"); continue; } @@ -482,84 +617,104 @@ int ask_password_agent( control.cmsghdr.cmsg_level != SOL_SOCKET || control.cmsghdr.cmsg_type != SCM_CREDENTIALS || control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) { - log_warning("Received message without credentials. Ignoring."); + log_debug("Received message without credentials. Ignoring."); continue; } ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr); if (ucred->uid != 0) { - log_warning("Got request from unprivileged user. Ignoring."); + log_debug("Got request from unprivileged user. Ignoring."); continue; } if (passphrase[0] == '+') { - char **l; - + /* An empty message refers to the empty password */ if (n == 1) l = strv_new("", NULL); else l = strv_parse_nulstr(passphrase+1, n-1); - /* An empty message refers to the empty password */ - + memory_erase(passphrase, n); if (!l) { r = -ENOMEM; goto finish; } if (strv_length(l) <= 0) { - strv_free(l); - log_error("Invalid packet"); + l = strv_free(l); + log_debug("Invalid packet"); continue; } - *_passphrases = l; + break; + } - } else if (passphrase[0] == '-') { + if (passphrase[0] == '-') { r = -ECANCELED; goto finish; - } else { - log_error("Invalid packet"); - continue; } - break; + log_debug("Invalid packet"); } + if (keyname) + (void) add_to_keyring_and_log(keyname, flags, l); + + *ret = l; + l = NULL; r = 0; finish: if (socket_name) - unlink(socket_name); + (void) unlink(socket_name); - unlink(temp); + (void) unlink(temp); if (final[0]) - unlink(final); + (void) unlink(final); assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0); - return r; } -int ask_password_auto(const char *message, const char *icon, const char *id, - usec_t until, bool accept_cached, char ***_passphrases) { - assert(message); - assert(_passphrases); +int ask_password_auto( + const char *message, + const char *icon, + const char *id, + const char *keyname, + usec_t until, + AskPasswordFlags flags, + char ***ret) { - if (isatty(STDIN_FILENO)) { - int r; - char *s = NULL, **l = NULL; + int r; - r = ask_password_tty(message, until, false, NULL, &s); - if (r < 0) + assert(ret); + + if ((flags & ASK_PASSWORD_ACCEPT_CACHED) && keyname) { + r = ask_password_keyring(keyname, flags, ret); + if (r != -ENOKEY) return r; + } - r = strv_consume(&l, s); + if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) { + char *s = NULL, **l = NULL; + + r = ask_password_tty(message, keyname, until, flags, NULL, &s); if (r < 0) return r; - *_passphrases = l; - return r; - } else - return ask_password_agent(message, icon, id, until, false, accept_cached, _passphrases); + r = strv_push(&l, s); + if (r < 0) { + string_erase(s); + free(s); + return -ENOMEM; + } + + *ret = l; + return 0; + } + + if (!(flags & ASK_PASSWORD_NO_AGENT)) + return ask_password_agent(message, icon, id, keyname, until, flags, ret); + + return -EUNATCH; } diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index 0954e072be..913cad9f8a 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -21,11 +21,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - -int ask_password_tty(const char *message, usec_t until, bool echo, const char *flag_file, char **_passphrase); - -int ask_password_agent(const char *message, const char *icon, const char *id, - usec_t until, bool echo, bool accept_cached, char ***_passphrases); - -int ask_password_auto(const char *message, const char *icon, const char *id, - usec_t until, bool accept_cached, char ***_passphrases); +#include <stdbool.h> + +#include "time-util.h" + +typedef enum AskPasswordFlags { + ASK_PASSWORD_ACCEPT_CACHED = 1, + ASK_PASSWORD_PUSH_CACHE = 2, + ASK_PASSWORD_ECHO = 4, /* show the password literally while reading, instead of "*" */ + ASK_PASSWORD_SILENT = 8, /* do no show any password at all while reading */ + ASK_PASSWORD_NO_TTY = 16, + ASK_PASSWORD_NO_AGENT = 32, +} AskPasswordFlags; + +int ask_password_tty(const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char **ret); +int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret); +int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret); +int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret); diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c index ab6fc171b0..e605490c32 100644 --- a/src/shared/base-filesystem.c +++ b/src/shared/base-filesystem.c @@ -20,13 +20,18 @@ ***/ #include <errno.h> -#include <sys/stat.h> #include <stdlib.h> +#include <sys/stat.h> #include <unistd.h> +#include "alloc-util.h" #include "base-filesystem.h" +#include "fd-util.h" #include "log.h" #include "macro.h" +#include "string-util.h" +#include "umask-util.h" +#include "user-util.h" #include "util.h" typedef struct BaseFilesystem { @@ -34,12 +39,13 @@ typedef struct BaseFilesystem { mode_t mode; const char *target; const char *exists; + bool ignore_failure; } BaseFilesystem; static const BaseFilesystem table[] = { { "bin", 0, "usr/bin\0", NULL }, { "lib", 0, "usr/lib\0", NULL }, - { "root", 0755, NULL, NULL }, + { "root", 0755, NULL, NULL, true }, { "sbin", 0, "usr/sbin\0", NULL }, { "usr", 0755, NULL, NULL }, { "var", 0755, NULL, NULL }, @@ -104,8 +110,13 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) { RUN_WITH_UMASK(0000) r = mkdirat(fd, table[i].dir, table[i].mode); - if (r < 0 && errno != EEXIST) - return log_error_errno(errno, "Failed to create directory at %s/%s: %m", root, table[i].dir); + if (r < 0 && errno != EEXIST) { + log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno, + "Failed to create directory at %s/%s: %m", root, table[i].dir); + + if (!table[i].ignore_failure) + return -errno; + } if (uid != UID_INVALID || gid != UID_INVALID) { if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0) diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 16b17c2c82..a13991a960 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -21,27 +21,39 @@ #include <sys/socket.h> +#include "sd-bus.h" #include "sd-daemon.h" #include "sd-event.h" -#include "sd-bus.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-internal.h" #include "bus-label.h" #include "bus-message.h" +#include "bus-util.h" #include "cgroup-util.h" #include "def.h" +#include "env-util.h" +#include "escape.h" +#include "fd-util.h" #include "macro.h" #include "missing.h" +#include "parse-util.h" #include "path-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "rlimit-util.h" #include "set.h" #include "signal-util.h" +#include "stdio-util.h" +#include "string-util.h" #include "strv.h" +#include "syslog-util.h" #include "unit-name.h" +#include "user-util.h" +#include "utf8.h" #include "util.h" -#include "bus-util.h" - static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { sd_event *e = userdata; @@ -574,14 +586,14 @@ int bus_check_peercred(sd_bus *c) { return 1; } -int bus_open_system_systemd(sd_bus **_bus) { +int bus_connect_system_systemd(sd_bus **_bus) { _cleanup_bus_unref_ sd_bus *bus = NULL; int r; assert(_bus); if (geteuid() != 0) - return sd_bus_open_system(_bus); + return sd_bus_default_system(_bus); /* If we are root and kdbus is not available, then let's talk * directly to the system instance, instead of going via the @@ -616,7 +628,7 @@ int bus_open_system_systemd(sd_bus **_bus) { r = sd_bus_start(bus); if (r < 0) - return sd_bus_open_system(_bus); + return sd_bus_default_system(_bus); r = bus_check_peercred(bus); if (r < 0) @@ -628,7 +640,7 @@ int bus_open_system_systemd(sd_bus **_bus) { return 0; } -int bus_open_user_systemd(sd_bus **_bus) { +int bus_connect_user_systemd(sd_bus **_bus) { _cleanup_bus_unref_ sd_bus *bus = NULL; _cleanup_free_ char *ee = NULL; const char *e; @@ -658,7 +670,7 @@ int bus_open_user_systemd(sd_bus **_bus) { e = secure_getenv("XDG_RUNTIME_DIR"); if (!e) - return sd_bus_open_user(_bus); + return sd_bus_default_user(_bus); ee = bus_address_escape(e); if (!ee) @@ -674,7 +686,7 @@ int bus_open_user_systemd(sd_bus **_bus) { r = sd_bus_start(bus); if (r < 0) - return sd_bus_open_user(_bus); + return sd_bus_default_user(_bus); r = bus_check_peercred(bus); if (r < 0) @@ -1209,7 +1221,7 @@ int bus_map_all_properties( return bus_message_map_all_properties(m, map, userdata); } -int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) { +int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus) { int r; assert(transport >= 0); @@ -1244,7 +1256,7 @@ int bus_open_transport(BusTransport transport, const char *host, bool user, sd_b return r; } -int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) { +int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus) { int r; assert(transport >= 0); @@ -1258,9 +1270,9 @@ int bus_open_transport_systemd(BusTransport transport, const char *host, bool us case BUS_TRANSPORT_LOCAL: if (user) - r = bus_open_user_systemd(bus); + r = bus_connect_user_systemd(bus); else - r = bus_open_system_systemd(bus); + r = bus_connect_system_systemd(bus); break; @@ -1416,6 +1428,17 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return bus_log_create_error(r); return 0; + } else if (streq(field, "EnvironmentFile")) { + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "EnvironmentFiles"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "v", "a(sb)", 1, + eq[0] == '-' ? eq + 1 : eq, + eq[0] == '-'); + if (r < 0) + return r; + return 0; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); @@ -1426,7 +1449,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", - "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges")) { + "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", + "SyslogLevelPrefix", "Delegate")) { r = parse_boolean(eq); if (r < 0) { @@ -1493,10 +1517,33 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath", "StandardInput", "StandardOutput", "StandardError", "Description", "Slice", "Type", "WorkingDirectory", - "RootDirectory")) + "RootDirectory", "SyslogIdentifier", "ProtectSystem", + "ProtectHome")) r = sd_bus_message_append(m, "v", "s", eq); - else if (streq(field, "DeviceAllow")) { + else if (streq(field, "SyslogLevel")) { + int level; + + level = log_level_from_string(eq); + if (level < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", level); + + } else if (streq(field, "SyslogFacility")) { + int facility; + + facility = log_facility_unshifted_from_string(eq); + if (facility < 0) { + log_error("Failed to parse %s value %s.", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", facility); + + } else if (streq(field, "DeviceAllow")) { if (isempty(eq)) r = sd_bus_message_append(m, "v", "a(ss)", 0); @@ -1608,8 +1655,44 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "i", i); } else if (streq(field, "Environment")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE); + if (r < 0) { + log_error("Failed to parse Environment value %s", eq); + return -EINVAL; + } + if (r == 0) + break; - r = sd_bus_message_append(m, "v", "as", 1, eq); + if (!env_assignment_is_valid(word)) { + log_error("Invalid environment assignment: %s", eq); + return -EINVAL; + } + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); } else if (streq(field, "KillSignal")) { int sig; @@ -1632,6 +1715,113 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen } r = sd_bus_message_append(m, "v", "t", u); + } else if (streq(field, "TimerSlackNSec")) { + nsec_t n; + + r = parse_nsec(eq, &n); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "t", n); + } else if (streq(field, "OOMScoreAdjust")) { + int oa; + + r = safe_atoi(eq, &oa); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + if (!oom_score_adjust_is_valid(oa)) { + log_error("OOM score adjust value out of range"); + return -EINVAL; + } + + r = sd_bus_message_append(m, "v", "i", oa); + } else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + int offset; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + if (r == 0) + break; + + if (!utf8_is_valid(word)) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + offset = word[0] == '-'; + if (!path_is_absolute(word + offset)) { + log_error("Failed to parse %s value %s", field, eq); + return -EINVAL; + } + + path_kill_slashes(word + offset); + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + + } else if (streq(field, "RuntimeDirectory")) { + const char *p; + + r = sd_bus_message_open_container(m, 'v', "as"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "s"); + if (r < 0) + return bus_log_create_error(r); + + p = eq; + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value %s", field, eq); + + if (r == 0) + break; + + r = sd_bus_message_append_basic(m, 's', word); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); } else { log_error("Unknown assignment %s.", assignment); @@ -2137,3 +2327,42 @@ bool is_kdbus_available(void) { return ioctl(fd, KDBUS_CMD_BUS_MAKE, &cmd) >= 0; } + +int bus_property_get_rlimit( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + struct rlimit *rl; + uint64_t u; + rlim_t x; + + assert(bus); + assert(reply); + assert(userdata); + + rl = *(struct rlimit**) userdata; + if (rl) + x = rl->rlim_max; + else { + struct rlimit buf = {}; + int z; + + z = rlimit_from_string(strstr(property, "Limit")); + assert(z >= 0); + + getrlimit(z, &buf); + x = buf.rlim_max; + } + + /* rlim_t might have different sizes, let's map + * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on + * all archs */ + u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x; + + return sd_bus_message_append(reply, "t", u); +} diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index d2b2d701ce..3925c10fde 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -21,10 +21,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-event.h" #include "sd-bus.h" +#include "sd-event.h" + #include "hashmap.h" #include "install.h" +#include "string-util.h" #include "time-util.h" typedef enum BusTransport { @@ -65,11 +67,11 @@ int bus_test_polkit(sd_bus_message *call, int capability, const char *action, co int bus_verify_polkit_async(sd_bus_message *call, int capability, const char *action, const char **details, bool interactive, uid_t good_user, Hashmap **registry, sd_bus_error *error); void bus_verify_polkit_async_registry_free(Hashmap *registry); -int bus_open_system_systemd(sd_bus **_bus); -int bus_open_user_systemd(sd_bus **_bus); +int bus_connect_system_systemd(sd_bus **_bus); +int bus_connect_user_systemd(sd_bus **_bus); -int bus_open_transport(BusTransport transport, const char *host, bool user, sd_bus **bus); -int bus_open_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus); +int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **bus); +int bus_connect_transport_systemd(BusTransport transport, const char *host, bool user, sd_bus **bus); int bus_print_property(const char *name, sd_bus_message *property, bool all); int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all); @@ -200,3 +202,5 @@ int bus_path_decode_unique(const char *path, const char *prefix, char **ret_send bool is_kdbus_wanted(void); bool is_kdbus_available(void); + +int bus_property_get_rlimit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 31b4f6c684..129ffc7056 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -19,19 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <string.h> #include <dirent.h> #include <errno.h> +#include <stdio.h> +#include <string.h> -#include "util.h" +#include "alloc-util.h" +#include "cgroup-show.h" +#include "cgroup-util.h" +#include "fd-util.h" #include "formats-util.h" -#include "process-util.h" +#include "locale-util.h" #include "macro.h" #include "path-util.h" -#include "cgroup-util.h" -#include "cgroup-show.h" +#include "process-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" static int compare(const void *a, const void *b) { const pid_t *p = a, *q = b; diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c index d1cdb151b2..835fe52423 100644 --- a/src/shared/clean-ipc.c +++ b/src/shared/clean-ipc.c @@ -19,19 +19,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <dirent.h> +#include <fcntl.h> +#include <mqueue.h> #include <sys/ipc.h> -#include <sys/shm.h> -#include <sys/sem.h> #include <sys/msg.h> +#include <sys/sem.h> +#include <sys/shm.h> #include <sys/stat.h> -#include <fcntl.h> -#include <dirent.h> -#include <mqueue.h> -#include "util.h" +#include "clean-ipc.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "string-util.h" #include "strv.h" -#include "clean-ipc.h" +#include "util.h" +#include "dirent-util.h" static int clean_sysvipc_shm(uid_t delete_uid) { _cleanup_fclose_ FILE *f = NULL; @@ -44,8 +48,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /proc/sysvipc/shm: %m"); } FOREACH_LINE(line, f, goto fail) { @@ -87,8 +90,7 @@ static int clean_sysvipc_shm(uid_t delete_uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /proc/sysvipc/shm: %m"); } static int clean_sysvipc_sem(uid_t delete_uid) { @@ -102,8 +104,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /proc/sysvipc/sem: %m"); } FOREACH_LINE(line, f, goto fail) { @@ -140,8 +141,7 @@ static int clean_sysvipc_sem(uid_t delete_uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /proc/sysvipc/sem: %m"); } static int clean_sysvipc_msg(uid_t delete_uid) { @@ -155,8 +155,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /proc/sysvipc/msg: %m"); } FOREACH_LINE(line, f, goto fail) { @@ -194,8 +193,7 @@ static int clean_sysvipc_msg(uid_t delete_uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /proc/sysvipc/msg: %m"); } static int clean_posix_shm_internal(DIR *dir, uid_t uid) { @@ -273,8 +271,7 @@ static int clean_posix_shm(uid_t uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /dev/shm: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /dev/shm: %m"); } return clean_posix_shm_internal(dir, uid); @@ -290,8 +287,7 @@ static int clean_posix_mq(uid_t uid) { if (errno == ENOENT) return 0; - log_warning_errno(errno, "Failed to open /dev/mqueue: %m"); - return -errno; + return log_warning_errno(errno, "Failed to open /dev/mqueue: %m"); } FOREACH_DIRENT(de, dir, goto fail) { @@ -330,8 +326,7 @@ static int clean_posix_mq(uid_t uid) { return ret; fail: - log_warning_errno(errno, "Failed to read /dev/mqueue: %m"); - return -errno; + return log_warning_errno(errno, "Failed to read /dev/mqueue: %m"); } int clean_ipc(uid_t uid) { diff --git a/src/shared/condition.c b/src/shared/condition.c index 1d7dd49e04..a69719116c 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -19,25 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> +#include <fnmatch.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> -#include <fnmatch.h> #include "sd-id128.h" -#include "util.h" -#include "virt.h" -#include "path-util.h" -#include "architecture.h" -#include "smack-util.h" + +#include "alloc-util.h" #include "apparmor-util.h" -#include "ima-util.h" -#include "selinux-util.h" -#include "audit.h" +#include "architecture.h" +#include "audit-util.h" #include "cap-list.h" -#include "hostname-util.h" #include "condition.h" +#include "extract-word.h" +#include "fd-util.h" +#include "glob-util.h" +#include "hostname-util.h" +#include "ima-util.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" +#include "selinux-util.h" +#include "smack-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" +#include "virt.h" Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { Condition *c; diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 946eac6823..3f8eaf7d9a 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -19,21 +19,29 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <stdio.h> #include <errno.h> +#include <stdio.h> #include <stdlib.h> +#include <string.h> #include "sd-messages.h" + +#include "alloc-util.h" #include "conf-files.h" -#include "util.h" -#include "macro.h" -#include "strv.h" +#include "conf-parser.h" +#include "fd-util.h" +#include "fs-util.h" #include "log.h" -#include "utf8.h" +#include "macro.h" +#include "parse-util.h" #include "path-util.h" +#include "process-util.h" #include "signal-util.h" -#include "conf-parser.h" +#include "string-util.h" +#include "strv.h" +#include "syslog-util.h" +#include "utf8.h" +#include "util.h" int config_item_table_lookup( const void *table, @@ -147,8 +155,7 @@ static int next_assignment(const char *unit, /* Warn about unknown non-extension fields. */ if (!relaxed && !startswith(lvalue, "X-")) - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, - "Unknown lvalue '%s' in section '%s'", lvalue, section); + log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section); return 0; } @@ -196,8 +203,7 @@ static int parse_line(const char* unit, * Support for them should be eventually removed. */ if (!allow_include) { - log_syntax(unit, LOG_ERR, filename, line, EBADMSG, - ".include not allowed here. Ignoring."); + log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring."); return 0; } @@ -216,8 +222,7 @@ static int parse_line(const char* unit, assert(k > 0); if (l[k-1] != ']') { - log_syntax(unit, LOG_ERR, filename, line, EBADMSG, - "Invalid section header '%s'", l); + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid section header '%s'", l); return -EBADMSG; } @@ -228,8 +233,7 @@ static int parse_line(const char* unit, if (sections && !nulstr_contains(sections, n)) { if (!relaxed && !startswith(n, "X-")) - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, - "Unknown section '%s'. Ignoring.", n); + log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n); free(n); *section = mfree(*section); @@ -248,16 +252,15 @@ static int parse_line(const char* unit, if (sections && !*section) { if (!relaxed && !*section_ignored) - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, - "Assignment outside of section. Ignoring."); + log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring."); return 0; } e = strchr(l, '='); if (!e) { - log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Missing '='."); - return -EBADMSG; + log_syntax(unit, LOG_WARNING, filename, line, 0, "Missing '='."); + return -EINVAL; } *e = 0; @@ -420,16 +423,17 @@ int config_parse_many(const char *conf_file, } #define DEFINE_PARSER(type, vartype, conv_func) \ - int config_parse_##type(const char *unit, \ - const char *filename, \ - unsigned line, \ - const char *section, \ - unsigned section_line, \ - const char *lvalue, \ - int ltype, \ - const char *rvalue, \ - void *data, \ - void *userdata) { \ + int config_parse_##type( \ + const char *unit, \ + const char *filename, \ + unsigned line, \ + const char *section, \ + unsigned section_line, \ + const char *lvalue, \ + int ltype, \ + const char *rvalue, \ + void *data, \ + void *userdata) { \ \ vartype *i = data; \ int r; \ @@ -441,21 +445,23 @@ int config_parse_many(const char *conf_file, \ r = conv_func(rvalue, i); \ if (r < 0) \ - log_syntax(unit, LOG_ERR, filename, line, -r, \ + log_syntax(unit, LOG_ERR, filename, line, r, \ "Failed to parse %s value, ignoring: %s", \ #type, rvalue); \ \ return 0; \ - } - -DEFINE_PARSER(int, int, safe_atoi) -DEFINE_PARSER(long, long, safe_atoli) -DEFINE_PARSER(uint32, uint32_t, safe_atou32) -DEFINE_PARSER(uint64, uint64_t, safe_atou64) -DEFINE_PARSER(unsigned, unsigned, safe_atou) -DEFINE_PARSER(double, double, safe_atod) -DEFINE_PARSER(nsec, nsec_t, parse_nsec) -DEFINE_PARSER(sec, usec_t, parse_sec) + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +DEFINE_PARSER(int, int, safe_atoi); +DEFINE_PARSER(long, long, safe_atoli); +DEFINE_PARSER(uint32, uint32_t, safe_atou32); +DEFINE_PARSER(uint64, uint64_t, safe_atou64); +DEFINE_PARSER(unsigned, unsigned, safe_atou); +DEFINE_PARSER(double, double, safe_atod); +DEFINE_PARSER(nsec, nsec_t, parse_nsec); +DEFINE_PARSER(sec, usec_t, parse_sec); +DEFINE_PARSER(mode, mode_t, parse_mode); int config_parse_iec_size(const char* unit, const char *filename, @@ -479,7 +485,7 @@ int config_parse_iec_size(const char* unit, r = parse_size(rvalue, 1024, &v); if (r < 0 || (uint64_t) (size_t) v != v) { - log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue); return 0; } @@ -509,7 +515,7 @@ int config_parse_si_size(const char* unit, r = parse_size(rvalue, 1000, &v); if (r < 0 || (uint64_t) (size_t) v != v) { - log_syntax(unit, LOG_ERR, filename, line, r < 0 ? r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse size value, ignoring: %s", rvalue); return 0; } @@ -564,8 +570,7 @@ int config_parse_bool(const char* unit, k = parse_boolean(rvalue); if (k < 0) { - log_syntax(unit, LOG_ERR, filename, line, -k, - "Failed to parse boolean value, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse boolean value, ignoring: %s", rvalue); return 0; } @@ -626,7 +631,7 @@ int config_parse_string( assert(data); if (!utf8_is_valid(rvalue)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); return 0; } @@ -664,12 +669,12 @@ int config_parse_path( assert(data); if (!utf8_is_valid(rvalue)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); return 0; } if (!path_is_absolute(rvalue)) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Not an absolute path, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue); return 0; } @@ -730,7 +735,7 @@ int config_parse_strv(const char *unit, return log_oom(); if (!utf8_is_valid(n)) { - log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue); + log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue); free(n); continue; } @@ -740,35 +745,7 @@ int config_parse_strv(const char *unit, return log_oom(); } if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); - - return 0; -} - -int config_parse_mode( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - mode_t *m = data; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (parse_mode(rvalue, m) < 0) { - log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse mode value, ignoring: %s", rvalue); - return 0; - } + log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); return 0; } @@ -795,7 +772,7 @@ int config_parse_log_facility( x = log_facility_unshifted_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log facility, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue); return 0; } @@ -826,7 +803,7 @@ int config_parse_log_level( x = log_level_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse log level, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue); return 0; } @@ -855,7 +832,7 @@ int config_parse_signal( r = signal_from_string_try_harder(rvalue); if (r <= 0) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse signal name, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue); return 0; } @@ -884,7 +861,7 @@ int config_parse_personality( p = personality_from_string(rvalue); if (p == PERSONALITY_INVALID) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Failed to parse personality, ignoring: %s", rvalue); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse personality, ignoring: %s", rvalue); return 0; } diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 4efed138c9..fb0234baae 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -123,13 +123,6 @@ int config_parse_log_level(const char *unit, const char *filename, unsigned line int config_parse_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_personality(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -#define log_invalid_utf8(unit, level, config_file, config_line, error, rvalue) \ - do { \ - _cleanup_free_ char *_p = utf8_escape_invalid(rvalue); \ - log_syntax(unit, level, config_file, config_line, error, \ - "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ - } while(false) - #define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \ int function(const char *unit, \ const char *filename, \ diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index 25ad918b85..ad3c17d5bd 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -23,10 +23,12 @@ #include <stdlib.h> #include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "dev-setup.h" #include "label.h" #include "path-util.h" -#include "dev-setup.h" +#include "user-util.h" +#include "util.h" int dev_setup(const char *prefix, uid_t uid, gid_t gid) { static const char symlinks[] = diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 6dc04d51e4..7af15e0098 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -24,7 +24,11 @@ #include <stringprep.h> #endif +#include "alloc-util.h" #include "dns-domain.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "string-util.h" int dns_label_unescape(const char **name, char *dest, size_t sz) { const char *n; @@ -379,9 +383,8 @@ int dns_name_concat(const char *a, const char *b, char **_ret) { return 0; } -unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) { +void dns_name_hash_func(const void *s, struct siphash *state) { const char *p = s; - unsigned long ul = hash_key[0]; int r; assert(p); @@ -400,13 +403,17 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_ if (k > 0) r = k; + if (r == 0) + break; + label[r] = 0; ascii_strlower(label); - ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key); + string_hash_func(label, state); } - return ul; + /* enforce that all names are terminated by the empty label */ + string_hash_func("", state); } int dns_name_compare_func(const void *a, const void *b) { diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 8e73d9c20f..1f0d242c18 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -54,7 +54,7 @@ static inline int dns_name_is_valid(const char *s) { return 1; } -unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]); +void dns_name_hash_func(const void *s, struct siphash *state); int dns_name_compare_func(const void *a, const void *b); extern const struct hash_ops dns_name_hash_ops; diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 963d05d32e..0d44401cc2 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -19,12 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "conf-files.h" #include "dropin.h" -#include "util.h" -#include "strv.h" -#include "mkdir.h" +#include "escape.h" +#include "fd-util.h" #include "fileio-label.h" -#include "conf-files.h" +#include "mkdir.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" int drop_in_file(const char *dir, const char *unit, unsigned level, const char *name, char **_p, char **_q) { @@ -78,7 +83,7 @@ int write_drop_in(const char *dir, const char *unit, unsigned level, if (r < 0) return r; - mkdir_p(p, 0755); + (void) mkdir_p(p, 0755); return write_string_file_atomic_label(q, data); } @@ -132,8 +137,7 @@ static int iterate_dir( if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open directory %s: %m", path); - return -errno; + return log_error_errno(errno, "Failed to open directory %s: %m", path); } for (;;) { diff --git a/src/shared/efivars.c b/src/shared/efivars.c index f087c2a566..86bb0b57c3 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -23,10 +23,16 @@ #include <string.h> #include <fcntl.h> -#include "util.h" +#include "alloc-util.h" +#include "dirent-util.h" +#include "efivars.h" +#include "fd-util.h" +#include "io-util.h" +#include "parse-util.h" +#include "stdio-util.h" #include "utf8.h" +#include "util.h" #include "virt.h" -#include "efivars.h" #ifdef ENABLE_EFI diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index effc6e8e70..e178287872 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -27,8 +27,9 @@ #include <linux/netfilter/xt_addrtype.h> #include <libiptc/libiptc.h> -#include "util.h" +#include "alloc-util.h" #include "firewall-util.h" +#include "util.h" DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free); diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index e231a0ff80..eb2845cddf 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -19,10 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "device-nodes.h" #include "fstab-util.h" +#include "mount-util.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" #include "strv.h" #include "util.h" +bool fstab_is_mount_point(const char *mount) { + _cleanup_endmntent_ FILE *f = NULL; + struct mntent *m; + + f = setmntent("/etc/fstab", "r"); + if (!f) + return false; + + while ((m = getmntent(f))) + if (path_equal(m->mnt_dir, mount)) + return true; + + return false; +} + int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered) { const char *name, *n = NULL, *x; @@ -178,3 +199,60 @@ int fstab_find_pri(const char *options, int *ret) { *ret = (int) pri; return 1; } + +static char *unquote(const char *s, const char* quotes) { + size_t l; + assert(s); + + /* This is rather stupid, simply removes the heading and + * trailing quotes if there is one. Doesn't care about + * escaping or anything. + * + * DON'T USE THIS FOR NEW CODE ANYMORE!*/ + + l = strlen(s); + if (l < 2) + return strdup(s); + + if (strchr(quotes, s[0]) && s[l-1] == s[0]) + return strndup(s+1, l-2); + + return strdup(s); +} + +static char *tag_to_udev_node(const char *tagvalue, const char *by) { + _cleanup_free_ char *t = NULL, *u = NULL; + size_t enc_len; + + u = unquote(tagvalue, QUOTES); + if (!u) + return NULL; + + enc_len = strlen(u) * 4 + 1; + t = new(char, enc_len); + if (!t) + return NULL; + + if (encode_devnode_name(u, t, enc_len) < 0) + return NULL; + + return strjoin("/dev/disk/by-", by, "/", t, NULL); +} + +char *fstab_node_to_udev_node(const char *p) { + assert(p); + + if (startswith(p, "LABEL=")) + return tag_to_udev_node(p+6, "label"); + + if (startswith(p, "UUID=")) + return tag_to_udev_node(p+5, "uuid"); + + if (startswith(p, "PARTUUID=")) + return tag_to_udev_node(p+9, "partuuid"); + + if (startswith(p, "PARTLABEL=")) + return tag_to_udev_node(p+10, "partlabel"); + + return strdup(p); +} diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h index 387c562a96..5ebea44019 100644 --- a/src/shared/fstab-util.h +++ b/src/shared/fstab-util.h @@ -23,10 +23,12 @@ #include <stdbool.h> #include <stddef.h> + #include "macro.h" -int fstab_filter_options(const char *opts, const char *names, - const char **namefound, char **value, char **filtered); +bool fstab_is_mount_point(const char *mount); + +int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered); int fstab_extract_values(const char *opts, const char *name, char ***values); @@ -48,3 +50,5 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no return opt == yes_no; } + +char *fstab_node_to_udev_node(const char *p); diff --git a/src/shared/generator.c b/src/shared/generator.c index e58bbea77c..cb4ebc606e 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -21,21 +21,25 @@ #include <unistd.h> -#include "util.h" -#include "special.h" -#include "mkdir.h" -#include "unit-name.h" +#include "alloc-util.h" +#include "dropin.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "fstab-util.h" #include "generator.h" +#include "mkdir.h" +#include "mount-util.h" #include "path-util.h" -#include "fstab-util.h" -#include "fileio.h" -#include "dropin.h" +#include "special.h" +#include "string-util.h" +#include "unit-name.h" +#include "util.h" static int write_fsck_sysroot_service(const char *dir, const char *what) { - const char *unit; - _cleanup_free_ char *device = NULL; - _cleanup_free_ char *escaped; + _cleanup_free_ char *device = NULL, *escaped = NULL; _cleanup_fclose_ FILE *f = NULL; + const char *unit; int r; escaped = cescape(what); @@ -101,16 +105,17 @@ int generator_write_fsck_deps( if (!isempty(fstype) && !streq(fstype, "auto")) { r = fsck_exists(fstype); - if (r == -ENOENT) { + if (r < 0) + log_warning_errno(r, "Checking was requested for %s, but couldn't detect if fsck.%s may be used, proceeding: %m", what, fstype); + else if (r == 0) { /* treat missing check as essentially OK */ - log_debug_errno(r, "Checking was requested for %s, but fsck.%s does not exist: %m", what, fstype); + log_debug("Checking was requested for %s, but fsck.%s does not exist.", what, fstype); return 0; - } else if (r < 0) - return log_warning_errno(r, "Checking was requested for %s, but fsck.%s cannot be used: %m", what, fstype); + } } if (path_equal(where, "/")) { - char *lnk; + const char *lnk; lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service"); diff --git a/src/shared/import-util.c b/src/shared/import-util.c index 001a8a37e8..ddc8c00a2d 100644 --- a/src/shared/import-util.c +++ b/src/shared/import-util.c @@ -19,8 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" +#include "btrfs-util.h" #include "import-util.h" +#include "path-util.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" int import_url_last_component(const char *url, char **ret) { const char *e, *p; @@ -201,3 +206,29 @@ bool dkr_id_is_valid(const char *id) { return true; } + +int import_assign_pool_quota_and_warn(const char *path) { + int r; + + r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true); + if (r == -ENOTTY) { + log_debug_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, as directory is not on btrfs or not a subvolume. Ignoring."); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines: %m"); + if (r > 0) + log_info("Set up default quota hierarchy for /var/lib/machines."); + + r = btrfs_subvol_auto_qgroup(path, 0, true); + if (r == -ENOTTY) { + log_debug_errno(r, "Failed to set up quota hierarchy for %s, as directory is not on btrfs or not a subvolume. Ignoring.", path); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path); + if (r > 0) + log_info("Set up default quota hierarchy for %s.", path); + + return 0; +} diff --git a/src/shared/import-util.h b/src/shared/import-util.h index 7bf7d4ca40..9120a5119f 100644 --- a/src/shared/import-util.h +++ b/src/shared/import-util.h @@ -47,3 +47,5 @@ bool dkr_id_is_valid(const char *id); bool dkr_ref_is_valid(const char *ref); bool dkr_digest_is_valid(const char *digest); #define dkr_tag_is_valid(tag) filename_is_valid(tag) + +int import_assign_pool_quota_and_warn(const char *path); diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index cbe984d2fb..e1cb5d27ff 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -21,11 +21,13 @@ #include <stdlib.h> +#include "alloc-util.h" +#include "formats-util.h" +#include "install-printf.h" #include "specifier.h" #include "unit-name.h" +#include "user-util.h" #include "util.h" -#include "install-printf.h" -#include "formats-util.h" static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { UnitFileInstallInfo *i = userdata; diff --git a/src/shared/install.c b/src/shared/install.c index 3d2b5ae77f..b7d1d22505 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -21,23 +21,30 @@ #include <errno.h> #include <fcntl.h> -#include <unistd.h> -#include <string.h> #include <fnmatch.h> +#include <string.h> +#include <unistd.h> -#include "util.h" -#include "mkdir.h" +#include "alloc-util.h" +#include "conf-files.h" +#include "conf-parser.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "hashmap.h" -#include "set.h" -#include "path-util.h" +#include "install-printf.h" +#include "install.h" +#include "mkdir.h" #include "path-lookup.h" +#include "path-util.h" +#include "set.h" +#include "special.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "unit-name.h" -#include "install.h" -#include "conf-parser.h" -#include "conf-files.h" -#include "install-printf.h" -#include "special.h" +#include "util.h" typedef struct { OrderedHashmap *will_install; @@ -46,13 +53,12 @@ typedef struct { static int in_search_path(const char *path, char **search) { _cleanup_free_ char *parent = NULL; - int r; assert(path); - r = path_get_parent(path, &parent); - if (r < 0) - return r; + parent = dirname_malloc(path); + if (!parent) + return -ENOMEM; return strv_contains(search, parent); } @@ -923,8 +929,6 @@ static int config_parse_also( void *data, void *userdata) { - size_t l; - const char *word, *state; InstallContext *c = data; UnitFileInstallInfo *i = userdata; @@ -932,13 +936,18 @@ static int config_parse_also( assert(lvalue); assert(rvalue); - FOREACH_WORD_QUOTED(word, l, rvalue, state) { - _cleanup_free_ char *n; + for(;;) { + _cleanup_free_ char *n = NULL; int r; - n = strndup(word, l); - if (!n) - return -ENOMEM; + r = extract_first_word(&rvalue, &n, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse config %s, ignoring.", rvalue); + return 0; + } + + if (r == 0) + break; r = install_info_add(c, n, NULL); if (r < 0) @@ -948,9 +957,6 @@ static int config_parse_also( if (r < 0) return r; } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Trailing garbage, ignoring."); return 0; } diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index dbc07aa7ad..0313b0946f 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -19,25 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <time.h> #include <errno.h> -#include <sys/socket.h> -#include <string.h> #include <fcntl.h> +#include <string.h> +#include <sys/socket.h> +#include <time.h> -#include "logs-show.h" -#include "log.h" -#include "util.h" -#include "utf8.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "formats-util.h" #include "hashmap.h" +#include "hostname-util.h" +#include "io-util.h" #include "journal-internal.h" -#include "formats-util.h" +#include "log.h" +#include "logs-show.h" +#include "parse-util.h" #include "process-util.h" +#include "string-table.h" +#include "string-util.h" #include "terminal-util.h" -#include "hostname-util.h" +#include "utf8.h" +#include "util.h" -/* up to three lines (each up to 100 characters), - or 300 characters, whichever is less */ +/* up to three lines (each up to 100 characters) or 300 characters, whichever is less */ #define PRINT_LINE_THRESHOLD 3 #define PRINT_CHAR_THRESHOLD 300 diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 9c1e4d5e13..2c1da0a40d 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -23,15 +23,22 @@ #include <linux/fs.h> #include <sys/statfs.h> +#include "alloc-util.h" #include "btrfs-util.h" +#include "chattr-util.h" #include "copy.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fs-util.h" +#include "machine-image.h" #include "mkdir.h" #include "path-util.h" #include "rm-rf.h" +#include "string-table.h" +#include "string-util.h" #include "strv.h" #include "utf8.h" - -#include "machine-image.h" +#include "xattr-util.h" static const char image_search_path[] = "/var/lib/machines\0" @@ -176,11 +183,10 @@ static int image_make( return r; if (r) { BtrfsSubvolInfo info; - BtrfsQuotaInfo quota; /* It's a btrfs subvolume */ - r = btrfs_subvol_get_info_fd(fd, &info); + r = btrfs_subvol_get_info_fd(fd, 0, &info); if (r < 0) return r; @@ -195,13 +201,17 @@ static int image_make( if (r < 0) return r; - r = btrfs_subvol_get_quota_fd(fd, "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 41da820938..d149bc1722 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -21,17 +21,20 @@ #include <fcntl.h> #include <stdlib.h> -#include <unistd.h> #include <string.h> #include <sys/prctl.h> +#include <unistd.h> +#include "copy.h" +#include "fd-util.h" +#include "locale-util.h" +#include "macro.h" #include "pager.h" -#include "util.h" #include "process-util.h" -#include "macro.h" -#include "terminal-util.h" #include "signal-util.h" -#include "copy.h" +#include "string-util.h" +#include "terminal-util.h" +#include "util.h" static pid_t pager_pid = 0; @@ -48,24 +51,27 @@ noreturn static void pager_fallback(void) { } int pager_open(bool jump_to_end) { - int fd[2]; + _cleanup_close_pair_ int fd[2] = { -1, -1 }; const char *pager; pid_t parent_pid; - int r; if (pager_pid > 0) return 1; - if ((pager = getenv("SYSTEMD_PAGER")) || (pager = getenv("PAGER"))) - if (!*pager || streq(pager, "cat")) - return 0; - if (!on_tty()) return 0; + pager = getenv("SYSTEMD_PAGER"); + if (!pager) + pager = getenv("PAGER"); + + /* If the pager is explicitly turned off, honour it */ + if (pager && (pager[0] == 0 || streq(pager, "cat"))) + return 0; + /* Determine and cache number of columns before we spawn the * pager so that we get the value from the actual tty */ - columns(); + (void) columns(); if (pipe(fd) < 0) return log_error_errno(errno, "Failed to create pager pipe: %m"); @@ -73,11 +79,8 @@ int pager_open(bool jump_to_end) { parent_pid = getpid(); pager_pid = fork(); - if (pager_pid < 0) { - r = log_error_errno(errno, "Failed to fork pager: %m"); - safe_close_pair(fd); - return r; - } + if (pager_pid < 0) + return log_error_errno(errno, "Failed to fork pager: %m"); /* In the child start the pager */ if (pager_pid == 0) { @@ -86,7 +89,7 @@ int pager_open(bool jump_to_end) { (void) reset_all_signal_handlers(); (void) reset_signal_mask(); - dup2(fd[0], STDIN_FILENO); + (void) dup2(fd[0], STDIN_FILENO); safe_close_pair(fd); /* Initialize a good set of less options */ @@ -141,7 +144,6 @@ int pager_open(bool jump_to_end) { if (dup2(fd[1], STDERR_FILENO) < 0) return log_error_errno(errno, "Failed to duplicate pager pipe: %m"); - safe_close_pair(fd); return 1; } diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index d803bbe07e..d71f379e76 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -24,11 +24,13 @@ #include <string.h> #include <errno.h> +#include "alloc-util.h" #include "util.h" #include "strv.h" #include "path-util.h" -#include "path-lookup.h" #include "install.h" +#include "string-util.h" +#include "path-lookup.h" int user_config_home(char **config_home) { const char *e; @@ -181,7 +183,7 @@ static char** user_dirs( if (strv_extend_strv_concat(&res, config_dirs, "/systemd/user") < 0) return NULL; - if (strv_extend_strv(&res, (char**) config_unit_paths) < 0) + if (strv_extend_strv(&res, (char**) config_unit_paths, false) < 0) return NULL; if (runtime_dir) @@ -203,14 +205,14 @@ static char** user_dirs( if (strv_extend_strv_concat(&res, data_dirs, "/systemd/user") < 0) return NULL; - if (strv_extend_strv(&res, (char**) data_unit_paths) < 0) + if (strv_extend_strv(&res, (char**) data_unit_paths, false) < 0) return NULL; if (generator_late) if (strv_extend(&res, generator_late) < 0) return NULL; - if (!path_strv_make_absolute_cwd(res)) + if (path_strv_make_absolute_cwd(res) < 0) return NULL; tmp = res; @@ -244,6 +246,7 @@ int lookup_paths_init( const char *e; bool append = false; /* Add items from SYSTEMD_UNIT_PATH before normal directories */ + int r; assert(p); @@ -259,9 +262,9 @@ int lookup_paths_init( /* FIXME: empty components in other places should be * rejected. */ - p->unit_path = path_split_and_make_absolute(e); - if (!p->unit_path) - return -ENOMEM; + r = path_split_and_make_absolute(e, &p->unit_path); + if (r < 0) + return r; } else p->unit_path = NULL; @@ -269,7 +272,6 @@ int lookup_paths_init( /* Let's figure something out. */ _cleanup_strv_free_ char **unit_path; - int r; /* For the user units we include share/ in the search * path in order to comply with the XDG basedir spec. @@ -318,7 +320,7 @@ int lookup_paths_init( if (!unit_path) return -ENOMEM; - r = strv_extend_strv(&p->unit_path, unit_path); + r = strv_extend_strv(&p->unit_path, unit_path, false); if (r < 0) return r; } @@ -342,9 +344,9 @@ int lookup_paths_init( e = getenv("SYSTEMD_SYSVINIT_PATH"); if (e) { - p->sysvinit_path = path_split_and_make_absolute(e); - if (!p->sysvinit_path) - return -ENOMEM; + r = path_split_and_make_absolute(e, &p->sysvinit_path); + if (r < 0) + return r; } else p->sysvinit_path = NULL; @@ -360,9 +362,9 @@ int lookup_paths_init( e = getenv("SYSTEMD_SYSVRCND_PATH"); if (e) { - p->sysvrcnd_path = path_split_and_make_absolute(e); - if (!p->sysvrcnd_path) - return -ENOMEM; + r = path_split_and_make_absolute(e, &p->sysvrcnd_path); + if (r < 0) + return r; } else p->sysvrcnd_path = NULL; @@ -417,9 +419,8 @@ void lookup_paths_free(LookupPaths *p) { p->unit_path = strv_free(p->unit_path); #ifdef HAVE_SYSV_COMPAT - strv_free(p->sysvinit_path); - strv_free(p->sysvrcnd_path); - p->sysvinit_path = p->sysvrcnd_path = NULL; + p->sysvinit_path = strv_free(p->sysvinit_path); + p->sysvrcnd_path = strv_free(p->sysvrcnd_path); #endif } diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 789f217efc..63e81f4894 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -24,14 +24,18 @@ #include <limits.h> #include <termios.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "ptyfwd.h" +#include "util.h" struct PTYForward { sd_event *event; int master; + PTYForwardFlags flags; + sd_event_source *stdin_event_source; sd_event_source *stdout_event_source; sd_event_source *master_event_source; @@ -41,8 +45,6 @@ struct PTYForward { struct termios saved_stdin_attr; struct termios saved_stdout_attr; - bool read_only:1; - bool saved_stdin:1; bool saved_stdout:1; @@ -54,8 +56,7 @@ struct PTYForward { bool master_writable:1; bool master_hangup:1; - /* Continue reading after hangup? */ - bool ignore_vhangup:1; + bool read_from_master:1; bool last_char_set:1; char last_char; @@ -100,6 +101,18 @@ static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) { return false; } +static bool ignore_vhangup(PTYForward *f) { + assert(f); + + if (f->flags & PTY_FORWARD_IGNORE_VHANGUP) + return true; + + if ((f->flags & PTY_FORWARD_IGNORE_INITIAL_VHANGUP) && !f->read_from_master) + return true; + + return false; +} + static int shovel(PTYForward *f) { ssize_t k; @@ -179,7 +192,7 @@ static int shovel(PTYForward *f) { * EAGAIN here and try again, unless * ignore_vhangup is off. */ - if (errno == EAGAIN || (errno == EIO && f->ignore_vhangup)) + if (errno == EAGAIN || (errno == EIO && ignore_vhangup(f))) f->master_readable = false; else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) { f->master_readable = f->master_writable = false; @@ -190,8 +203,10 @@ static int shovel(PTYForward *f) { log_error_errno(errno, "read(): %m"); return sd_event_exit(f->event, EXIT_FAILURE); } - } else + } else { + f->read_from_master = true; f->out_buffer_full += (size_t) k; + } } if (f->stdout_writable && f->out_buffer_full > 0) { @@ -302,8 +317,7 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo * int pty_forward_new( sd_event *event, int master, - bool ignore_vhangup, - bool read_only, + PTYForwardFlags flags, PTYForward **ret) { _cleanup_(pty_forward_freep) PTYForward *f = NULL; @@ -314,8 +328,7 @@ int pty_forward_new( if (!f) return -ENOMEM; - f->read_only = read_only; - f->ignore_vhangup = ignore_vhangup; + f->flags = flags; if (event) f->event = sd_event_ref(event); @@ -325,7 +338,7 @@ int pty_forward_new( return r; } - if (!read_only) { + if (!(flags & PTY_FORWARD_READ_ONLY)) { r = fd_nonblock(STDIN_FILENO, true); if (r < 0) return r; @@ -344,7 +357,7 @@ int pty_forward_new( if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0) (void) ioctl(master, TIOCSWINSZ, &ws); - if (!read_only) { + if (!(flags & PTY_FORWARD_READ_ONLY)) { if (tcgetattr(STDIN_FILENO, &f->saved_stdin_attr) >= 0) { struct termios raw_stdin_attr; @@ -400,6 +413,7 @@ PTYForward *pty_forward_free(PTYForward *f) { sd_event_source_unref(f->stdin_event_source); sd_event_source_unref(f->stdout_event_source); sd_event_source_unref(f->master_event_source); + sd_event_source_unref(f->sigwinch_event_source); sd_event_unref(f->event); if (f->saved_stdout) @@ -429,16 +443,20 @@ int pty_forward_get_last_char(PTYForward *f, char *ch) { return 0; } -int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) { +int pty_forward_set_ignore_vhangup(PTYForward *f, bool b) { int r; assert(f); - if (f->ignore_vhangup == ignore_vhangup) + if (!!(f->flags & PTY_FORWARD_IGNORE_VHANGUP) == b) return 0; - f->ignore_vhangup = ignore_vhangup; - if (!f->ignore_vhangup) { + if (b) + f->flags |= PTY_FORWARD_IGNORE_VHANGUP; + else + f->flags &= ~PTY_FORWARD_IGNORE_VHANGUP; + + if (!ignore_vhangup(f)) { /* We shall now react to vhangup()s? Let's check * immediately if we might be in one */ @@ -455,5 +473,5 @@ int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup) { int pty_forward_get_ignore_vhangup(PTYForward *f) { assert(f); - return f->ignore_vhangup; + return !!(f->flags & PTY_FORWARD_IGNORE_VHANGUP); } diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h index 6f84e4036a..9b3214221b 100644 --- a/src/shared/ptyfwd.h +++ b/src/shared/ptyfwd.h @@ -27,7 +27,17 @@ typedef struct PTYForward PTYForward; -int pty_forward_new(sd_event *event, int master, bool ignore_vhangup, bool read_only, PTYForward **f); +typedef enum PTYForwardFlags { + PTY_FORWARD_READ_ONLY = 1, + + /* Continue reading after hangup? */ + PTY_FORWARD_IGNORE_VHANGUP = 2, + + /* Continue reading after hangup but only if we never read anything else? */ + PTY_FORWARD_IGNORE_INITIAL_VHANGUP = 4, +} PTYForwardFlags; + +int pty_forward_new(sd_event *event, int master, PTYForwardFlags flags, PTYForward **f); PTYForward *pty_forward_free(PTYForward *f); int pty_forward_get_last_char(PTYForward *f, char *ch); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index d73a74912e..c518cf83ec 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -21,6 +21,7 @@ #include <seccomp.h> +#include "string-util.h" #include "util.h" #include "seccomp-util.h" diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 1064fd5cbd..102c5cc992 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -21,10 +21,15 @@ #include <stdio.h> +#include "alloc-util.h" #include "conf-parser.h" -#include "sleep-config.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" #include "log.h" +#include "parse-util.h" +#include "sleep-config.h" +#include "string-util.h" #include "strv.h" #include "util.h" @@ -226,7 +231,7 @@ static bool enough_memory_for_hibernation(void) { if (r < 0) return false; - r = get_status_field("/proc/meminfo", "\nActive(anon):", &active); + r = get_proc_field("/proc/meminfo", "Active(anon)", WHITESPACE, &active); if (r < 0) { log_error_errno(r, "Failed to retrieve Active(anon) from /proc/meminfo: %m"); return false; diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c index 70466d17e5..29db855c67 100644 --- a/src/shared/spawn-ask-password-agent.c +++ b/src/shared/spawn-ask-password-agent.c @@ -19,13 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <signal.h> #include <stdlib.h> #include <unistd.h> -#include <signal.h> #include "log.h" -#include "util.h" #include "process-util.h" +#include "util.h" #include "spawn-ask-password-agent.h" static pid_t agent_pid = 0; @@ -46,9 +46,9 @@ int ask_password_agent_open(void) { SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL); if (r < 0) - log_error_errno(r, "Failed to fork TTY ask password agent: %m"); + return log_error_errno(r, "Failed to fork TTY ask password agent: %m"); - return r; + return 1; } void ask_password_agent_close(void) { @@ -57,8 +57,8 @@ void ask_password_agent_close(void) { return; /* Inform agent that we are done */ - kill(agent_pid, SIGTERM); - kill(agent_pid, SIGCONT); + (void) kill(agent_pid, SIGTERM); + (void) kill(agent_pid, SIGCONT); (void) wait_for_terminate(agent_pid, NULL); agent_pid = 0; } diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c index 4db249e1ca..ec6e5a8312 100644 --- a/src/shared/spawn-polkit-agent.c +++ b/src/shared/spawn-polkit-agent.c @@ -25,10 +25,13 @@ #include <errno.h> #include <poll.h> +#include "fd-util.h" +#include "io-util.h" #include "log.h" -#include "util.h" #include "process-util.h" #include "spawn-polkit-agent.h" +#include "stdio-util.h" +#include "util.h" #ifdef ENABLE_POLKIT static pid_t agent_pid = 0; @@ -76,8 +79,9 @@ void polkit_agent_close(void) { return; /* Inform agent that we are done */ - kill(agent_pid, SIGTERM); - kill(agent_pid, SIGCONT); + (void) kill(agent_pid, SIGTERM); + (void) kill(agent_pid, SIGCONT); + (void) wait_for_terminate(agent_pid, NULL); agent_pid = 0; } diff --git a/src/shared/specifier.c b/src/shared/specifier.c index 85bd477f2d..c5c4a4d7d7 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -22,10 +22,12 @@ #include <string.h> #include <sys/utsname.h> -#include "macro.h" -#include "util.h" +#include "alloc-util.h" #include "hostname-util.h" +#include "macro.h" #include "specifier.h" +#include "string-util.h" +#include "util.h" /* * Generic infrastructure for replacing %x style specifiers in diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index b12189cd10..fc885f6cb8 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -19,21 +19,24 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/stat.h> -#include <stdbool.h> #include <errno.h> +#include <fcntl.h> +#include <stdbool.h> #include <string.h> #include <sys/mount.h> +#include <sys/stat.h> #include <unistd.h> -#include <fcntl.h> -#include "util.h" -#include "path-util.h" -#include "mkdir.h" -#include "rm-rf.h" #include "base-filesystem.h" +#include "fd-util.h" #include "missing.h" +#include "mkdir.h" +#include "path-util.h" +#include "rm-rf.h" +#include "string-util.h" #include "switch-root.h" +#include "user-util.h" +#include "util.h" int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, unsigned long mountflags) { diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c index 1de0b94fd5..21cb82ea1c 100644 --- a/src/shared/sysctl-util.c +++ b/src/shared/sysctl-util.c @@ -19,18 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stdbool.h> #include <errno.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> #include <getopt.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "fileio.h" #include "log.h" +#include "string-util.h" #include "util.h" -#include "fileio.h" -#include "build.h" #include "sysctl-util.h" char *sysctl_normalize(char *s) { diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c index 4794ff45bb..079dd8752c 100644 --- a/src/shared/uid-range.c +++ b/src/shared/uid-range.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "uid-range.h" +#include "user-util.h" +#include "util.h" static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) { assert(range); diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c index 63f1e4ca6f..13b32a0509 100644 --- a/src/shared/utmp-wtmp.c +++ b/src/shared/utmp-wtmp.c @@ -19,18 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <utmpx.h> #include <errno.h> +#include <fcntl.h> +#include <poll.h> #include <string.h> #include <sys/utsname.h> -#include <fcntl.h> #include <unistd.h> -#include <poll.h> +#include <utmpx.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "hostname-util.h" #include "macro.h" #include "path-util.h" +#include "string-util.h" #include "terminal-util.h" -#include "hostname-util.h" +#include "user-util.h" #include "utmp-wtmp.h" int utmp_get_runlevel(int *runlevel, int *previous) { diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index 9d39beb340..d58f9873d5 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -27,6 +27,7 @@ #include "watchdog.h" #include "log.h" +#include "fd-util.h" static int watchdog_fd = -1; static usec_t watchdog_timeout = USEC_INFINITY; diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 2b2310152d..95de369817 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -20,18 +20,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> #include <getopt.h> +#include <stdio.h> #include "sd-messages.h" -#include "log.h" -#include "util.h" -#include "strv.h" + +#include "def.h" +#include "fd-util.h" #include "fileio.h" -#include "build.h" +#include "log.h" #include "sleep-config.h" -#include "def.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static char* arg_verb = NULL; @@ -165,9 +167,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; /* done */ case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0 /* done */; + return version(); case '?': return -EINVAL; diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index 715f440cb1..ba82adadb4 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -20,12 +20,12 @@ ***/ #include <errno.h> +#include <fcntl.h> #include <getopt.h> +#include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <netdb.h> -#include <fcntl.h> #include <sys/socket.h> #include <sys/un.h> #include <unistd.h> @@ -33,12 +33,15 @@ #include "sd-daemon.h" #include "sd-event.h" #include "sd-resolve.h" + +#include "alloc-util.h" +#include "fd-util.h" #include "log.h" +#include "path-util.h" +#include "set.h" #include "socket-util.h" +#include "string-util.h" #include "util.h" -#include "build.h" -#include "set.h" -#include "path-util.h" #define BUFFER_SIZE (256 * 1024) #define CONNECTIONS_MAX 256 @@ -603,9 +606,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case '?': return -EINVAL; diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 618844382f..152c98b348 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -19,23 +19,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stdbool.h> #include <errno.h> -#include <string.h> -#include <stdio.h> -#include <limits.h> #include <getopt.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> -#include "log.h" -#include "strv.h" -#include "util.h" -#include "hashmap.h" -#include "path-util.h" #include "conf-files.h" +#include "def.h" +#include "fd-util.h" #include "fileio.h" -#include "build.h" +#include "hashmap.h" +#include "log.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" #include "sysctl-util.h" +#include "util.h" static char **arg_prefixes = NULL; @@ -86,8 +88,7 @@ static int parse_file(Hashmap *sysctl_options, const char *path, bool ignore_eno if (feof(f)) break; - log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); - return -errno; + return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path); } p = strstrip(l); @@ -195,9 +196,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_PREFIX: { char *p; diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c index 00045150f6..6c2f53774d 100644 --- a/src/system-update-generator/system-update-generator.c +++ b/src/system-update-generator/system-update-generator.c @@ -22,7 +22,9 @@ #include <errno.h> #include <unistd.h> +#include "fs-util.h" #include "log.h" +#include "string-util.h" #include "util.h" /* diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 34e4751b94..70871cf3e6 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -37,7 +37,7 @@ #include "sd-daemon.h" #include "sd-login.h" -#include "build.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-error.h" #include "bus-message.h" @@ -49,31 +49,42 @@ #include "efivars.h" #include "env-util.h" #include "exit-status.h" +#include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "glob-util.h" #include "hostname-util.h" #include "initreq.h" #include "install.h" +#include "io-util.h" #include "list.h" +#include "locale-util.h" #include "log.h" #include "logs-show.h" #include "macro.h" #include "mkdir.h" #include "pager.h" +#include "parse-util.h" #include "path-lookup.h" #include "path-util.h" #include "process-util.h" +#include "rlimit-util.h" #include "set.h" #include "signal-util.h" #include "socket-util.h" #include "spawn-ask-password-agent.h" #include "spawn-polkit-agent.h" #include "special.h" +#include "stat-util.h" #include "strv.h" #include "terminal-util.h" #include "unit-name.h" +#include "user-util.h" #include "util.h" #include "utmp-wtmp.h" +#include "verbs.h" +#include "virt.h" static char **arg_types = NULL; static char **arg_states = NULL; @@ -107,7 +118,7 @@ static UnitFilePresetMode arg_preset_mode = UNIT_FILE_PRESET_FULL; static char **arg_wall = NULL; static const char *arg_kill_who = NULL; static int arg_signal = SIGTERM; -static const char *arg_root = NULL; +static char *arg_root = NULL; static usec_t arg_when = 0; static enum action { _ACTION_INVALID, @@ -134,23 +145,61 @@ static enum action { _ACTION_MAX } arg_action = ACTION_SYSTEMCTL; static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; -static char *arg_host = NULL; +static const char *arg_host = NULL; static unsigned arg_lines = 10; static OutputMode arg_output = OUTPUT_SHORT; static bool arg_plain = false; static bool arg_firmware_setup = false; static bool arg_now = false; -static bool original_stdout_is_tty; - -static int daemon_reload(sd_bus *bus, char **args); +static int daemon_reload(int argc, char *argv[], void* userdata); static int halt_now(enum action a); static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet); -static char** strv_skip_first(char **strv) { - if (strv_length(strv) > 0) - return strv + 1; - return NULL; +static bool original_stdout_is_tty; + +typedef enum BusFocus { + BUS_FULL, /* The full bus indicated via --system or --user */ + BUS_MANAGER, /* The manager itself, possibly directly, possibly via the bus */ + _BUS_FOCUS_MAX +} BusFocus; + +static sd_bus *busses[_BUS_FOCUS_MAX] = {}; + +static int acquire_bus(BusFocus focus, sd_bus **ret) { + int r; + + assert(focus < _BUS_FOCUS_MAX); + assert(ret); + + /* We only go directly to the manager, if we are using a local transport */ + if (arg_transport != BUS_TRANSPORT_LOCAL) + focus = BUS_FULL; + + if (!busses[focus]) { + bool user; + + user = arg_scope != UNIT_FILE_SYSTEM; + + if (focus == BUS_MANAGER) + r = bus_connect_transport_systemd(arg_transport, arg_host, user, &busses[focus]); + else + r = bus_connect_transport(arg_transport, arg_host, user, &busses[focus]); + if (r < 0) + return log_error_errno(r, "Failed to connect to bus: %m"); + + (void) sd_bus_set_allow_interactive_authorization(busses[focus], arg_ask_password); + } + + *ret = busses[focus]; + return 0; +} + +static void release_busses(void) { + BusFocus w; + + for (w = 0; w < _BUS_FOCUS_MAX; w++) + busses[w] = sd_bus_flush_close_unref(busses[w]); } static void pager_open_if_enabled(void) { @@ -230,42 +279,10 @@ static int translate_bus_error_to_exit_status(int r, const sd_bus_error *error) return EXIT_FAILURE; } -static void warn_wall(enum action a) { - static const char *table[_ACTION_MAX] = { - [ACTION_HALT] = "The system is going down for system halt NOW!", - [ACTION_REBOOT] = "The system is going down for reboot NOW!", - [ACTION_POWEROFF] = "The system is going down for power-off NOW!", - [ACTION_KEXEC] = "The system is going down for kexec reboot NOW!", - [ACTION_RESCUE] = "The system is going down to rescue mode NOW!", - [ACTION_EMERGENCY] = "The system is going down to emergency mode NOW!", - [ACTION_CANCEL_SHUTDOWN] = "The system shutdown has been cancelled NOW!" - }; - - if (arg_no_wall) - return; - - if (arg_wall) { - _cleanup_free_ char *p; +static bool install_client_side(void) { - p = strv_join(arg_wall, " "); - if (!p) { - log_oom(); - return; - } - - if (*p) { - utmp_wall(p, NULL, NULL, NULL, NULL); - return; - } - } - - if (!table[a]) - return; - - utmp_wall(table[a], NULL, NULL, NULL, NULL); -} - -static bool avoid_bus(void) { + /* Decides when to execute enable/disable/... operations + * client-side rather than server-side. */ if (running_in_chroot() > 0) return true; @@ -279,6 +296,10 @@ static bool avoid_bus(void) { if (arg_scope == UNIT_FILE_GLOBAL) return true; + /* Unsupported environment variable, mostly for debugging purposes */ + if (getenv_bool("SYSTEMCTL_INSTALL_CLIENT_SIDE") > 0) + return true; + return false; } @@ -652,15 +673,20 @@ static int get_unit_list_recursive( return c; } -static int list_units(sd_bus *bus, char **args) { +static int list_units(int argc, char *argv[], void *userdata) { _cleanup_free_ UnitInfo *unit_infos = NULL; _cleanup_(message_set_freep) Set *replies = NULL; _cleanup_strv_free_ char **machines = NULL; + sd_bus *bus; int r; pager_open_if_enabled(); - r = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (r < 0) return r; @@ -676,6 +702,10 @@ static int get_triggered_units( _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; int r; + assert(bus); + assert(path); + assert(ret); + r = sd_bus_get_property_strv( bus, "org.freedesktop.systemd1", @@ -684,9 +714,8 @@ static int get_triggered_units( "Triggers", &error, ret); - if (r < 0) - log_error("Failed to determine triggers: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to determine triggers: %s", bus_error_message(&error, r)); return 0; } @@ -710,10 +739,8 @@ static int get_listening( &error, &reply, "a(ss)"); - if (r < 0) { - log_error("Failed to get list of listening sockets: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get list of listening sockets: %s", bus_error_message(&error, r)); r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)"); if (r < 0) @@ -853,7 +880,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { return 0; } -static int list_sockets(sd_bus *bus, char **args) { +static int list_sockets(int argc, char *argv[], void *userdata) { _cleanup_(message_set_freep) Set *replies = NULL; _cleanup_strv_free_ char **machines = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; @@ -863,10 +890,15 @@ static int list_sockets(sd_bus *bus, char **args) { unsigned cs = 0; size_t size = 0; int r = 0, n; + sd_bus *bus; pager_open_if_enabled(); - n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (n < 0) return n; @@ -947,10 +979,8 @@ static int get_next_elapse( &error, 't', &t.monotonic); - if (r < 0) { - log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r)); r = sd_bus_get_property_trivial( bus, @@ -961,10 +991,8 @@ static int get_next_elapse( &error, 't', &t.realtime); - if (r < 0) { - log_error("Failed to get next elapsation time: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get next elapsation time: %s", bus_error_message(&error, r)); *next = t; return 0; @@ -991,10 +1019,8 @@ static int get_last_trigger( &error, 't', last); - if (r < 0) { - log_error("Failed to get last trigger time: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get last trigger time: %s", bus_error_message(&error, r)); return 0; } @@ -1160,7 +1186,7 @@ static usec_t calc_next_elapse(dual_timestamp *nw, dual_timestamp *next) { return next_elapse; } -static int list_timers(sd_bus *bus, char **args) { +static int list_timers(int argc, char *argv[], void *userdata) { _cleanup_(message_set_freep) Set *replies = NULL; _cleanup_strv_free_ char **machines = NULL; _cleanup_free_ struct timer_info *timer_infos = NULL; @@ -1170,11 +1196,16 @@ static int list_timers(sd_bus *bus, char **args) { size_t size = 0; int n, c = 0; dual_timestamp nw; + sd_bus *bus; int r = 0; pager_open_if_enabled(); - n = get_unit_list_recursive(bus, strv_skip_first(args), &unit_infos, &replies, &machines); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines); if (n < 0) return n; @@ -1326,7 +1357,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { printf("\n%u unit files listed.\n", c); } -static int list_unit_files(sd_bus *bus, char **args) { +static int list_unit_files(int argc, char *argv[], void *userdata) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_free_ UnitFileList *units = NULL; UnitFileList *unit; @@ -1338,7 +1369,7 @@ static int list_unit_files(sd_bus *bus, char **args) { pager_open_if_enabled(); - if (avoid_bus()) { + if (install_client_side()) { Hashmap *h; UnitFileList *u; Iterator i; @@ -1351,8 +1382,7 @@ static int list_unit_files(sd_bus *bus, char **args) { r = unit_file_get_list(arg_scope, arg_root, h); if (r < 0) { unit_file_list_free(h); - log_error_errno(r, "Failed to get unit file list: %m"); - return r; + return log_error_errno(r, "Failed to get unit file list: %m"); } n_units = hashmap_size(h); @@ -1364,7 +1394,7 @@ static int list_unit_files(sd_bus *bus, char **args) { } HASHMAP_FOREACH(u, h, i) { - if (!output_show_unit_file(u, strv_skip_first(args))) + if (!output_show_unit_file(u, strv_skip(argv, 1))) continue; units[c++] = *u; @@ -1375,6 +1405,11 @@ static int list_unit_files(sd_bus *bus, char **args) { hashmap_free(h); } else { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; r = sd_bus_call_method( bus, @@ -1385,10 +1420,8 @@ static int list_unit_files(sd_bus *bus, char **args) { &error, &reply, NULL); - if (r < 0) { - log_error("Failed to list unit files: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to list unit files: %s", bus_error_message(&error, r)); r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ss)"); if (r < 0) @@ -1404,7 +1437,7 @@ static int list_unit_files(sd_bus *bus, char **args) { unit_file_state_from_string(state) }; - if (output_show_unit_file(&units[c], strv_skip_first(args))) + if (output_show_unit_file(&units[c], strv_skip(argv, 1))) c ++; } @@ -1419,7 +1452,7 @@ static int list_unit_files(sd_bus *bus, char **args) { qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list); output_unit_file_list(units, c); - if (avoid_bus()) { + if (install_client_side()) { for (unit = units; unit < units + c; unit++) free(unit->path); } @@ -1511,10 +1544,8 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha &error, &reply, "s", "org.freedesktop.systemd1.Unit"); - if (r < 0) { - log_error("Failed to get properties of %s: %s", name, bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get properties of %s: %s", name, bus_error_message(&error, r)); r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}"); if (r < 0) @@ -1638,16 +1669,15 @@ static int list_dependencies_one( return 0; } -static int list_dependencies(sd_bus *bus, char **args) { +static int list_dependencies(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **units = NULL; _cleanup_free_ char *unit = NULL; const char *u; + sd_bus *bus; int r; - assert(bus); - - if (args[1]) { - r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &unit); + if (argv[1]) { + r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &unit); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); @@ -1657,6 +1687,10 @@ static int list_dependencies(sd_bus *bus, char **args) { pager_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + puts(u); return list_dependencies_one(bus, u, 0, &units, 0); @@ -1872,12 +1906,11 @@ static void output_machines_list(struct machine_info *machine_infos, unsigned n) printf("\n%u machines listed.\n", n); } -static int list_machines(sd_bus *bus, char **args) { +static int list_machines(int argc, char *argv[], void *userdata) { struct machine_info *machine_infos = NULL; + sd_bus *bus; int r; - assert(bus); - if (geteuid() != 0) { log_error("Must be root."); return -EPERM; @@ -1885,7 +1918,11 @@ static int list_machines(sd_bus *bus, char **args) { pager_open_if_enabled(); - r = get_machine_list(bus, &machine_infos, strv_skip_first(args)); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + r = get_machine_list(bus, &machine_infos, strv_skip(argv, 1)); if (r < 0) return r; @@ -1896,13 +1933,13 @@ static int list_machines(sd_bus *bus, char **args) { return 0; } -static int get_default(sd_bus *bus, char **args) { +static int get_default(int argc, char *argv[], void *userdata) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_free_ char *_path = NULL; const char *path; int r; - if (!bus || avoid_bus()) { + if (install_client_side()) { r = unit_file_get_default(arg_scope, arg_root, &_path); if (r < 0) return log_error_errno(r, "Failed to get default target: %m"); @@ -1910,6 +1947,11 @@ static int get_default(sd_bus *bus, char **args) { } else { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; r = sd_bus_call_method( bus, @@ -1920,10 +1962,8 @@ static int get_default(sd_bus *bus, char **args) { &error, &reply, NULL); - if (r < 0) { - log_error("Failed to get default target: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get default target: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &path); if (r < 0) @@ -1949,17 +1989,21 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha } } -static int set_default(sd_bus *bus, char **args) { +static int set_default(int argc, char *argv[], void *userdata) { _cleanup_free_ char *unit = NULL; - UnitFileChange *changes = NULL; - unsigned n_changes = 0; int r; - r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &unit); + assert(argc >= 2); + assert(argv); + + r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &unit); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); - if (!bus || avoid_bus()) { + if (install_client_side()) { + UnitFileChange *changes = NULL; + unsigned n_changes = 0; + r = unit_file_set_default(arg_scope, arg_root, unit, true, &changes, &n_changes); if (r < 0) return log_error_errno(r, "Failed to set default target: %m"); @@ -1967,13 +2011,19 @@ static int set_default(sd_bus *bus, char **args) { if (!arg_quiet) dump_unit_file_changes(changes, n_changes); + unit_file_changes_free(changes, n_changes); r = 0; } else { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + sd_bus *bus; polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -1983,10 +2033,8 @@ static int set_default(sd_bus *bus, char **args) { &error, &reply, "sb", unit, 1); - if (r < 0) { - log_error("Failed to set default target: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to set default target: %s", bus_error_message(&error, r)); r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); if (r < 0) @@ -1994,13 +2042,11 @@ static int set_default(sd_bus *bus, char **args) { /* Try to reload if enabled */ if (!arg_no_reload) - r = daemon_reload(bus, args); + r = daemon_reload(argc, argv, userdata); else r = 0; } - unit_file_changes_free(changes, n_changes); - return r; } @@ -2085,17 +2131,24 @@ static bool output_show_job(struct job_info *job, char **patterns) { return strv_fnmatch_or_empty(patterns, job->name, FNM_NOESCAPE); } -static int list_jobs(sd_bus *bus, char **args) { +static int list_jobs(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; const char *name, *type, *state, *job_path, *unit_path; _cleanup_free_ struct job_info *jobs = NULL; size_t size = 0; unsigned c = 0; + sd_bus *bus; uint32_t id; int r; bool skipped = false; + pager_open_if_enabled(); + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -2105,10 +2158,8 @@ static int list_jobs(sd_bus *bus, char **args) { &error, &reply, NULL); - if (r < 0) { - log_error("Failed to list jobs: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to list jobs: %s", bus_error_message(&error, r)); r = sd_bus_message_enter_container(reply, 'a', "(usssoo)"); if (r < 0) @@ -2117,7 +2168,7 @@ static int list_jobs(sd_bus *bus, char **args) { while ((r = sd_bus_message_read(reply, "(usssoo)", &id, &name, &type, &state, &job_path, &unit_path)) > 0) { struct job_info job = { id, name, type, state }; - if (!output_show_job(&job, strv_skip_first(args))) { + if (!output_show_job(&job, strv_skip(argv, 1))) { skipped = true; continue; } @@ -2138,18 +2189,21 @@ static int list_jobs(sd_bus *bus, char **args) { return r; } -static int cancel_job(sd_bus *bus, char **args) { +static int cancel_job(int argc, char *argv[], void *userdata) { + sd_bus *bus; char **name; int r = 0; - assert(args); - - if (strv_length(args) <= 1) - return daemon_reload(bus, args); + if (argc <= 1) + return daemon_reload(argc, argv, userdata); polkit_agent_open_if_enabled(); - STRV_FOREACH(name, args+1) { + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + STRV_FOREACH(name, strv_skip(argv, 1)) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; uint32_t id; int q; @@ -2168,7 +2222,7 @@ static int cancel_job(sd_bus *bus, char **args) { NULL, "u", id); if (q < 0) { - log_error("Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q)); + log_error_errno(q, "Failed to cancel job %"PRIu32": %s", id, bus_error_message(&error, q)); if (r == 0) r = q; } @@ -2253,7 +2307,6 @@ static int unit_file_find_path(LookupPaths *lp, const char *unit_name, char **un static int unit_find_paths( sd_bus *bus, const char *unit_name, - bool avoid_bus_cache, LookupPaths *lp, char **fragment_path, char ***dropin_paths) { @@ -2274,7 +2327,7 @@ static int unit_find_paths( assert(fragment_path); assert(lp); - if (!avoid_bus_cache && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) { + if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL; _cleanup_free_ char *unit = NULL; @@ -2471,10 +2524,8 @@ static int check_triggering_units( "LoadState", &error, &state); - if (r < 0) { - log_error("Failed to get load state of %s: %s", n, bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get load state of %s: %s", n, bus_error_message(&error, r)); if (streq(state, "masked")) return 0; @@ -2487,10 +2538,8 @@ static int check_triggering_units( "TriggeredBy", &error, &triggered_by); - if (r < 0) { - log_error("Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get triggered by array of %s: %s", n, bus_error_message(&error, r)); STRV_FOREACH(i, triggered_by) { r = check_one_unit(bus, *i, "active\0reloading\0", true); @@ -2586,8 +2635,7 @@ static int start_unit_one( verb = method_to_verb(method); - log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r)); - return r; + return log_error_errno(r, "Failed to %s %s: %s", verb, name, bus_error_message(error, r)); } r = sd_bus_message_read(reply, "o", &path); @@ -2608,11 +2656,13 @@ static int start_unit_one( } static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) { - _cleanup_strv_free_ char **mangled = NULL, **globs = NULL; char **name; int r, i; + assert(bus); + assert(ret); + STRV_FOREACH(name, names) { char *t; @@ -2637,9 +2687,6 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; - if (!bus) - return log_error_errno(EOPNOTSUPP, "Unit name globbing without bus is not implemented."); - r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply); if (r < 0) return r; @@ -2687,24 +2734,28 @@ static enum action verb_to_action(const char *verb) { return _ACTION_INVALID; } -static int start_unit(sd_bus *bus, char **args) { +static int start_unit(int argc, char *argv[], void *userdata) { _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; const char *method, *mode, *one_name, *suffix = NULL; _cleanup_strv_free_ char **names = NULL; + sd_bus *bus; char **name; int r = 0; - assert(bus); - ask_password_agent_open_if_enabled(); polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + if (arg_action == ACTION_SYSTEMCTL) { enum action action; - method = verb_to_method(args[0]); - action = verb_to_action(args[0]); - if (streq(args[0], "isolate")) { + method = verb_to_method(argv[0]); + action = verb_to_action(argv[0]); + + if (streq(argv[0], "isolate")) { mode = "isolate"; suffix = ".target"; } else @@ -2724,9 +2775,9 @@ static int start_unit(sd_bus *bus, char **args) { if (one_name) names = strv_new(one_name, NULL); else { - r = expand_names(bus, args + 1, suffix, &names); + r = expand_names(bus, strv_skip(argv, 1), suffix, &names); if (r < 0) - log_error_errno(r, "Failed to expand names: %m"); + return log_error_errno(r, "Failed to expand names: %m"); } if (!arg_no_block) { @@ -2761,18 +2812,55 @@ static int start_unit(sd_bus *bus, char **args) { return r; } +static int logind_set_wall_message(void) { +#ifdef HAVE_LOGIND + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; + _cleanup_free_ char *m = NULL; + int r; + + r = acquire_bus(BUS_FULL, &bus); + if (r < 0) + return r; + + m = strv_join(arg_wall, " "); + if (!m) + return log_oom(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "SetWallMessage", + &error, + NULL, + "sb", + m, + !arg_no_wall); + + if (r < 0) + return log_warning_errno(r, "Failed to set wall message, ignoring: %s", bus_error_message(&error, r)); + +#endif + return 0; +} + /* Ask systemd-logind, which might grant access to unprivileged users * through PolicyKit */ -static int reboot_with_logind(sd_bus *bus, enum action a) { +static int logind_reboot(enum action a) { #ifdef HAVE_LOGIND _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; const char *method, *description; + sd_bus *bus; int r; - if (!bus) - return -EIO; - polkit_agent_open_if_enabled(); + (void) logind_set_wall_message(); + + r = acquire_bus(BUS_FULL, &bus); + if (r < 0) + return r; switch (a) { @@ -2805,33 +2893,6 @@ static int reboot_with_logind(sd_bus *bus, enum action a) { return -EINVAL; } - if (!strv_isempty(arg_wall)) { - _cleanup_free_ char *m; - - m = strv_join(arg_wall, " "); - if (!m) - return log_oom(); - - r = sd_bus_call_method( - bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "SetWallMessage", - &error, - NULL, - "sb", - m, - !arg_no_wall); - - if (r < 0) { - log_warning_errno(r, "Failed to set wall message, ignoring: %s", - bus_error_message(&error, r)); - sd_bus_error_free(&error); - } - } - - r = sd_bus_call_method( bus, "org.freedesktop.login1", @@ -2842,27 +2903,25 @@ static int reboot_with_logind(sd_bus *bus, enum action a) { NULL, "b", arg_ask_password); if (r < 0) - log_error("Failed to %s via logind: %s", description, bus_error_message(&error, r)); + return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r)); - return r; + return 0; #else return -ENOSYS; #endif } -static int check_inhibitors(sd_bus *bus, enum action a) { +static int logind_check_inhibitors(enum action a) { #ifdef HAVE_LOGIND _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_strv_free_ char **sessions = NULL; const char *what, *who, *why, *mode; uint32_t uid, pid; + sd_bus *bus; unsigned c = 0; char **s; int r; - if (!bus) - return 0; - if (arg_ignore_inhibitors || arg_force > 0) return 0; @@ -2875,6 +2934,10 @@ static int check_inhibitors(sd_bus *bus, enum action a) { if (!on_tty()) return 0; + r = acquire_bus(BUS_FULL, &bus); + if (r < 0) + return r; + r = sd_bus_call_method( bus, "org.freedesktop.login1", @@ -2964,10 +3027,36 @@ static int check_inhibitors(sd_bus *bus, enum action a) { #endif } -static int prepare_firmware_setup(sd_bus *bus) { +static int logind_prepare_firmware_setup(void) { #ifdef HAVE_LOGIND _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; + int r; + + r = acquire_bus(BUS_FULL, &bus); + if (r < 0) + return r; + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "SetRebootToFirmwareSetup", + &error, + NULL, + "b", true); + if (r < 0) + return log_error_errno(r, "Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r)); + + return 0; +#else + log_error("Cannot remotely indicate to EFI to boot into setup mode."); + return -ENOSYS; #endif +} + +static int prepare_firmware_setup(void) { int r; if (!arg_firmware_setup) @@ -2982,38 +3071,42 @@ static int prepare_firmware_setup(sd_bus *bus) { return r; } -#ifdef HAVE_LOGIND + return logind_prepare_firmware_setup(); +} + +static int set_exit_code(uint8_t code) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; + int r; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_call_method( bus, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "SetRebootToFirmwareSetup", + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "SetExitCode", &error, NULL, - "b", true); - if (r < 0) { - log_error("Cannot indicate to EFI to boot into setup mode: %s", bus_error_message(&error, r)); - return r; - } + "y", code); + if (r < 0) + return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); return 0; -#else - log_error("Cannot remotely indicate to EFI to boot into setup mode."); - return -EINVAL; -#endif } -static int start_special(sd_bus *bus, char **args) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; +static int start_special(int argc, char *argv[], void *userdata) { enum action a; int r; - assert(args); + assert(argv); - a = verb_to_action(args[0]); + a = verb_to_action(argv[0]); - r = check_inhibitors(bus, a); + r = logind_check_inhibitors(a); if (r < 0) return r; @@ -3022,39 +3115,29 @@ static int start_special(sd_bus *bus, char **args) { return -EPERM; } - r = prepare_firmware_setup(bus); + r = prepare_firmware_setup(); if (r < 0) return r; - if (a == ACTION_REBOOT && args[1]) { - r = update_reboot_param_file(args[1]); + if (a == ACTION_REBOOT && argc > 1) { + r = update_reboot_param_file(argv[1]); if (r < 0) return r; - } else if (a == ACTION_EXIT && strv_length(args) > 1) { - /* If the exit code is not given on the command line, don't - * reset it to zero: just keep it as it might have been set - * previously. */ - uint8_t code = 0; - r = safe_atou8(args[1], &code); - if (r < 0) { - log_error("Invalid exit code."); - return -EINVAL; - } + } else if (a == ACTION_EXIT && argc > 1) { + uint8_t code; - r = sd_bus_call_method( - bus, - "org.freedesktop.systemd1", - "/org/freedesktop/systemd1", - "org.freedesktop.systemd1.Manager", - "SetExitCode", - &error, - NULL, - "y", code); - if (r < 0) { - log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + /* If the exit code is not given on the command line, + * don't reset it to zero: just keep it as it might + * have been set previously. */ + + r = safe_atou8(argv[1], &code); + if (r < 0) + return log_error_errno(r, "Invalid exit code."); + + r = set_exit_code(code); + if (r < 0) return r; - } } if (arg_force >= 2 && @@ -3071,39 +3154,37 @@ static int start_special(sd_bus *bus, char **args) { ACTION_REBOOT, ACTION_KEXEC, ACTION_EXIT)) - return daemon_reload(bus, args); + return daemon_reload(argc, argv, userdata); - /* first try logind, to allow authentication with polkit */ - if (geteuid() != 0 && - IN_SET(a, + /* First try logind, to allow authentication with polkit */ + if (IN_SET(a, ACTION_POWEROFF, ACTION_REBOOT, ACTION_SUSPEND, ACTION_HIBERNATE, ACTION_HYBRID_SLEEP)) { - r = reboot_with_logind(bus, a); + r = logind_reboot(a); if (r >= 0) return r; if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) /* requested operation is not supported or already in progress */ return r; - /* on all other errors, try low-level operation */ - } - r = start_unit(bus, args); - if (r == EXIT_SUCCESS) - warn_wall(a); + /* On all other errors, try low-level operation */ + } - return r; + return start_unit(argc, argv, userdata); } -static int check_unit_generic(sd_bus *bus, int code, const char *good_states, char **args) { +static int check_unit_generic(int code, const char *good_states, char **args) { _cleanup_strv_free_ char **names = NULL; + sd_bus *bus; char **name; int r; - assert(bus); - assert(args); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; r = expand_names(bus, args, NULL, &names); if (r < 0) @@ -3122,25 +3203,27 @@ static int check_unit_generic(sd_bus *bus, int code, const char *good_states, ch return r; } -static int check_unit_active(sd_bus *bus, char **args) { +static int check_unit_active(int argc, char *argv[], void *userdata) { /* According to LSB: 3, "program is not running" */ - return check_unit_generic(bus, 3, "active\0reloading\0", args + 1); + return check_unit_generic(3, "active\0reloading\0", strv_skip(argv, 1)); } -static int check_unit_failed(sd_bus *bus, char **args) { - return check_unit_generic(bus, 1, "failed\0", args + 1); +static int check_unit_failed(int argc, char *argv[], void *userdata) { + return check_unit_generic(1, "failed\0", strv_skip(argv, 1)); } -static int kill_unit(sd_bus *bus, char **args) { +static int kill_unit(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; char *kill_who = NULL, **name; + sd_bus *bus; int r, q; - assert(bus); - assert(args); - polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + if (!arg_kill_who) arg_kill_who = "all"; @@ -3148,9 +3231,9 @@ static int kill_unit(sd_bus *bus, char **args) { if (streq(arg_job_mode, "fail")) kill_who = strjoina(arg_kill_who, "-fail", NULL); - r = expand_names(bus, args + 1, NULL, &names); + r = expand_names(bus, strv_skip(argv, 1), NULL, &names); if (r < 0) - log_error_errno(r, "Failed to expand names: %m"); + return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; @@ -3165,7 +3248,7 @@ static int kill_unit(sd_bus *bus, char **args) { NULL, "ssi", *names, kill_who ? kill_who : arg_kill_who, arg_signal); if (q < 0) { - log_error("Failed to kill unit %s: %s", *names, bus_error_message(&error, q)); + log_error_errno(q, "Failed to kill unit %s: %s", *names, bus_error_message(&error, q)); if (r == 0) r = q; } @@ -3407,7 +3490,8 @@ static void print_status_info( dir = mfree(dir); - if (path_get_parent(*dropin, &dir) < 0) { + dir = dirname_malloc(*dropin); + if (!dir) { log_oom(); return; } @@ -3456,7 +3540,7 @@ static void print_status_info( printf("Condition: start %scondition failed%s at %s%s%s\n", ansi_highlight_yellow(), ansi_normal(), - s2, s1 ? "; " : "", s1 ? s1 : ""); + s2, s1 ? "; " : "", strempty(s1)); if (i->failed_condition_trigger) printf(" none of the trigger conditions were met\n"); else if (i->failed_condition) @@ -3472,7 +3556,7 @@ static void print_status_info( printf(" Assert: start %sassertion failed%s at %s%s%s\n", ansi_highlight_red(), ansi_normal(), - s2, s1 ? "; " : "", s1 ? s1 : ""); + s2, s1 ? "; " : "", strempty(s1)); if (i->failed_assert_trigger) printf(" none of the trigger assertions were met\n"); else if (i->failed_assert) @@ -3861,13 +3945,13 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * info->name = strdup(name); if (!info->name) - log_oom(); + return log_oom(); LIST_PREPEND(exec, i->exec, info); info = new0(ExecStatusInfo, 1); if (!info) - log_oom(); + return log_oom(); } if (r < 0) @@ -4439,10 +4523,8 @@ static int get_unit_dbus_path_by_pid( &error, &reply, "u", pid); - if (r < 0) { - log_error("Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r)); r = sd_bus_message_read(reply, "o", &u); if (r < 0) @@ -4551,16 +4633,22 @@ static int show_system_status(sd_bus *bus) { return 0; } -static int show(sd_bus *bus, char **args) { - bool show_properties, show_status, new_line = false; +static int show(int argc, char *argv[], void *userdata) { + bool show_properties, show_status, show_help, new_line = false; bool ellipsized = false; int r, ret = 0; + sd_bus *bus; - assert(bus); - assert(args); + assert(argv); - show_properties = streq(args[0], "show"); - show_status = streq(args[0], "status"); + show_properties = streq(argv[0], "show"); + show_status = streq(argv[0], "status"); + show_help = streq(argv[0], "help"); + + if (show_help && argc <= 1) { + log_error("This command expects one or more unit names. Did you mean --help?"); + return -EINVAL; + } if (show_properties) pager_open_if_enabled(); @@ -4571,24 +4659,27 @@ static int show(sd_bus *bus, char **args) { * be split up into many files. */ setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384)); - /* If no argument is specified inspect the manager itself */ + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; - if (show_properties && strv_length(args) <= 1) - return show_one(args[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); + /* If no argument is specified inspect the manager itself */ + if (show_properties && argc <= 1) + return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized); - if (show_status && strv_length(args) <= 1) { + if (show_status && argc <= 1) { pager_open_if_enabled(); show_system_status(bus); new_line = true; if (arg_all) - ret = show_all(args[0], bus, false, &new_line, &ellipsized); + ret = show_all(argv[0], bus, false, &new_line, &ellipsized); } else { _cleanup_free_ char **patterns = NULL; char **name; - STRV_FOREACH(name, args + 1) { + STRV_FOREACH(name, strv_skip(argv, 1)) { _cleanup_free_ char *unit = NULL; uint32_t id; @@ -4611,8 +4702,7 @@ static int show(sd_bus *bus, char **args) { } } - r = show_one(args[0], bus, unit, show_properties, - &new_line, &ellipsized); + r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized); if (r < 0) return r; else if (r > 0 && ret == 0) @@ -4624,7 +4714,7 @@ static int show(sd_bus *bus, char **args) { r = expand_names(bus, patterns, NULL, &names); if (r < 0) - log_error_errno(r, "Failed to expand names: %m"); + return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { _cleanup_free_ char *unit; @@ -4633,8 +4723,7 @@ static int show(sd_bus *bus, char **args) { if (!unit) return log_oom(); - r = show_one(args[0], bus, unit, show_properties, - &new_line, &ellipsized); + r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized); if (r < 0) return r; else if (r > 0 && ret == 0) @@ -4694,19 +4783,18 @@ static int cat_file(const char *filename, bool newline) { return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false); } -static int cat(sd_bus *bus, char **args) { +static int cat(int argc, char *argv[], void *userdata) { _cleanup_free_ char *user_home = NULL; _cleanup_free_ char *user_runtime = NULL; _cleanup_lookup_paths_free_ LookupPaths lp = {}; _cleanup_strv_free_ char **names = NULL; char **name; - bool first = true, avoid_bus_cache; + sd_bus *bus; + bool first = true; int r; - assert(args); - if (arg_transport != BUS_TRANSPORT_LOCAL) { - log_error("Cannot remotely cat units"); + log_error("Cannot remotely cat units."); return -EINVAL; } @@ -4714,11 +4802,13 @@ static int cat(sd_bus *bus, char **args) { if (r < 0) return r; - r = expand_names(bus, args + 1, NULL, &names); + r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) - return log_error_errno(r, "Failed to expand names: %m"); + return r; - avoid_bus_cache = !bus || avoid_bus(); + r = expand_names(bus, strv_skip(argv, 1), NULL, &names); + if (r < 0) + return log_error_errno(r, "Failed to expand names: %m"); pager_open_if_enabled(); @@ -4727,7 +4817,7 @@ static int cat(sd_bus *bus, char **args) { _cleanup_strv_free_ char **dropin_paths = NULL; char **path; - r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &fragment_path, &dropin_paths); + r = unit_find_paths(bus, *name, &lp, &fragment_path, &dropin_paths); if (r < 0) return r; else if (r == 0) @@ -4754,15 +4844,20 @@ static int cat(sd_bus *bus, char **args) { return 0; } -static int set_property(sd_bus *bus, char **args) { +static int set_property(int argc, char *argv[], void *userdata) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *n = NULL; + sd_bus *bus; char **i; int r; polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_message_new_method_call( bus, &m, @@ -4773,7 +4868,7 @@ static int set_property(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); - r = unit_name_mangle(args[1], UNIT_NAME_NOGLOB, &n); + r = unit_name_mangle(argv[1], UNIT_NAME_NOGLOB, &n); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); @@ -4785,7 +4880,7 @@ static int set_property(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); - STRV_FOREACH(i, args + 2) { + STRV_FOREACH(i, strv_skip(argv, 2)) { r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); if (r < 0) return bus_log_create_error(r); @@ -4804,25 +4899,24 @@ static int set_property(sd_bus *bus, char **args) { return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); - if (r < 0) { - log_error("Failed to set unit properties on %s: %s", n, bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to set unit properties on %s: %s", n, bus_error_message(&error, r)); return 0; } -static int snapshot(sd_bus *bus, char **args) { +static int snapshot(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_free_ char *n = NULL, *id = NULL; const char *path; + sd_bus *bus; int r; polkit_agent_open_if_enabled(); - if (strv_length(args) > 1) { - r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".snapshot", &n); + if (argc > 1) { + r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".snapshot", &n); if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); } else { @@ -4831,6 +4925,10 @@ static int snapshot(sd_bus *bus, char **args) { return log_oom(); } + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -4840,10 +4938,8 @@ static int snapshot(sd_bus *bus, char **args) { &error, &reply, "sb", n, false); - if (r < 0) { - log_error("Failed to create snapshot: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to create snapshot: %s", bus_error_message(&error, r)); r = sd_bus_message_read(reply, "o", &path); if (r < 0) @@ -4857,10 +4953,8 @@ static int snapshot(sd_bus *bus, char **args) { "Id", &error, &id); - if (r < 0) { - log_error("Failed to get ID of snapshot: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get ID of snapshot: %s", bus_error_message(&error, r)); if (!arg_quiet) puts(id); @@ -4868,18 +4962,21 @@ static int snapshot(sd_bus *bus, char **args) { return 0; } -static int delete_snapshot(sd_bus *bus, char **args) { +static int delete_snapshot(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; + sd_bus *bus; char **name; int r; - assert(args); - polkit_agent_open_if_enabled(); - r = expand_names(bus, args + 1, ".snapshot", &names); + r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) - log_error_errno(r, "Failed to expand names: %m"); + return r; + + r = expand_names(bus, strv_skip(argv, 1), ".snapshot", &names); + if (r < 0) + return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; @@ -4895,7 +4992,7 @@ static int delete_snapshot(sd_bus *bus, char **args) { NULL, "s", *name); if (q < 0) { - log_error("Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q)); + log_error_errno(q, "Failed to remove snapshot %s: %s", *name, bus_error_message(&error, q)); if (r == 0) r = q; } @@ -4904,13 +5001,18 @@ static int delete_snapshot(sd_bus *bus, char **args) { return r; } -static int daemon_reload(sd_bus *bus, char **args) { +static int daemon_reload(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; const char *method; + sd_bus *bus; int r; polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + if (arg_action == ACTION_RELOAD) method = "Reload"; else if (arg_action == ACTION_REEXEC) @@ -4919,15 +5021,15 @@ static int daemon_reload(sd_bus *bus, char **args) { assert(arg_action == ACTION_SYSTEMCTL); method = - streq(args[0], "clear-jobs") || - streq(args[0], "cancel") ? "ClearJobs" : - streq(args[0], "daemon-reexec") ? "Reexecute" : - streq(args[0], "reset-failed") ? "ResetFailed" : - streq(args[0], "halt") ? "Halt" : - streq(args[0], "poweroff") ? "PowerOff" : - streq(args[0], "reboot") ? "Reboot" : - streq(args[0], "kexec") ? "KExec" : - streq(args[0], "exit") ? "Exit" : + streq(argv[0], "clear-jobs") || + streq(argv[0], "cancel") ? "ClearJobs" : + streq(argv[0], "daemon-reexec") ? "Reexecute" : + streq(argv[0], "reset-failed") ? "ResetFailed" : + streq(argv[0], "halt") ? "Halt" : + streq(argv[0], "poweroff") ? "PowerOff" : + streq(argv[0], "reboot") ? "Reboot" : + streq(argv[0], "kexec") ? "KExec" : + streq(argv[0], "exit") ? "Exit" : /* "daemon-reload" */ "Reload"; } @@ -4949,24 +5051,29 @@ static int daemon_reload(sd_bus *bus, char **args) { * reply */ r = 0; else if (r < 0) - log_error("Failed to execute operation: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); return r < 0 ? r : 0; } -static int reset_failed(sd_bus *bus, char **args) { +static int reset_failed(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; + sd_bus *bus; char **name; int r, q; - if (strv_length(args) <= 1) - return daemon_reload(bus, args); + if (argc <= 1) + return daemon_reload(argc, argv, userdata); polkit_agent_open_if_enabled(); - r = expand_names(bus, args + 1, NULL, &names); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + r = expand_names(bus, strv_skip(argv, 1), NULL, &names); if (r < 0) - log_error_errno(r, "Failed to expand names: %m"); + return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; @@ -4981,7 +5088,7 @@ static int reset_failed(sd_bus *bus, char **args) { NULL, "s", *name); if (q < 0) { - log_error("Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q)); + log_error_errno(q, "Failed to reset failed state of unit %s: %s", *name, bus_error_message(&error, q)); if (r == 0) r = q; } @@ -4990,14 +5097,19 @@ static int reset_failed(sd_bus *bus, char **args) { return r; } -static int show_environment(sd_bus *bus, char **args) { +static int show_environment(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; const char *text; + sd_bus *bus; int r; pager_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_get_property( bus, "org.freedesktop.systemd1", @@ -5007,10 +5119,8 @@ static int show_environment(sd_bus *bus, char **args) { &error, &reply, "as"); - if (r < 0) { - log_error("Failed to get environment: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get environment: %s", bus_error_message(&error, r)); r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "s"); if (r < 0) @@ -5028,23 +5138,27 @@ static int show_environment(sd_bus *bus, char **args) { return 0; } -static int switch_root(sd_bus *bus, char **args) { +static int switch_root(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *cmdline_init = NULL; const char *root, *init; - unsigned l; + sd_bus *bus; int r; - l = strv_length(args); - if (l < 2 || l > 3) { + if (arg_transport != BUS_TRANSPORT_LOCAL) { + log_error("Cannot switch root remotely."); + return -EINVAL; + } + + if (argc < 2 || argc > 3) { log_error("Wrong number of arguments."); return -EINVAL; } - root = args[1]; + root = argv[1]; - if (l >= 3) - init = args[2]; + if (argc >= 3) + init = argv[2]; else { r = parse_env_file("/proc/cmdline", WHITESPACE, "init", &cmdline_init, @@ -5070,6 +5184,10 @@ static int switch_root(sd_bus *bus, char **args) { init = NULL; } + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + log_debug("Switching root - root: %s; init: %s", root, strna(init)); r = sd_bus_call_method( @@ -5081,26 +5199,29 @@ static int switch_root(sd_bus *bus, char **args) { &error, NULL, "ss", root, init); - if (r < 0) { - log_error("Failed to switch root: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r)); return 0; } -static int set_environment(sd_bus *bus, char **args) { +static int set_environment(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *m = NULL; const char *method; + sd_bus *bus; int r; - assert(bus); - assert(args); + assert(argc > 1); + assert(argv); polkit_agent_open_if_enabled(); - method = streq(args[0], "set-environment") + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + method = streq(argv[0], "set-environment") ? "SetEnvironment" : "UnsetEnvironment"; @@ -5114,29 +5235,29 @@ static int set_environment(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); - r = sd_bus_message_append_strv(m, args + 1); + r = sd_bus_message_append_strv(m, strv_skip(argv, 1)); if (r < 0) return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); - if (r < 0) { - log_error("Failed to set environment: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to set environment: %s", bus_error_message(&error, r)); return 0; } -static int import_environment(sd_bus *bus, char **args) { +static int import_environment(int argc, char *argv[], void *userdata) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + sd_bus *bus; int r; - assert(bus); - assert(args); - polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_message_new_method_call( bus, &m, @@ -5147,7 +5268,7 @@ static int import_environment(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); - if (strv_isempty(args + 1)) + if (argc < 2) r = sd_bus_message_append_strv(m, environ); else { char **a, **b; @@ -5156,7 +5277,7 @@ static int import_environment(sd_bus *bus, char **args) { if (r < 0) return bus_log_create_error(r); - STRV_FOREACH(a, args + 1) { + STRV_FOREACH(a, strv_skip(argv, 1)) { if (!env_name_is_valid(*a)) { log_error("Not a valid environment variable name: %s", *a); @@ -5184,10 +5305,8 @@ static int import_environment(sd_bus *bus, char **args) { return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, NULL); - if (r < 0) { - log_error("Failed to import environment: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to import environment: %s", bus_error_message(&error, r)); return 0; } @@ -5202,6 +5321,9 @@ static int enable_sysv_units(const char *verb, char **args) { if (arg_scope != UNIT_FILE_SYSTEM) return 0; + if (getenv_bool("SYSTEMCTL_SKIP_SYSV") > 0) + return 0; + if (!STR_IN_SET(verb, "enable", "disable", @@ -5290,13 +5412,13 @@ static int enable_sysv_units(const char *verb, char **args) { (void) reset_signal_mask(); execv(argv[0], (char**) argv); - log_error("Failed to execute %s: %m", argv[0]); + log_error_errno(r, "Failed to execute %s: %m", argv[0]); _exit(EXIT_FAILURE); } j = wait_for_terminate(pid, &status); if (j < 0) { - log_error_errno(r, "Failed to wait for child: %m"); + log_error_errno(j, "Failed to wait for child: %m"); return j; } @@ -5366,18 +5488,18 @@ static int mangle_names(char **original_names, char ***mangled_names) { return 0; } -static int enable_unit(sd_bus *bus, char **args) { +static int enable_unit(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; - const char *verb = args[0]; + const char *verb = argv[0]; UnitFileChange *changes = NULL; unsigned n_changes = 0; int carries_install_info = -1; int r; - if (!args[1]) + if (!argv[1]) return 0; - r = mangle_names(args+1, &names); + r = mangle_names(strv_skip(argv, 1), &names); if (r < 0) return r; @@ -5390,7 +5512,7 @@ static int enable_unit(sd_bus *bus, char **args) { if (strv_isempty(names)) return 0; - if (!bus || avoid_bus()) { + if (install_client_side()) { if (streq(verb, "enable")) { r = unit_file_enable(arg_scope, arg_runtime, arg_root, names, arg_force, &changes, &n_changes); carries_install_info = r; @@ -5426,9 +5548,14 @@ static int enable_unit(sd_bus *bus, char **args) { int expect_carries_install_info = false; bool send_force = true, send_preset_mode = false; const char *method; + sd_bus *bus; polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + if (streq(verb, "enable")) { method = "EnableUnitFiles"; expect_carries_install_info = true; @@ -5488,10 +5615,8 @@ static int enable_unit(sd_bus *bus, char **args) { } r = sd_bus_call(bus, m, 0, &error, &reply); - if (r < 0) { - log_error("Failed to execute operation: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); if (expect_carries_install_info) { r = sd_bus_message_read(reply, "b", &carries_install_info); @@ -5505,7 +5630,7 @@ static int enable_unit(sd_bus *bus, char **args) { /* Try to reload if enabled */ if (!arg_no_reload) - r = daemon_reload(bus, args); + r = daemon_reload(argc, argv, userdata); else r = 0; } @@ -5521,16 +5646,21 @@ static int enable_unit(sd_bus *bus, char **args) { "3) A unit may be started when needed via activation (socket, path, timer,\n" " D-Bus, udev, scripted systemctl call, ...).\n"); - if (arg_now && n_changes > 0 && STR_IN_SET(args[0], "enable", "disable", "mask")) { + if (arg_now && n_changes > 0 && STR_IN_SET(argv[0], "enable", "disable", "mask")) { char *new_args[n_changes + 2]; + sd_bus *bus; unsigned i; - new_args[0] = streq(args[0], "enable") ? (char *)"start" : (char *)"stop"; + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + new_args[0] = (char*) (streq(argv[0], "enable") ? "start" : "stop"); for (i = 0; i < n_changes; i++) new_args[i + 1] = basename(changes[i].path); new_args[i + 1] = NULL; - r = start_unit(bus, new_args); + r = start_unit(strv_length(new_args), new_args, userdata); } finish: @@ -5539,21 +5669,21 @@ finish: return r; } -static int add_dependency(sd_bus *bus, char **args) { +static int add_dependency(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; _cleanup_free_ char *target = NULL; - const char *verb = args[0]; + const char *verb = argv[0]; UnitDependency dep; int r = 0; - if (!args[1]) + if (!argv[1]) return 0; - r = unit_name_mangle_with_suffix(args[1], UNIT_NAME_NOGLOB, ".target", &target); + r = unit_name_mangle_with_suffix(argv[1], UNIT_NAME_NOGLOB, ".target", &target); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); - r = mangle_names(args+2, &names); + r = mangle_names(strv_skip(argv, 2), &names); if (r < 0) return r; @@ -5564,7 +5694,7 @@ static int add_dependency(sd_bus *bus, char **args) { else assert_not_reached("Unknown verb"); - if (!bus || avoid_bus()) { + if (install_client_side()) { UnitFileChange *changes = NULL; unsigned n_changes = 0; @@ -5581,9 +5711,14 @@ static int add_dependency(sd_bus *bus, char **args) { } else { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_message_new_method_call( bus, &m, @@ -5603,17 +5738,15 @@ static int add_dependency(sd_bus *bus, char **args) { return bus_log_create_error(r); r = sd_bus_call(bus, m, 0, &error, &reply); - if (r < 0) { - log_error("Failed to execute operation: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); if (r < 0) return r; if (!arg_no_reload) - r = daemon_reload(bus, args); + r = daemon_reload(argc, argv, userdata); else r = 0; } @@ -5621,12 +5754,12 @@ static int add_dependency(sd_bus *bus, char **args) { return r; } -static int preset_all(sd_bus *bus, char **args) { +static int preset_all(int argc, char *argv[], void *userdata) { UnitFileChange *changes = NULL; unsigned n_changes = 0; int r; - if (!bus || avoid_bus()) { + if (install_client_side()) { r = unit_file_preset_all(arg_scope, arg_runtime, arg_root, arg_preset_mode, arg_force, &changes, &n_changes); if (r < 0) { @@ -5642,9 +5775,14 @@ static int preset_all(sd_bus *bus, char **args) { } else { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + sd_bus *bus; polkit_agent_open_if_enabled(); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_call_method( bus, "org.freedesktop.systemd1", @@ -5657,17 +5795,15 @@ static int preset_all(sd_bus *bus, char **args) { unit_file_preset_mode_to_string(arg_preset_mode), arg_runtime, arg_force); - if (r < 0) { - log_error("Failed to execute operation: %s", bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r)); r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL); if (r < 0) return r; if (!arg_no_reload) - r = daemon_reload(bus, args); + r = daemon_reload(argc, argv, userdata); else r = 0; } @@ -5678,25 +5814,24 @@ finish: return r; } -static int unit_is_enabled(sd_bus *bus, char **args) { +static int unit_is_enabled(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_strv_free_ char **names = NULL; bool enabled; char **name; int r; - r = mangle_names(args+1, &names); + r = mangle_names(strv_skip(argv, 1), &names); if (r < 0) return r; - r = enable_sysv_units(args[0], names); + r = enable_sysv_units(argv[0], names); if (r < 0) return r; enabled = r > 0; - if (!bus || avoid_bus()) { + if (install_client_side()) { STRV_FOREACH(name, names) { UnitFileState state; @@ -5717,6 +5852,13 @@ static int unit_is_enabled(sd_bus *bus, char **args) { } } else { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + STRV_FOREACH(name, names) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; const char *s; @@ -5730,10 +5872,8 @@ static int unit_is_enabled(sd_bus *bus, char **args) { &error, &reply, "s", *name); - if (r < 0) { - log_error("Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to get unit file state for %s: %s", *name, bus_error_message(&error, r)); r = sd_bus_message_read(reply, "s", &s); if (r < 0) @@ -5750,10 +5890,21 @@ static int unit_is_enabled(sd_bus *bus, char **args) { return !enabled; } -static int is_system_running(sd_bus *bus, char **args) { +static int is_system_running(int argc, char *argv[], void *userdata) { _cleanup_free_ char *state = NULL; + sd_bus *bus; int r; + if (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted()) { + if (!arg_quiet) + puts("offline"); + return EXIT_FAILURE; + } + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + r = sd_bus_get_property_string( bus, "org.freedesktop.systemd1", @@ -5775,7 +5926,7 @@ static int is_system_running(sd_bus *bus, char **args) { } static int create_edit_temp_file(const char *new_path, const char *original_path, char **ret_tmp_fn) { - char *t; + _cleanup_free_ char *t = NULL; int r; assert(new_path); @@ -5787,27 +5938,21 @@ static int create_edit_temp_file(const char *new_path, const char *original_path return log_error_errno(r, "Failed to determine temporary filename for \"%s\": %m", new_path); r = mkdir_parents(new_path, 0755); - if (r < 0) { - log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path); - free(t); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path); r = copy_file(original_path, t, 0, 0644, 0); if (r == -ENOENT) { + r = touch(t); - if (r < 0) { - log_error_errno(r, "Failed to create temporary file \"%s\": %m", t); - free(t); - return r; - } - } else if (r < 0) { - log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t); - free(t); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t); + + } else if (r < 0) + return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t); *ret_tmp_fn = t; + t = NULL; return 0; } @@ -5815,6 +5960,9 @@ static int create_edit_temp_file(const char *new_path, const char *original_path static int get_file_to_edit(const char *name, const char *user_home, const char *user_runtime, char **ret_path) { _cleanup_free_ char *path = NULL, *path2 = NULL, *run = NULL; + assert(name); + assert(ret_path); + switch (arg_scope) { case UNIT_FILE_SYSTEM: path = path_join(arg_root, SYSTEM_CONFIG_UNIT_PATH, name); @@ -5845,12 +5993,16 @@ static int get_file_to_edit(const char *name, const char *user_home, const char return log_oom(); if (arg_runtime) { - if (access(path, F_OK) >= 0) - return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", - run, path); - if (path2 && access(path2, F_OK) >= 0) - return log_error_errno(EEXIST, "Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", - run, path2); + if (access(path, F_OK) >= 0) { + log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path); + return -EEXIST; + } + + if (path2 && access(path2, F_OK) >= 0) { + log_error("Refusing to create \"%s\" because it would be overridden by \"%s\" anyway.", run, path2); + return -EEXIST; + } + *ret_path = run; run = NULL; } else { @@ -5862,8 +6014,7 @@ static int get_file_to_edit(const char *name, const char *user_home, const char } static int unit_file_create_dropin(const char *unit_name, const char *user_home, const char *user_runtime, char **ret_new_path, char **ret_tmp_path) { - char *tmp_new_path, *ending; - char *tmp_tmp_path; + char *tmp_new_path, *tmp_tmp_path, *ending; int r; assert(unit_name); @@ -5895,8 +6046,7 @@ static int unit_file_create_copy( char **ret_new_path, char **ret_tmp_path) { - char *tmp_new_path; - char *tmp_tmp_path; + char *tmp_new_path, *tmp_tmp_path; int r; assert(fragment_path); @@ -5943,10 +6093,8 @@ static int run_editor(char **paths) { assert(paths); pid = fork(); - if (pid < 0) { - log_error_errno(errno, "Failed to fork: %m"); - return -errno; - } + if (pid < 0) + return log_error_errno(errno, "Failed to fork: %m"); if (pid == 0) { const char **args; @@ -6004,7 +6152,7 @@ static int run_editor(char **paths) { * failing. */ if (errno != ENOENT) { - log_error("Failed to execute %s: %m", editor); + log_error_errno(errno, "Failed to execute %s: %m", editor); _exit(EXIT_FAILURE); } } @@ -6017,14 +6165,13 @@ static int run_editor(char **paths) { if (r < 0) return log_error_errno(r, "Failed to wait for child: %m"); - return r; + return 0; } static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { _cleanup_free_ char *user_home = NULL; _cleanup_free_ char *user_runtime = NULL; _cleanup_lookup_paths_free_ LookupPaths lp = {}; - bool avoid_bus_cache; char **name; int r; @@ -6035,13 +6182,11 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { if (r < 0) return r; - avoid_bus_cache = !bus || avoid_bus(); - STRV_FOREACH(name, names) { _cleanup_free_ char *path = NULL; char *new_path, *tmp_path; - r = unit_find_paths(bus, *name, avoid_bus_cache, &lp, &path, NULL); + r = unit_find_paths(bus, *name, &lp, &path, NULL); if (r < 0) return r; else if (r == 0) @@ -6067,25 +6212,28 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) { return 0; } -static int edit(sd_bus *bus, char **args) { +static int edit(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **names = NULL; _cleanup_strv_free_ char **paths = NULL; char **original, **tmp; + sd_bus *bus; int r; - assert(args); - if (!on_tty()) { - log_error("Cannot edit units if not on a tty"); + log_error("Cannot edit units if not on a tty."); return -EINVAL; } if (arg_transport != BUS_TRANSPORT_LOCAL) { - log_error("Cannot remotely edit units"); + log_error("Cannot edit units remotely."); return -EINVAL; } - r = expand_names(bus, args + 1, NULL, &names); + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + r = expand_names(bus, strv_skip(argv, 1), NULL, &names); if (r < 0) return log_error_errno(r, "Failed to expand names: %m"); @@ -6101,13 +6249,14 @@ static int edit(sd_bus *bus, char **args) { goto end; STRV_FOREACH_PAIR(original, tmp, paths) { - /* If the temporary file is empty we ignore it. - * It's useful if the user wants to cancel its modification + /* If the temporary file is empty we ignore it. It's + * useful if the user wants to cancel its modification */ if (null_or_empty_path(*tmp)) { - log_warning("Editing \"%s\" canceled: temporary file is empty", *original); + log_warning("Editing \"%s\" canceled: temporary file is empty.", *original); continue; } + r = rename(*tmp, *original); if (r < 0) { r = log_error_errno(errno, "Failed to rename \"%s\" to \"%s\": %m", *tmp, *original); @@ -6115,12 +6264,14 @@ static int edit(sd_bus *bus, char **args) { } } - if (!arg_no_reload && bus && !avoid_bus()) - r = daemon_reload(bus, args); + r = 0; + + if (!arg_no_reload && !install_client_side()) + r = daemon_reload(argc, argv, userdata); end: STRV_FOREACH_PAIR(original, tmp, paths) - unlink_noerrno(*tmp); + (void) unlink(*tmp); return r; } @@ -6314,15 +6465,90 @@ static void runlevel_help(void) { static void help_types(void) { int i; - const char *t; if (!arg_no_legend) puts("Available unit types:"); - for (i = 0; i < _UNIT_TYPE_MAX; i++) { - t = unit_type_to_string(i); - if (t) - puts(t); - } + for (i = 0; i < _UNIT_TYPE_MAX; i++) + puts(unit_type_to_string(i)); +} + +static void help_states(void) { + int i; + + if (!arg_no_legend) + puts("Available unit load states:"); + for (i = 0; i < _UNIT_LOAD_STATE_MAX; i++) + puts(unit_load_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable unit active states:"); + for (i = 0; i < _UNIT_ACTIVE_STATE_MAX; i++) + puts(unit_active_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable automount unit substates:"); + for (i = 0; i < _AUTOMOUNT_STATE_MAX; i++) + puts(automount_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable busname unit substates:"); + for (i = 0; i < _BUSNAME_STATE_MAX; i++) + puts(busname_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable device unit substates:"); + for (i = 0; i < _DEVICE_STATE_MAX; i++) + puts(device_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable mount unit substates:"); + for (i = 0; i < _MOUNT_STATE_MAX; i++) + puts(mount_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable path unit substates:"); + for (i = 0; i < _PATH_STATE_MAX; i++) + puts(path_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable scope unit substates:"); + for (i = 0; i < _SCOPE_STATE_MAX; i++) + puts(scope_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable service unit substates:"); + for (i = 0; i < _SERVICE_STATE_MAX; i++) + puts(service_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable slice unit substates:"); + for (i = 0; i < _SLICE_STATE_MAX; i++) + puts(slice_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable snapshot unit substates:"); + for (i = 0; i < _SNAPSHOT_STATE_MAX; i++) + puts(snapshot_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable socket unit substates:"); + for (i = 0; i < _SOCKET_STATE_MAX; i++) + puts(socket_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable swap unit substates:"); + for (i = 0; i < _SWAP_STATE_MAX; i++) + puts(swap_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable target unit substates:"); + for (i = 0; i < _TARGET_STATE_MAX; i++) + puts(target_state_to_string(i)); + + if (!arg_no_legend) + puts("\nAvailable timer unit substates:"); + for (i = 0; i < _TIMER_STATE_MAX; i++) + puts(timer_state_to_string(i)); } static int systemctl_parse_argv(int argc, char *argv[]) { @@ -6405,7 +6631,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { {} }; - int c; + const char *p; + int c, r; assert(argc >= 0); assert(argv); @@ -6422,20 +6649,22 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 't': { - const char *word, *state; - size_t size; + if (isempty(optarg)) + return log_error_errno(r, "--type requires arguments."); - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { - _cleanup_free_ char *type; + p = optarg; + for(;;) { + _cleanup_free_ char *type = NULL; - type = strndup(word, size); - if (!type) - return -ENOMEM; + r = extract_first_word(&p, &type, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse type: %s", optarg); + + if (r == 0) + break; if (streq(type, "help")) { help_types(); @@ -6443,7 +6672,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } if (unit_type_from_string(type) >= 0) { - if (strv_push(&arg_types, type)) + if (strv_push(&arg_types, type) < 0) return log_oom(); type = NULL; continue; @@ -6453,7 +6682,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { * load states, but let's support this * in --types= too for compatibility * with old versions */ - if (unit_load_state_from_string(optarg) >= 0) { + if (unit_load_state_from_string(type) >= 0) { if (strv_push(&arg_states, type) < 0) return log_oom(); type = NULL; @@ -6476,18 +6705,21 @@ static int systemctl_parse_argv(int argc, char *argv[]) { if (!arg_properties) return log_oom(); } else { - const char *word, *state; - size_t size; + p = optarg; + for(;;) { + _cleanup_free_ char *prop = NULL; - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { - char *prop; + r = extract_first_word(&p, &prop, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse property: %s", optarg); - prop = strndup(word, size); - if (!prop) - return log_oom(); + if (r == 0) + break; - if (strv_consume(&arg_properties, prop) < 0) + if (strv_push(&arg_properties, prop) < 0) return log_oom(); + + prop = NULL; } } @@ -6564,7 +6796,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - arg_root = optarg; + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case 'l': @@ -6598,7 +6832,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case 's': - if ((arg_signal = signal_from_string_try_harder(optarg)) < 0) { + arg_signal = signal_from_string_try_harder(optarg); + if (arg_signal < 0) { log_error("Failed to parse signal string %s.", optarg); return -EINVAL; } @@ -6650,18 +6885,29 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_STATE: { - const char *word, *state; - size_t size; + if (isempty(optarg)) + return log_error_errno(r, "--signal requires arguments."); - FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) { - char *s; + p = optarg; + for(;;) { + _cleanup_free_ char *s = NULL; - s = strndup(word, size); - if (!s) - return log_oom(); + r = extract_first_word(&p, &s, ",", 0); + if (r < 0) + return log_error_errno(r, "Failed to parse signal: %s", optarg); + + if (r == 0) + break; + + if (streq(s, "help")) { + help_states(); + return 0; + } - if (strv_consume(&arg_states, s) < 0) + if (strv_push(&arg_states, s) < 0) return log_oom(); + + s = NULL; } break; } @@ -6800,7 +7046,7 @@ static int halt_parse_argv(int argc, char *argv[]) { return 1; } -static int parse_time_spec(const char *t, usec_t *_u) { +static int parse_shutdown_time_spec(const char *t, usec_t *_u) { assert(t); assert(_u); @@ -6866,12 +7112,13 @@ static int shutdown_parse_argv(int argc, char *argv[]) { {} }; + char **wall = NULL; int c, r; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "HPrhkKt:afFc", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "HPrhkKtafFc", options, NULL)) >= 0) switch (c) { case ARG_HELP: @@ -6929,7 +7176,7 @@ static int shutdown_parse_argv(int argc, char *argv[]) { } if (argc > optind && arg_action != ACTION_CANCEL_SHUTDOWN) { - r = parse_time_spec(argv[optind], &arg_when); + r = parse_shutdown_time_spec(argv[optind], &arg_when); if (r < 0) { log_error("Failed to parse time specification: %s", argv[optind]); return r; @@ -6939,10 +7186,16 @@ static int shutdown_parse_argv(int argc, char *argv[]) { if (argc > optind && arg_action == ACTION_CANCEL_SHUTDOWN) /* No time argument for shutdown cancel */ - arg_wall = argv + optind; + wall = argv + optind; else if (argc > optind + 1) /* We skip the time argument */ - arg_wall = argv + optind + 1; + wall = argv + optind + 1; + + if (wall) { + arg_wall = strv_copy(wall); + if (!arg_wall) + return log_oom(); + } optind = argc; @@ -7006,8 +7259,7 @@ static int telinit_parse_argv(int argc, char *argv[]) { } if (optind >= argc) { - log_error("%s: required argument missing.", - program_invocation_short_name); + log_error("%s: required argument missing.", program_invocation_short_name); return -EINVAL; } @@ -7142,7 +7394,7 @@ _pure_ static int action_to_runlevel(void) { } static int talk_initctl(void) { - +#ifdef HAVE_SYSV_COMPAT struct init_request request = { .magic = INIT_MAGIC, .sleeptime = 0, @@ -7164,8 +7416,7 @@ static int talk_initctl(void) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Failed to open "INIT_FIFO": %m"); - return -errno; + return log_error_errno(errno, "Failed to open "INIT_FIFO": %m"); } r = loop_write(fd, &request, sizeof(request), false); @@ -7173,177 +7424,91 @@ static int talk_initctl(void) { return log_error_errno(r, "Failed to write to "INIT_FIFO": %m"); return 1; +#else + return 0; +#endif } -static int systemctl_main(sd_bus *bus, int argc, char *argv[], int bus_error) { - - static const struct { - const char* verb; - const enum { - MORE, - LESS, - EQUAL - } argc_cmp; - const int argc; - int (* const dispatch)(sd_bus *bus, char **args); - const enum { - NOBUS = 1, - FORCE, - } bus; - } verbs[] = { - { "list-units", MORE, 0, list_units }, - { "list-unit-files", MORE, 1, list_unit_files, NOBUS }, - { "list-sockets", MORE, 1, list_sockets }, - { "list-timers", MORE, 1, list_timers }, - { "list-jobs", MORE, 1, list_jobs }, - { "list-machines", MORE, 1, list_machines }, - { "clear-jobs", EQUAL, 1, daemon_reload }, - { "cancel", MORE, 2, cancel_job }, - { "start", MORE, 2, start_unit }, - { "stop", MORE, 2, start_unit }, - { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ - { "reload", MORE, 2, start_unit }, - { "restart", MORE, 2, start_unit }, - { "try-restart", MORE, 2, start_unit }, - { "reload-or-restart", MORE, 2, start_unit }, - { "reload-or-try-restart", MORE, 2, start_unit }, - { "force-reload", MORE, 2, start_unit }, /* For compatibility with SysV */ - { "condreload", MORE, 2, start_unit }, /* For compatibility with ALTLinux */ - { "condrestart", MORE, 2, start_unit }, /* For compatibility with RH */ - { "isolate", EQUAL, 2, start_unit }, - { "kill", MORE, 2, kill_unit }, - { "is-active", MORE, 2, check_unit_active }, - { "check", MORE, 2, check_unit_active }, - { "is-failed", MORE, 2, check_unit_failed }, - { "show", MORE, 1, show }, - { "cat", MORE, 2, cat, NOBUS }, - { "status", MORE, 1, show }, - { "help", MORE, 2, show }, - { "snapshot", LESS, 2, snapshot }, - { "delete", MORE, 2, delete_snapshot }, - { "daemon-reload", EQUAL, 1, daemon_reload }, - { "daemon-reexec", EQUAL, 1, daemon_reload }, - { "show-environment", EQUAL, 1, show_environment }, - { "set-environment", MORE, 2, set_environment }, - { "unset-environment", MORE, 2, set_environment }, - { "import-environment", MORE, 1, import_environment}, - { "halt", EQUAL, 1, start_special, FORCE }, - { "poweroff", EQUAL, 1, start_special, FORCE }, - { "reboot", MORE, 1, start_special, FORCE }, - { "kexec", EQUAL, 1, start_special }, - { "suspend", EQUAL, 1, start_special }, - { "hibernate", EQUAL, 1, start_special }, - { "hybrid-sleep", EQUAL, 1, start_special }, - { "default", EQUAL, 1, start_special }, - { "rescue", EQUAL, 1, start_special }, - { "emergency", EQUAL, 1, start_special }, - { "exit", LESS, 2, start_special }, - { "reset-failed", MORE, 1, reset_failed }, - { "enable", MORE, 2, enable_unit, NOBUS }, - { "disable", MORE, 2, enable_unit, NOBUS }, - { "is-enabled", MORE, 2, unit_is_enabled, NOBUS }, - { "reenable", MORE, 2, enable_unit, NOBUS }, - { "preset", MORE, 2, enable_unit, NOBUS }, - { "preset-all", EQUAL, 1, preset_all, NOBUS }, - { "mask", MORE, 2, enable_unit, NOBUS }, - { "unmask", MORE, 2, enable_unit, NOBUS }, - { "link", MORE, 2, enable_unit, NOBUS }, - { "switch-root", MORE, 2, switch_root }, - { "list-dependencies", LESS, 2, list_dependencies }, - { "set-default", EQUAL, 2, set_default, NOBUS }, - { "get-default", EQUAL, 1, get_default, NOBUS }, - { "set-property", MORE, 3, set_property }, - { "is-system-running", EQUAL, 1, is_system_running }, - { "add-wants", MORE, 3, add_dependency, NOBUS }, - { "add-requires", MORE, 3, add_dependency, NOBUS }, - { "edit", MORE, 2, edit, NOBUS }, +static int systemctl_main(int argc, char *argv[]) { + + static const Verb verbs[] = { + { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units }, + { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files }, + { "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets }, + { "list-timers", VERB_ANY, VERB_ANY, 0, list_timers }, + { "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs }, + { "list-machines", VERB_ANY, VERB_ANY, 0, list_machines }, + { "clear-jobs", VERB_ANY, 1, 0, daemon_reload }, + { "cancel", 2, VERB_ANY, 0, cancel_job }, + { "start", 2, VERB_ANY, 0, start_unit }, + { "stop", 2, VERB_ANY, 0, start_unit }, + { "condstop", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */ + { "reload", 2, VERB_ANY, 0, start_unit }, + { "restart", 2, VERB_ANY, 0, start_unit }, + { "try-restart", 2, VERB_ANY, 0, start_unit }, + { "reload-or-restart", 2, VERB_ANY, 0, start_unit }, + { "reload-or-try-restart", 2, VERB_ANY, 0, start_unit }, + { "force-reload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with SysV */ + { "condreload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */ + { "condrestart", 2, VERB_ANY, 0, start_unit }, /* For compatibility with RH */ + { "isolate", 2, 2, 0, start_unit }, + { "kill", 2, VERB_ANY, 0, kill_unit }, + { "is-active", 2, VERB_ANY, 0, check_unit_active }, + { "check", 2, VERB_ANY, 0, check_unit_active }, + { "is-failed", 2, VERB_ANY, 0, check_unit_failed }, + { "show", VERB_ANY, VERB_ANY, 0, show }, + { "cat", 2, VERB_ANY, 0, cat }, + { "status", VERB_ANY, VERB_ANY, 0, show }, + { "help", VERB_ANY, VERB_ANY, 0, show }, + { "snapshot", VERB_ANY, 2, 0, snapshot }, + { "delete", 2, VERB_ANY, 0, delete_snapshot }, + { "daemon-reload", VERB_ANY, 1, 0, daemon_reload }, + { "daemon-reexec", VERB_ANY, 1, 0, daemon_reload }, + { "show-environment", VERB_ANY, 1, 0, show_environment }, + { "set-environment", 2, VERB_ANY, 0, set_environment }, + { "unset-environment", 2, VERB_ANY, 0, set_environment }, + { "import-environment", VERB_ANY, VERB_ANY, 0, import_environment}, + { "halt", VERB_ANY, 1, 0, start_special }, + { "poweroff", VERB_ANY, 1, 0, start_special }, + { "reboot", VERB_ANY, 2, 0, start_special }, + { "kexec", VERB_ANY, 1, 0, start_special }, + { "suspend", VERB_ANY, 1, 0, start_special }, + { "hibernate", VERB_ANY, 1, 0, start_special }, + { "hybrid-sleep", VERB_ANY, 1, 0, start_special }, + { "default", VERB_ANY, 1, 0, start_special }, + { "rescue", VERB_ANY, 1, 0, start_special }, + { "emergency", VERB_ANY, 1, 0, start_special }, + { "exit", VERB_ANY, 2, 0, start_special }, + { "reset-failed", VERB_ANY, VERB_ANY, 0, reset_failed }, + { "enable", 2, VERB_ANY, 0, enable_unit }, + { "disable", 2, VERB_ANY, 0, enable_unit }, + { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled }, + { "reenable", 2, VERB_ANY, 0, enable_unit }, + { "preset", 2, VERB_ANY, 0, enable_unit }, + { "preset-all", VERB_ANY, 1, 0, preset_all }, + { "mask", 2, VERB_ANY, 0, enable_unit }, + { "unmask", 2, VERB_ANY, 0, enable_unit }, + { "link", 2, VERB_ANY, 0, enable_unit }, + { "switch-root", 2, VERB_ANY, 0, switch_root }, + { "list-dependencies", VERB_ANY, 2, 0, list_dependencies }, + { "set-default", 2, 2, 0, set_default }, + { "get-default", VERB_ANY, 1, 0, get_default, }, + { "set-property", 3, VERB_ANY, 0, set_property }, + { "is-system-running", VERB_ANY, 1, 0, is_system_running }, + { "add-wants", 3, VERB_ANY, 0, add_dependency }, + { "add-requires", 3, VERB_ANY, 0, add_dependency }, + { "edit", 2, VERB_ANY, 0, edit }, {} - }, *verb = verbs; - - int left; - - assert(argc >= 0); - assert(argv); - - left = argc - optind; - - /* Special rule: no arguments (left == 0) means "list-units" */ - if (left > 0) { - if (streq(argv[optind], "help") && !argv[optind+1]) { - log_error("This command expects one or more " - "unit names. Did you mean --help?"); - return -EINVAL; - } - - for (; verb->verb; verb++) - if (streq(argv[optind], verb->verb)) - goto found; - - log_error("Unknown operation '%s'.", argv[optind]); - return -EINVAL; - } -found: - - switch (verb->argc_cmp) { - - case EQUAL: - if (left != verb->argc) { - log_error("Invalid number of arguments."); - return -EINVAL; - } - - break; - - case MORE: - if (left < verb->argc) { - log_error("Too few arguments."); - return -EINVAL; - } - - break; - - case LESS: - if (left > verb->argc) { - log_error("Too many arguments."); - return -EINVAL; - } - - break; - - default: - assert_not_reached("Unknown comparison operator."); - } - - /* Require a bus connection for all operations but - * enable/disable */ - if (verb->bus == NOBUS) { - if (!bus && !avoid_bus()) { - log_error_errno(bus_error, "Failed to get D-Bus connection: %m"); - return -EIO; - } - - } else { - if (running_in_chroot() > 0) { - log_info("Running in chroot, ignoring request."); - return 0; - } - - if ((verb->bus != FORCE || arg_force <= 0) && !bus) { - log_error_errno(bus_error, "Failed to get D-Bus connection: %m"); - return -EIO; - } - } + }; - return verb->dispatch(bus, argv + optind); + return dispatch_verb(argc, argv, verbs, NULL); } -static int reload_with_fallback(sd_bus *bus) { +static int reload_with_fallback(void) { - if (bus) { - /* First, try systemd via D-Bus. */ - if (daemon_reload(bus, NULL) >= 0) - return 0; - } + /* First, try systemd via D-Bus. */ + if (daemon_reload(0, NULL, NULL) >= 0) + return 0; /* Nothing else worked, so let's try signals */ assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC); @@ -7354,25 +7519,19 @@ static int reload_with_fallback(sd_bus *bus) { return 0; } -static int start_with_fallback(sd_bus *bus) { +static int start_with_fallback(void) { - if (bus) { - /* First, try systemd via D-Bus. */ - if (start_unit(bus, NULL) >= 0) - goto done; - } + /* First, try systemd via D-Bus. */ + if (start_unit(0, NULL, NULL) >= 0) + return 0; /* Nothing else worked, so let's try * /dev/initctl */ if (talk_initctl() > 0) - goto done; + return 0; log_error("Failed to talk to init daemon."); return -EIO; - -done: - warn_wall(arg_action); - return 0; } static int halt_now(enum action a) { @@ -7380,22 +7539,22 @@ static int halt_now(enum action a) { /* The kernel will automaticall flush ATA disks and suchlike * on reboot(), but the file systems need to be synce'd * explicitly in advance. */ - sync(); + (void) sync(); /* Make sure C-A-D is handled by the kernel from this point * on... */ - reboot(RB_ENABLE_CAD); + (void) reboot(RB_ENABLE_CAD); switch (a) { case ACTION_HALT: log_info("Halting."); - reboot(RB_HALT_SYSTEM); + (void) reboot(RB_HALT_SYSTEM); return -errno; case ACTION_POWEROFF: log_info("Powering off."); - reboot(RB_POWER_OFF); + (void) reboot(RB_POWER_OFF); return -errno; case ACTION_KEXEC: @@ -7404,12 +7563,11 @@ static int halt_now(enum action a) { if (read_one_line_file(REBOOT_PARAM_FILE, ¶m) >= 0) { log_info("Rebooting with argument '%s'.", param); - syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, - LINUX_REBOOT_CMD_RESTART2, param); + (void) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param); } log_info("Rebooting."); - reboot(RB_AUTOBOOT); + (void) reboot(RB_AUTOBOOT); return -errno; } @@ -7418,17 +7576,77 @@ static int halt_now(enum action a) { } } -static int halt_main(sd_bus *bus) { +static int logind_schedule_shutdown(void) { + +#ifdef HAVE_LOGIND + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char date[FORMAT_TIMESTAMP_MAX]; + const char *action; + sd_bus *bus; int r; - r = check_inhibitors(bus, arg_action); + (void) logind_set_wall_message(); + + r = acquire_bus(BUS_FULL, &bus); if (r < 0) return r; + switch (arg_action) { + case ACTION_HALT: + action = "halt"; + break; + case ACTION_POWEROFF: + action = "poweroff"; + break; + case ACTION_KEXEC: + action = "kexec"; + break; + case ACTION_EXIT: + action = "exit"; + break; + case ACTION_REBOOT: + default: + action = "reboot"; + break; + } + + if (arg_dry) + action = strjoina("dry-", action); + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "ScheduleShutdown", + &error, + NULL, + "st", + action, + arg_when); + if (r < 0) + return log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", bus_error_message(&error, r)); + + log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when)); + return 0; +#else + log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown."); + return -ENOSYS; +#endif +} + +static int halt_main(void) { + int r; + + r = logind_check_inhibitors(arg_action); + if (r < 0) + return r; + + if (arg_when > 0) + return logind_schedule_shutdown(); + if (geteuid() != 0) { - if (arg_when > 0 || - arg_dry || - arg_force > 0) { + if (arg_dry || arg_force > 0) { log_error("Must be root."); return -EPERM; } @@ -7436,101 +7654,21 @@ static int halt_main(sd_bus *bus) { /* Try logind if we are a normal user and no special * mode applies. Maybe PolicyKit allows us to shutdown * the machine. */ - if (IN_SET(arg_action, - ACTION_POWEROFF, - ACTION_REBOOT)) { - r = reboot_with_logind(bus, arg_action); + if (IN_SET(arg_action, ACTION_POWEROFF, ACTION_REBOOT)) { + r = logind_reboot(arg_action); if (r >= 0) return r; if (IN_SET(r, -EOPNOTSUPP, -EINPROGRESS)) - /* requested operation is not supported or already in progress */ + /* requested operation is not + * supported on the local system or + * already in progress */ return r; /* on all other errors, try low-level operation */ } } - if (arg_when > 0) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; - _cleanup_free_ char *m = NULL; - const char *action; - - assert(geteuid() == 0); - - if (avoid_bus()) { - log_error("Unable to perform operation without bus connection."); - return -ENOSYS; - } - - r = sd_bus_open_system(&b); - if (r < 0) - return log_error_errno(r, "Unable to open system bus: %m"); - - m = strv_join(arg_wall, " "); - if (!m) - return log_oom(); - - r = sd_bus_call_method( - b, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "SetWallMessage", - &error, - NULL, - "sb", - m, - !arg_no_wall); - - if (r < 0) { - log_warning_errno(r, "Failed to set wall message, ignoring: %s", - bus_error_message(&error, r)); - sd_bus_error_free(&error); - } - - switch (arg_action) { - case ACTION_HALT: - action = "halt"; - break; - case ACTION_POWEROFF: - action = "poweroff"; - break; - case ACTION_KEXEC: - action = "kexec"; - break; - default: - action = "reboot"; - break; - } - - if (arg_dry) - action = strjoina("dry-", action); - - r = sd_bus_call_method( - b, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "ScheduleShutdown", - &error, - NULL, - "st", - action, - arg_when); - if (r < 0) - log_warning_errno(r, "Failed to call ScheduleShutdown in logind, proceeding with immediate shutdown: %s", - bus_error_message(&error, r)); - else { - char date[FORMAT_TIMESTAMP_MAX]; - - log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", - format_timestamp(date, sizeof(date), arg_when)); - return 0; - } - } - if (!arg_dry && !arg_force) - return start_with_fallback(bus); + return start_with_fallback(); assert(geteuid() == 0); @@ -7548,9 +7686,7 @@ static int halt_main(sd_bus *bus) { return 0; r = halt_now(arg_action); - log_error_errno(r, "Failed to reboot: %m"); - - return r; + return log_error_errno(r, "Failed to reboot: %m"); } static int runlevel_main(void) { @@ -7569,8 +7705,37 @@ static int runlevel_main(void) { return 0; } +static int logind_cancel_shutdown(void) { +#ifdef HAVE_LOGIND + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + sd_bus *bus; + int r; + + r = acquire_bus(BUS_FULL, &bus); + if (r < 0) + return r; + + (void) logind_set_wall_message(); + + r = sd_bus_call_method( + bus, + "org.freedesktop.login1", + "/org/freedesktop/login1", + "org.freedesktop.login1.Manager", + "CancelScheduledShutdown", + &error, + NULL, NULL); + if (r < 0) + return log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", bus_error_message(&error, r)); + + return 0; +#else + log_error("Not compiled with logind support, cannot cancel scheduled shutdowns."); + return -ENOSYS; +#endif +} + int main(int argc, char*argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); @@ -7586,39 +7751,26 @@ int main(int argc, char*argv[]) { if (r <= 0) goto finish; - /* /sbin/runlevel doesn't need to communicate via D-Bus, so - * let's shortcut this */ - if (arg_action == ACTION_RUNLEVEL) { - r = runlevel_main(); - goto finish; - } - if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) { log_info("Running in chroot, ignoring request."); r = 0; goto finish; } - if (!avoid_bus()) - r = bus_open_transport_systemd(arg_transport, arg_host, arg_scope != UNIT_FILE_SYSTEM, &bus); - - if (bus) - sd_bus_set_allow_interactive_authorization(bus, arg_ask_password); - /* systemctl_main() will print an error message for the bus * connection, but only if it needs to */ switch (arg_action) { case ACTION_SYSTEMCTL: - r = systemctl_main(bus, argc, argv, r); + r = systemctl_main(argc, argv); break; case ACTION_HALT: case ACTION_POWEROFF: case ACTION_REBOOT: case ACTION_KEXEC: - r = halt_main(bus); + r = halt_main(); break; case ACTION_RUNLEVEL2: @@ -7628,69 +7780,22 @@ int main(int argc, char*argv[]) { case ACTION_RESCUE: case ACTION_EMERGENCY: case ACTION_DEFAULT: - r = start_with_fallback(bus); + r = start_with_fallback(); break; case ACTION_RELOAD: case ACTION_REEXEC: - r = reload_with_fallback(bus); + r = reload_with_fallback(); break; - case ACTION_CANCEL_SHUTDOWN: { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; - _cleanup_free_ char *m = NULL; - - if (avoid_bus()) { - log_error("Unable to perform operation without bus connection."); - return -ENOSYS; - } - - r = sd_bus_open_system(&b); - if (r < 0) - return log_error_errno(r, "Unable to open system bus: %m"); - - if (arg_wall) { - m = strv_join(arg_wall, " "); - if (!m) { - r = log_oom(); - goto finish; - } - } - - r = sd_bus_call_method( - b, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "SetWallMessage", - &error, - NULL, - "sb", - m, - !arg_no_wall); - - if (r < 0) { - log_warning_errno(r, "Failed to set wall message, ignoring: %s", - bus_error_message(&error, r)); - sd_bus_error_free(&error); - } - - r = sd_bus_call_method( - b, - "org.freedesktop.login1", - "/org/freedesktop/login1", - "org.freedesktop.login1.Manager", - "CancelScheduledShutdown", - &error, - NULL, NULL); - if (r < 0) - log_warning_errno(r, "Failed to talk to logind, shutdown hasn't been cancelled: %s", - bus_error_message(&error, r)); + case ACTION_CANCEL_SHUTDOWN: + r = logind_cancel_shutdown(); break; - } case ACTION_RUNLEVEL: + r = runlevel_main(); + break; + case _ACTION_INVALID: default: assert_not_reached("Unknown action"); @@ -7705,7 +7810,10 @@ finish: strv_free(arg_states); strv_free(arg_properties); - sd_bus_default_flush_close(); + strv_free(arg_wall); + free(arg_root); + + release_busses(); return r < 0 ? EXIT_FAILURE : r; } diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 0883203ae7..43cf247cdf 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -420,7 +420,9 @@ int sd_bus_error_add_map(const sd_bus_error_map *map); /* Label escaping */ int sd_bus_path_encode(const char *prefix, const char *external_id, char **ret_path); +int sd_bus_path_encode_many(char **out, const char *path_template, ...); int sd_bus_path_decode(const char *path, const char *prefix, char **ret_external_id); +int sd_bus_path_decode_many(const char *path, const char *path_template, ...); /* Tracking peers */ diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h index 861dc8f1f4..214e77cab1 100644 --- a/src/systemd/sd-daemon.h +++ b/src/systemd/sd-daemon.h @@ -76,6 +76,8 @@ _SD_BEGIN_DECLARATIONS; */ int sd_listen_fds(int unset_environment); +int sd_listen_fds_with_names(int unset_environment, char ***names); + /* Helper call for identifying a passed file descriptor. Returns 1 if the file descriptor is a FIFO in the file system stored under the diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 38cb2a1102..fc11725821 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -24,7 +24,7 @@ ***/ #include <sys/types.h> -#include <stdint.h> +#include <inttypes.h> #include "_sd-common.h" diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index 4291fb7ebc..c0146158f3 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -22,12 +22,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/in.h> +#include <inttypes.h> #include <net/ethernet.h> +#include <netinet/in.h> +#include <sys/types.h> #include "sd-event.h" #include "sd-dhcp-lease.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + enum { SD_DHCP_CLIENT_EVENT_STOP = 0, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1, @@ -72,4 +78,6 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int pri int sd_dhcp_client_detach_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h index ed5bceecdd..38222594e7 100644 --- a/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/sd-dhcp-lease.h @@ -23,8 +23,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/in.h> +#include <inttypes.h> #include <net/ethernet.h> +#include <netinet/in.h> +#include <sys/types.h> + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; typedef struct sd_dhcp_lease sd_dhcp_lease; struct sd_dhcp_route; @@ -52,4 +58,6 @@ int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, s int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 4b0c7a1852..55bceb1ea5 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -23,10 +23,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> +#include <inttypes.h> #include <netinet/in.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; typedef struct sd_dhcp_server sd_dhcp_server; @@ -39,7 +42,7 @@ int sd_dhcp_server_attach_event(sd_dhcp_server *client, sd_event *event, int pri int sd_dhcp_server_detach_event(sd_dhcp_server *client); sd_event *sd_dhcp_server_get_event(sd_dhcp_server *client); -bool sd_dhcp_server_is_running(sd_dhcp_server *server); +int sd_dhcp_server_is_running(sd_dhcp_server *server); int sd_dhcp_server_start(sd_dhcp_server *server); int sd_dhcp_server_stop(sd_dhcp_server *server); @@ -55,4 +58,6 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t); int sd_dhcp_server_forcerenew(sd_dhcp_server *server); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 90c35ef3f6..13182a481d 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -22,12 +22,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <net/ethernet.h> +#include <sys/types.h> #include "sd-event.h" - #include "sd-dhcp6-lease.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + enum { SD_DHCP6_CLIENT_EVENT_STOP = 0, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10, @@ -48,10 +53,8 @@ int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, size_t duid_len); -int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, - bool enabled); -int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, - bool *enabled); +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option); @@ -67,4 +70,6 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client); int sd_dhcp6_client_new(sd_dhcp6_client **ret); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h index dc3df3bbf7..3fc0ee4bed 100644 --- a/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/sd-dhcp6-lease.h @@ -23,8 +23,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <inttypes.h> #include <netinet/in.h> +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + typedef struct sd_dhcp6_lease sd_dhcp6_lease; void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease); @@ -42,4 +47,6 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-hwdb.h b/src/systemd/sd-hwdb.h index 3c44b981d6..49269a073a 100644 --- a/src/systemd/sd-hwdb.h +++ b/src/systemd/sd-hwdb.h @@ -39,9 +39,11 @@ int sd_hwdb_get(sd_hwdb *hwdb, const char *modalias, const char *key, const char int sd_hwdb_seek(sd_hwdb *hwdb, const char *modalias); int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value); -/* the inverse condition avoids ambiguity of danling 'else' after the macro */ +/* the inverse condition avoids ambiguity of dangling 'else' after the macro */ #define SD_HWDB_FOREACH_PROPERTY(hwdb, modalias, key, value) \ if (sd_hwdb_seek(hwdb, modalias) < 0) { } \ else while (sd_hwdb_enumerate(hwdb, &(key), &(value)) > 0) +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-icmp6-nd.h b/src/systemd/sd-icmp6-nd.h deleted file mode 100644 index cb6c24a0cb..0000000000 --- a/src/systemd/sd-icmp6-nd.h +++ /dev/null @@ -1,79 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdicmp6ndfoo -#define foosdicmp6ndfoo - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <net/ethernet.h> - -#include "sd-event.h" - -enum { - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_NONE = 0, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_OTHER = 2, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3, - SD_ICMP6_ND_EVENT_ROUTER_ADVERTISMENT_PREFIX_EXPIRED = 4, -}; - -typedef struct sd_icmp6_nd sd_icmp6_nd; - -typedef void(*sd_icmp6_nd_callback_t)(sd_icmp6_nd *nd, int event, - void *userdata); - -int sd_icmp6_nd_set_callback(sd_icmp6_nd *nd, sd_icmp6_nd_callback_t cb, - void *userdata); -int sd_icmp6_nd_set_index(sd_icmp6_nd *nd, int interface_index); -int sd_icmp6_nd_set_mac(sd_icmp6_nd *nd, const struct ether_addr *mac_addr); - -int sd_icmp6_nd_attach_event(sd_icmp6_nd *nd, sd_event *event, int priority); -int sd_icmp6_nd_detach_event(sd_icmp6_nd *nd); -sd_event *sd_icmp6_nd_get_event(sd_icmp6_nd *nd); - -sd_icmp6_nd *sd_icmp6_nd_ref(sd_icmp6_nd *nd); -sd_icmp6_nd *sd_icmp6_nd_unref(sd_icmp6_nd *nd); -int sd_icmp6_nd_new(sd_icmp6_nd **ret); - -int sd_icmp6_prefix_match(struct in6_addr *prefix, uint8_t prefixlen, - struct in6_addr *addr); - -int sd_icmp6_ra_get_mtu(sd_icmp6_nd *nd, uint32_t *mtu); -int sd_icmp6_ra_get_prefixlen(sd_icmp6_nd *nd, const struct in6_addr *addr, - uint8_t *prefixlen); -int sd_icmp6_ra_get_expired_prefix(sd_icmp6_nd *nd, struct in6_addr **addr, - uint8_t *prefixlen); - -int sd_icmp6_nd_stop(sd_icmp6_nd *nd); -int sd_icmp6_router_solicitation_start(sd_icmp6_nd *nd); - -#define SD_ICMP6_ND_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" - -#define SD_ICMP6_ND_ADDRESS_FORMAT_VAL(address) \ - be16toh((address).s6_addr16[0]), \ - be16toh((address).s6_addr16[1]), \ - be16toh((address).s6_addr16[2]), \ - be16toh((address).s6_addr16[3]), \ - be16toh((address).s6_addr16[4]), \ - be16toh((address).s6_addr16[5]), \ - be16toh((address).s6_addr16[6]), \ - be16toh((address).s6_addr16[7]) - -#endif diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index adcb2c7b92..6337d61452 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -23,11 +23,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <netinet/in.h> #include <net/ethernet.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; enum { SD_IPV4ACD_EVENT_STOP = 0, @@ -45,11 +47,13 @@ int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index); int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); -bool sd_ipv4acd_is_running(sd_ipv4acd *ll); +int sd_ipv4acd_is_running(sd_ipv4acd *ll); int sd_ipv4acd_start(sd_ipv4acd *ll); int sd_ipv4acd_stop(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll); int sd_ipv4acd_new (sd_ipv4acd **ret); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 677505f0c6..2949f1dfb2 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -22,11 +22,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <netinet/in.h> #include <net/ethernet.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; enum { SD_IPV4LL_EVENT_STOP = 0, @@ -43,12 +45,15 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); +int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed); -bool sd_ipv4ll_is_running(sd_ipv4ll *ll); +int sd_ipv4ll_is_running(sd_ipv4ll *ll); int sd_ipv4ll_start(sd_ipv4ll *ll); int sd_ipv4ll_stop(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); int sd_ipv4ll_new (sd_ipv4ll **ret); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 0680e526b0..31651ce132 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -1,5 +1,8 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#ifndef foosdlldphfoo +#define foosdlldphfoo + /*** This file is part of systemd. @@ -20,15 +23,26 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#pragma once +#include <net/ethernet.h> +#include <inttypes.h> #include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; enum { SD_LLDP_EVENT_UPDATE_INFO = 0, }; +enum { + SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE, + SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE, + SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE, +}; + typedef struct sd_lldp sd_lldp; +typedef struct sd_lldp_packet sd_lldp_packet; typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata); @@ -43,3 +57,29 @@ int sd_lldp_detach_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata); int sd_lldp_save(sd_lldp *lldp, const char *file); + +int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); +int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); +int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl); +int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length); +int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length); +int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data); +int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length); + +/* IEEE 802.1 organizationally specific TLVs */ +int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id); +int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id); +int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length); +int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id); +int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id); + +sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); +sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); + +int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); + +int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h new file mode 100644 index 0000000000..570e1741d6 --- /dev/null +++ b/src/systemd/sd-ndisc.h @@ -0,0 +1,77 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdndiscfoo +#define foosdndiscfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <inttypes.h> +#include <net/ethernet.h> + +#include "sd-event.h" +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_NDISC_EVENT_ROUTER_ADVERTISMENT_NONE = 0, + SD_NDISC_EVENT_ROUTER_ADVERTISMENT_TIMEOUT = 1, + SD_NDISC_EVENT_ROUTER_ADVERTISMENT_OTHER = 2, + SD_NDISC_EVENT_ROUTER_ADVERTISMENT_MANAGED = 3, +}; + +typedef struct sd_ndisc sd_ndisc; + +typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, + void *userdata); + +int sd_ndisc_set_callback(sd_ndisc *nd, sd_ndisc_callback_t cb, + void *userdata); +int sd_ndisc_set_index(sd_ndisc *nd, int interface_index); +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); + +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority); +int sd_ndisc_detach_event(sd_ndisc *nd); +sd_event *sd_ndisc_get_event(sd_ndisc *nd); + +sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); +sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); +int sd_ndisc_new(sd_ndisc **ret); + +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu); + +int sd_ndisc_stop(sd_ndisc *nd); +int sd_ndisc_router_discovery_start(sd_ndisc *nd); + +#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" + +#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \ + be16toh((address).s6_addr16[0]), \ + be16toh((address).s6_addr16[1]), \ + be16toh((address).s6_addr16[2]), \ + be16toh((address).s6_addr16[3]), \ + be16toh((address).s6_addr16[4]), \ + be16toh((address).s6_addr16[5]), \ + be16toh((address).s6_addr16[6]), \ + be16toh((address).s6_addr16[7]) + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index cb462bf48f..8e1b06ee9a 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -104,6 +104,7 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump); int sd_netlink_message_is_error(sd_netlink_message *m); int sd_netlink_message_get_errno(sd_netlink_message *m); int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type); +int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags); int sd_netlink_message_is_broadcast(sd_netlink_message *m); /* rtnl */ @@ -136,6 +137,10 @@ int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope); int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family); +int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol); +int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope); +int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos); +int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table); int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len); int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len); diff --git a/src/systemd/sd-path.h b/src/systemd/sd-path.h index e238c0ce20..3280303633 100644 --- a/src/systemd/sd-path.h +++ b/src/systemd/sd-path.h @@ -24,6 +24,10 @@ #include <inttypes.h> +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + enum { /* Temporary files */ SD_PATH_TEMPORARY = 0x0ULL, @@ -84,4 +88,6 @@ enum { int sd_path_home(uint64_t type, const char *suffix, char **path); int sd_path_search(uint64_t type, const char *suffix, char ***paths); +_SD_END_DECLARATIONS; + #endif diff --git a/src/systemd/sd-pppoe.h b/src/systemd/sd-pppoe.h deleted file mode 100644 index 90878ffa27..0000000000 --- a/src/systemd/sd-pppoe.h +++ /dev/null @@ -1,53 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdpppoefoo -#define foosdpppoefoo - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see <http://www.gnu.org/licenses/>. -***/ - -#include <stdbool.h> -#include <net/ethernet.h> - -#include "sd-event.h" - -#include "sparse-endian.h" - -enum { - SD_PPPOE_EVENT_RUNNING = 0, - SD_PPPOE_EVENT_STOPPED = 1, -}; - -typedef struct sd_pppoe sd_pppoe; -typedef void (*sd_pppoe_cb_t)(sd_pppoe *ppp, int event, void *userdata); - -int sd_pppoe_detach_event(sd_pppoe *ppp); -int sd_pppoe_attach_event(sd_pppoe *ppp, sd_event *event, int priority); -int sd_pppoe_get_channel(sd_pppoe *ppp, int *channel); -int sd_pppoe_set_callback(sd_pppoe *ppp, sd_pppoe_cb_t cb, void *userdata); -int sd_pppoe_set_ifindex(sd_pppoe *ppp, int ifindex); -int sd_pppoe_set_ifname(sd_pppoe *ppp, const char *ifname); -int sd_pppoe_set_service_name(sd_pppoe *ppp, const char *service_name); -int sd_pppoe_start(sd_pppoe *ppp); -int sd_pppoe_stop(sd_pppoe *ppp); -sd_pppoe *sd_pppoe_ref(sd_pppoe *ppp); -sd_pppoe *sd_pppoe_unref(sd_pppoe *ppp); -int sd_pppoe_new (sd_pppoe **ret); - -#endif diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 80c5852e45..82c4b39efe 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -22,12 +22,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> -#include <sys/socket.h> +#include <inttypes.h> #include <netdb.h> +#include <sys/socket.h> +#include <sys/types.h> -#include "_sd-common.h" #include "sd-event.h" +#include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index aaa33354f4..008b1bde24 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -19,26 +19,31 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <pwd.h> +#include <getopt.h> #include <grp.h> -#include <shadow.h> #include <gshadow.h> -#include <getopt.h> +#include <pwd.h> +#include <shadow.h> #include <utmp.h> -#include "util.h" -#include "hashmap.h" -#include "specifier.h" -#include "path-util.h" -#include "build.h" -#include "strv.h" +#include "alloc-util.h" #include "conf-files.h" #include "copy.h" -#include "utf8.h" +#include "def.h" +#include "fd-util.h" #include "fileio-label.h" -#include "uid-range.h" -#include "selinux-util.h" #include "formats-util.h" +#include "hashmap.h" +#include "path-util.h" +#include "selinux-util.h" +#include "smack-util.h" +#include "specifier.h" +#include "string-util.h" +#include "strv.h" +#include "uid-range.h" +#include "user-util.h" +#include "utf8.h" +#include "util.h" typedef enum ItemType { ADD_USER = 'u', @@ -353,6 +358,19 @@ static int sync_rights(FILE *from, FILE *to) { return 0; } +static int rename_and_apply_smack(const char *temp_path, const char *dest_path) { + int r = 0; + if (rename(temp_path, dest_path) < 0) + return -errno; + +#ifdef SMACK_RUN_LABEL + r = mac_smack_apply(dest_path, SMACK_ATTR_ACCESS, SMACK_FLOOR_LABEL); + if (r < 0) + return r; +#endif + return r; +} + static int write_files(void) { _cleanup_fclose_ FILE *passwd = NULL, *group = NULL, *shadow = NULL, *gshadow = NULL; @@ -699,36 +717,32 @@ static int write_files(void) { /* And make the new files count */ if (group_changed) { if (group) { - if (rename(group_tmp, group_path) < 0) { - r = -errno; + r = rename_and_apply_smack(group_tmp, group_path); + if (r < 0) goto finish; - } group_tmp = mfree(group_tmp); } if (gshadow) { - if (rename(gshadow_tmp, gshadow_path) < 0) { - r = -errno; + r = rename_and_apply_smack(gshadow_tmp, gshadow_path); + if (r < 0) goto finish; - } gshadow_tmp = mfree(gshadow_tmp); } } if (passwd) { - if (rename(passwd_tmp, passwd_path) < 0) { - r = -errno; + r = rename_and_apply_smack(passwd_tmp, passwd_path); + if (r < 0) goto finish; - } passwd_tmp = mfree(passwd_tmp); } if (shadow) { - if (rename(shadow_tmp, shadow_path) < 0) { - r = -errno; + r = rename_and_apply_smack(shadow_tmp, shadow_path); + if (r < 0) goto finish; - } shadow_tmp = mfree(shadow_tmp); } @@ -929,7 +943,7 @@ static int add_user(Item *i) { } } - /* Otherwise try to reuse the group ID */ + /* Otherwise, try to reuse the group ID */ if (!i->uid_set && i->gid_set) { r = uid_is_ok((uid_t) i->gid, i->name); if (r < 0) @@ -1753,7 +1767,7 @@ static int parse_argv(int argc, char *argv[]) { {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -1767,17 +1781,12 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_ROOT: - free(arg_root); - arg_root = path_make_absolute_cwd(optarg); - if (!arg_root) - return log_oom(); - - path_kill_slashes(arg_root); + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case '?': @@ -1852,7 +1861,7 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - lock = take_password_lock(arg_root); + lock = take_etc_passwd_lock(arg_root); if (lock < 0) { log_error_errno(lock, "Failed to take lock: %m"); goto finish; diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 964750076a..042be97840 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -25,17 +25,24 @@ #include <stdio.h> #include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "hexdecoct.h" +#include "install.h" +#include "log.h" #include "mkdir.h" -#include "strv.h" -#include "path-util.h" #include "path-lookup.h" -#include "log.h" -#include "unit-name.h" -#include "special.h" -#include "hashmap.h" +#include "path-util.h" #include "set.h" -#include "install.h" +#include "special.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "unit-name.h" +#include "util.h" typedef enum RunlevelType { RUNLEVEL_UP, @@ -80,9 +87,13 @@ typedef struct SysvStub { char **conflicts; bool has_lsb; bool reload; + bool loaded; } SysvStub; static void free_sysvstub(SysvStub *s) { + if (!s) + return; + free(s->name); free(s->path); free(s->description); @@ -107,19 +118,14 @@ static void free_sysvstub_hashmapp(Hashmap **h) { } static int add_symlink(const char *service, const char *where) { - _cleanup_free_ char *from = NULL, *to = NULL; + const char *from, *to; int r; assert(service); assert(where); - from = strjoin(arg_dest, "/", service, NULL); - if (!from) - return log_oom(); - - to = strjoin(arg_dest, "/", where, ".wants/", service, NULL); - if (!to) - return log_oom(); + from = strjoina(arg_dest, "/", service); + to = strjoina(arg_dest, "/", where, ".wants/", service); mkdir_parents_label(to, 0755); @@ -127,6 +133,7 @@ static int add_symlink(const char *service, const char *where) { if (r < 0) { if (errno == EEXIST) return 0; + return -errno; } @@ -134,20 +141,19 @@ static int add_symlink(const char *service, const char *where) { } static int add_alias(const char *service, const char *alias) { - _cleanup_free_ char *link = NULL; + const char *link; int r; assert(service); assert(alias); - link = strjoin(arg_dest, "/", alias, NULL); - if (!link) - return log_oom(); + link = strjoina(arg_dest, "/", alias); r = symlink(service, link); if (r < 0) { if (errno == EEXIST) return 0; + return -errno; } @@ -155,26 +161,32 @@ static int add_alias(const char *service, const char *alias) { } static int generate_unit_file(SysvStub *s) { - char **p; + _cleanup_free_ char *before = NULL, *after = NULL, *wants = NULL, *conflicts = NULL; _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *unit = NULL, - *before = NULL, *after = NULL, - *wants = NULL, *conflicts = NULL; + const char *unit; + char **p; int r; + assert(s); + + if (!s->loaded) + return 0; + + unit = strjoina(arg_dest, "/", s->name); + before = strv_join(s->before, " "); after = strv_join(s->after, " "); wants = strv_join(s->wants, " "); conflicts = strv_join(s->conflicts, " "); - unit = strjoin(arg_dest, "/", s->name, NULL); - if (!before || !after || !wants || !conflicts || !unit) + + if (!before || !after || !wants || !conflicts) return log_oom(); /* We might already have a symlink with the same name from a Provides:, * or from backup files like /etc/init.d/foo.bak. Real scripts always win, * so remove an existing link */ if (is_symlink(unit) > 0) { - log_warning("Overwriting existing symlink %s with real service", unit); + log_warning("Overwriting existing symlink %s with real service.", unit); (void) unlink(unit); } @@ -186,9 +198,11 @@ static int generate_unit_file(SysvStub *s) { "# Automatically generated by systemd-sysv-generator\n\n" "[Unit]\n" "Documentation=man:systemd-sysv-generator(8)\n" - "SourcePath=%s\n" - "Description=%s\n", - s->path, s->description); + "SourcePath=%s\n", + s->path); + + if (s->description) + fprintf(f, "Description=%s\n", s->description); if (!isempty(before)) fprintf(f, "Before=%s\n", before); @@ -221,13 +235,17 @@ static int generate_unit_file(SysvStub *s) { if (s->reload) fprintf(f, "ExecReload=%s reload\n", s->path); + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write unit %s: %m", unit); + STRV_FOREACH(p, s->wanted_by) { r = add_symlink(s->name, *p); if (r < 0) - log_error_errno(r, "Failed to create 'Wants' symlink to %s: %m", *p); + log_warning_errno(r, "Failed to create 'Wants' symlink to %s, ignoring: %m", *p); } - return 0; + return 1; } static bool usage_contains_reload(const char *line) { @@ -257,7 +275,7 @@ static char *sysv_translate_name(const char *name) { return res; } -static int sysv_translate_facility(const char *name, const char *filename, char **_r) { +static int sysv_translate_facility(const char *name, const char *filename, char **ret) { /* We silently ignore the $ prefix here. According to the LSB * spec it simply indicates whether something is a @@ -276,31 +294,45 @@ static int sysv_translate_facility(const char *name, const char *filename, char "time", SPECIAL_TIME_SYNC_TARGET, }; - char *filename_no_sh, *e, *r; + char *filename_no_sh, *e, *m; const char *n; unsigned i; + int r; assert(name); - assert(_r); + assert(filename); + assert(ret); n = *name == '$' ? name + 1 : name; for (i = 0; i < ELEMENTSOF(table); i += 2) { - if (!streq(table[i], n)) continue; if (!table[i+1]) return 0; - r = strdup(table[i+1]); - if (!r) + m = strdup(table[i+1]); + if (!m) return log_oom(); - goto finish; + *ret = m; + return 1; + } + + /* If we don't know this name, fallback heuristics to figure + * out whether something is a target or a service alias. */ + + /* Facilities starting with $ are most likely targets */ + if (*name == '$') { + r = unit_name_build(n, NULL, ".target", ret); + if (r < 0) + return log_error_errno(r, "Failed to build name: %m"); + + return r; } - /* strip ".sh" suffix from file name for comparison */ + /* Strip ".sh" suffix from file name for comparison */ filename_no_sh = strdupa(filename); e = endswith(filename_no_sh, ".sh"); if (e) { @@ -308,103 +340,103 @@ static int sysv_translate_facility(const char *name, const char *filename, char filename = filename_no_sh; } - /* If we don't know this name, fallback heuristics to figure - * out whether something is a target or a service alias. */ - - if (*name == '$') { - int k; - - /* Facilities starting with $ are most likely targets */ - k = unit_name_build(n, NULL, ".target", &r); - if (k < 0) - return k; - - } else if (streq_ptr(n, filename)) - /* Names equaling the file name of the services are redundant */ + /* Names equaling the file name of the services are redundant */ + if (streq_ptr(n, filename)) return 0; - else - /* Everything else we assume to be normal service names */ - r = sysv_translate_name(n); - if (!r) - return -ENOMEM; -finish: - *_r = r; + /* Everything else we assume to be normal service names */ + m = sysv_translate_name(n); + if (!m) + return log_oom(); + *ret = m; return 1; } static int handle_provides(SysvStub *s, unsigned line, const char *full_text, const char *text) { - const char *word, *state_; - size_t z; int r; - FOREACH_WORD_QUOTED(word, z, text, state_) { - _cleanup_free_ char *n = NULL, *m = NULL; - UnitType t; + assert(s); + assert(full_text); + assert(text); - n = strndup(word, z); - if (!n) - return log_oom(); + for (;;) { + _cleanup_free_ char *word = NULL, *m = NULL; - r = sysv_translate_facility(n, basename(s->path), &m); + r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); if (r < 0) - return r; + return log_error_errno(r, "Failed to parse word from provides string: %m"); if (r == 0) + break; + + r = sysv_translate_facility(word, basename(s->path), &m); + if (r <= 0) /* continue on error */ continue; - t = unit_name_to_type(m); - if (t == UNIT_SERVICE) { + switch (unit_name_to_type(m)) { + + case UNIT_SERVICE: log_debug("Adding Provides: alias '%s' for '%s'", m, s->name); r = add_alias(s->name, m); if (r < 0) log_warning_errno(r, "[%s:%u] Failed to add LSB Provides name %s, ignoring: %m", s->path, line, m); - } else if (t == UNIT_TARGET) { + break; + + case UNIT_TARGET: + /* NB: SysV targets which are provided by a * service are pulled in by the services, as * an indication that the generic service is * now available. This is strictly one-way. * The targets do NOT pull in SysV services! */ + r = strv_extend(&s->before, m); if (r < 0) return log_oom(); + r = strv_extend(&s->wants, m); if (r < 0) return log_oom(); + if (streq(m, SPECIAL_NETWORK_ONLINE_TARGET)) { r = strv_extend(&s->before, SPECIAL_NETWORK_TARGET); if (r < 0) return log_oom(); } - } else if (t == _UNIT_TYPE_INVALID) + + break; + + case _UNIT_TYPE_INVALID: log_warning("Unit name '%s' is invalid", m); - else + break; + + default: log_warning("Unknown unit type for unit '%s'", m); + } } - if (!isempty(state_)) - log_error("[%s:%u] Trailing garbage in Provides, ignoring.", s->path, line); + return 0; } static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text, const char *text) { - const char *word, *state_; - size_t z; int r; - FOREACH_WORD_QUOTED(word, z, text, state_) { - _cleanup_free_ char *n = NULL, *m = NULL; - bool is_before; + assert(s); + assert(full_text); + assert(text); - n = strndup(word, z); - if (!n) - return log_oom(); + for (;;) { + _cleanup_free_ char *word = NULL, *m = NULL; + bool is_before; - r = sysv_translate_facility(n, basename(s->path), &m); - if (r < 0) { - log_warning_errno(r, "[%s:%u] Failed to translate LSB dependency %s, ignoring: %m", s->path, line, n); - continue; - } + r = extract_first_word(&text, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX); + if (r < 0) + return log_error_errno(r, "Failed to parse word from provides string: %m"); if (r == 0) + break; + + r = sysv_translate_facility(word, basename(s->path), &m); + if (r <= 0) /* continue on error */ continue; is_before = startswith_no_case(full_text, "X-Start-Before:"); @@ -414,15 +446,14 @@ static int handle_dependencies(SysvStub *s, unsigned line, const char *full_text r = strv_extend(&s->after, m); if (r < 0) return log_oom(); + r = strv_extend(&s->wants, m); } else r = strv_extend(is_before ? &s->before : &s->after, m); - if (r < 0) return log_oom(); } - if (!isempty(state_)) - log_warning("[%s:%u] Trailing garbage in %*s, ignoring.", s->path, line, (int)(strchr(full_text, ':') - full_text), full_text); + return 0; } @@ -440,24 +471,22 @@ static int load_sysv(SysvStub *s) { _cleanup_free_ char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL; char *description; bool supports_reload = false; + char l[LINE_MAX]; assert(s); f = fopen(s->path, "re"); - if (!f) - return errno == ENOENT ? 0 : -errno; - - log_debug("Loading SysV script %s", s->path); + if (!f) { + if (errno == ENOENT) + return 0; - while (!feof(f)) { - char l[LINE_MAX], *t; + return log_error_errno(errno, "Failed to open %s: %m", s->path); + } - if (!fgets(l, sizeof(l), f)) { - if (feof(f)) - break; + log_debug("Loading SysV script %s", s->path); - return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path); - } + FOREACH_LINE(l, f, goto fail) { + char *t; line++; @@ -500,29 +529,25 @@ static int load_sysv(SysvStub *s) { if (startswith_no_case(t, "description:")) { - size_t k = strlen(t); - char *d; + size_t k; const char *j; - if (t[k-1] == '\\') { + k = strlen(t); + if (k > 0 && t[k-1] == '\\') { state = DESCRIPTION; t[k-1] = 0; } j = strstrip(t+12); - if (j && *j) { - d = strdup(j); - if (!d) - return -ENOMEM; - } else - d = NULL; + if (isempty(j)) + j = NULL; - free(chkconfig_description); - chkconfig_description = d; + r = free_and_strdup(&chkconfig_description, j); + if (r < 0) + return log_oom(); } else if (startswith_no_case(t, "pidfile:")) { - - char *fn; + const char *fn; state = NORMAL; @@ -532,12 +557,9 @@ static int load_sysv(SysvStub *s) { continue; } - fn = strdup(fn); - if (!fn) - return -ENOMEM; - - free(s->pid_file); - s->pid_file = fn; + r = free_and_strdup(&s->pid_file, fn); + if (r < 0) + return log_oom(); } } else if (state == DESCRIPTION) { @@ -545,25 +567,25 @@ static int load_sysv(SysvStub *s) { /* Try to parse Red Hat style description * continuation */ - size_t k = strlen(t); + size_t k; char *j; - if (t[k-1] == '\\') + k = strlen(t); + if (k > 0 && t[k-1] == '\\') t[k-1] = 0; else state = NORMAL; j = strstrip(t); - if (j && *j) { + if (!isempty(j)) { char *d = NULL; if (chkconfig_description) d = strjoin(chkconfig_description, " ", j, NULL); else d = strdup(j); - if (!d) - return -ENOMEM; + return log_oom(); free(chkconfig_description); chkconfig_description = d; @@ -577,6 +599,7 @@ static int load_sysv(SysvStub *s) { r = handle_provides(s, line, t, t + 9); if (r < 0) return r; + } else if (startswith_no_case(t, "Required-Start:") || startswith_no_case(t, "Should-Start:") || startswith_no_case(t, "X-Start-Before:") || @@ -588,55 +611,47 @@ static int load_sysv(SysvStub *s) { if (r < 0) return r; - } else if (startswith_no_case(t, "Description:")) { - char *d, *j; + const char *j; state = LSB_DESCRIPTION; j = strstrip(t+12); - if (j && *j) { - d = strdup(j); - if (!d) - return -ENOMEM; - } else - d = NULL; + if (isempty(j)) + j = NULL; - free(long_description); - long_description = d; + r = free_and_strdup(&long_description, j); + if (r < 0) + return log_oom(); } else if (startswith_no_case(t, "Short-Description:")) { - char *d, *j; + const char *j; state = LSB; j = strstrip(t+18); - if (j && *j) { - d = strdup(j); - if (!d) - return -ENOMEM; - } else - d = NULL; + if (isempty(j)) + j = NULL; - free(short_description); - short_description = d; + r = free_and_strdup(&short_description, j); + if (r < 0) + return log_oom(); } else if (state == LSB_DESCRIPTION) { if (startswith(l, "#\t") || startswith(l, "# ")) { - char *j; + const char *j; j = strstrip(t); - if (j && *j) { + if (!isempty(j)) { char *d = NULL; if (long_description) d = strjoin(long_description, " ", t, NULL); else d = strdup(j); - if (!d) - return -ENOMEM; + return log_oom(); free(long_description); long_description = d; @@ -667,12 +682,16 @@ static int load_sysv(SysvStub *s) { d = strappend(s->has_lsb ? "LSB: " : "SYSV: ", description); if (!d) - return -ENOMEM; + return log_oom(); s->description = d; } + s->loaded = true; return 0; + +fail: + return log_error_errno(errno, "Failed to read configuration file '%s': %m", s->path); } static int fix_order(SysvStub *s, Hashmap *all_services) { @@ -682,6 +701,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { assert(s); + if (!s->loaded) + return 0; + if (s->sysv_start_priority < 0) return 0; @@ -689,6 +711,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { if (s == other) continue; + if (!other->loaded) + continue; + if (other->sysv_start_priority < 0) continue; @@ -701,13 +726,12 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { r = strv_extend(&s->after, other->name); if (r < 0) return log_oom(); - } - else if (other->sysv_start_priority > s->sysv_start_priority) { + + } else if (other->sysv_start_priority > s->sysv_start_priority) { r = strv_extend(&s->before, other->name); if (r < 0) return log_oom(); - } - else + } else continue; /* FIXME: Maybe we should compare the name here lexicographically? */ @@ -719,6 +743,9 @@ static int fix_order(SysvStub *s, Hashmap *all_services) { static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { char **path; + assert(lp); + assert(all_services); + STRV_FOREACH(path, lp->sysvinit_path) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -726,21 +753,18 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { d = opendir(*path); if (!d) { if (errno != ENOENT) - log_warning_errno(errno, "opendir(%s) failed: %m", *path); + log_warning_errno(errno, "Opening %s failed, ignoring: %m", *path); continue; } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", *path)) { _cleanup_free_ char *fpath = NULL, *name = NULL; _cleanup_(free_sysvstubp) SysvStub *service = NULL; struct stat st; int r; - if (hidden_file(de->d_name)) - continue; - if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) { - log_warning_errno(errno, "stat() failed on %s/%s: %m", *path, de->d_name); + log_warning_errno(errno, "stat() failed on %s/%s, ignoring: %m", *path, de->d_name); continue; } @@ -757,15 +781,15 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { if (hashmap_contains(all_services, name)) continue; - fpath = strjoin(*path, "/", de->d_name, NULL); - if (!fpath) - return log_oom(); - if (unit_file_lookup_state(UNIT_FILE_SYSTEM, NULL, lp, name) >= 0) { log_debug("Native unit for %s already exists, skipping", name); continue; } + fpath = strjoin(*path, "/", de->d_name, NULL); + if (!fpath) + return log_oom(); + service = new0(SysvStub, 1); if (!service) return log_oom(); @@ -773,12 +797,12 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { service->sysv_start_priority = -1; service->name = name; service->path = fpath; + name = fpath = NULL; r = hashmap_put(all_services, service->name, service); if (r < 0) return log_oom(); - name = fpath = NULL; service = NULL; } } @@ -787,43 +811,41 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) { } static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) { - char **p; - unsigned i; - _cleanup_closedir_ DIR *d = NULL; - _cleanup_free_ char *path = NULL, *fpath = NULL; - SysvStub *service; - Iterator j; Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {}; _cleanup_set_free_ Set *shutdown_services = NULL; - int r = 0; + SysvStub *service; + unsigned i; + Iterator j; + char **p; + int r; + + assert(lp); - STRV_FOREACH(p, lp->sysvrcnd_path) + STRV_FOREACH(p, lp->sysvrcnd_path) { for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) { + + _cleanup_closedir_ DIR *d = NULL; + _cleanup_free_ char *path = NULL; struct dirent *de; - free(path); path = strjoin(*p, "/", rcnd_table[i].path, NULL); - if (!path) - return -ENOMEM; - - safe_closedir(d); + if (!path) { + r = log_oom(); + goto finish; + } d = opendir(path); if (!d) { if (errno != ENOENT) - log_warning_errno(errno, "opendir(%s) failed: %m", path); + log_warning_errno(errno, "Opening %s failed, ignoring: %m", path); continue; } - while ((de = readdir(d))) { - _cleanup_free_ char *name = NULL; - + FOREACH_DIRENT(de, d, log_error_errno(errno, "Failed to enumerate directory %s, ignoring: %m", path)) { + _cleanup_free_ char *name = NULL, *fpath = NULL; int a, b; - if (hidden_file(de->d_name)) - continue; - if (de->d_name[0] != 'S' && de->d_name[0] != 'K') continue; @@ -836,10 +858,9 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic if (a < 0 || b < 0) continue; - free(fpath); fpath = strjoin(*p, "/", de->d_name, NULL); if (!fpath) { - r = -ENOMEM; + r = log_oom(); goto finish; } @@ -851,64 +872,77 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic service = hashmap_get(all_services, name); if (!service){ - log_debug("Ignoring %s symlink in %s, not generating %s.", - de->d_name, rcnd_table[i].path, name); + log_debug("Ignoring %s symlink in %s, not generating %s.", de->d_name, rcnd_table[i].path, name); continue; } if (de->d_name[0] == 'S') { - if (rcnd_table[i].type == RUNLEVEL_UP) { - service->sysv_start_priority = - MAX(a*10 + b, service->sysv_start_priority); - } + if (rcnd_table[i].type == RUNLEVEL_UP) + service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority); r = set_ensure_allocated(&runlevel_services[i], NULL); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } r = set_put(runlevel_services[i], service); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } } else if (de->d_name[0] == 'K' && (rcnd_table[i].type == RUNLEVEL_DOWN)) { r = set_ensure_allocated(&shutdown_services, NULL); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } r = set_put(shutdown_services, service); - if (r < 0) + if (r < 0) { + log_oom(); goto finish; + } } } } + } for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) SET_FOREACH(service, runlevel_services[i], j) { r = strv_extend(&service->before, rcnd_table[i].target); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } r = strv_extend(&service->wanted_by, rcnd_table[i].target); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } } SET_FOREACH(service, shutdown_services, j) { r = strv_extend(&service->before, SPECIAL_SHUTDOWN_TARGET); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } r = strv_extend(&service->conflicts, SPECIAL_SHUTDOWN_TARGET); - if (r < 0) - return log_oom(); + if (r < 0) { + log_oom(); + goto finish; + } } r = 0; finish: - for (i = 0; i < ELEMENTSOF(rcnd_table); i++) set_free(runlevel_services[i]); @@ -916,11 +950,11 @@ finish: } int main(int argc, char *argv[]) { - int r, q; - _cleanup_lookup_paths_free_ LookupPaths lp = {}; _cleanup_(free_sysvstub_hashmapp) Hashmap *all_services = NULL; + _cleanup_lookup_paths_free_ LookupPaths lp = {}; SysvStub *service; Iterator j; + int r; if (argc > 1 && argc != 4) { log_error("This program takes three or no arguments."); @@ -938,43 +972,34 @@ int main(int argc, char *argv[]) { r = lookup_paths_init(&lp, MANAGER_SYSTEM, true, NULL, NULL, NULL, NULL); if (r < 0) { - log_error("Failed to find lookup paths."); - return EXIT_FAILURE; + log_error_errno(r, "Failed to find lookup paths: %m"); + goto finish; } all_services = hashmap_new(&string_hash_ops); if (!all_services) { - log_oom(); - return EXIT_FAILURE; + r = log_oom(); + goto finish; } r = enumerate_sysv(&lp, all_services); - if (r < 0) { - log_error("Failed to generate units for all init scripts."); - return EXIT_FAILURE; - } + if (r < 0) + goto finish; r = set_dependencies_from_rcnd(&lp, all_services); - if (r < 0) { - log_error("Failed to read runlevels from rcnd links."); - return EXIT_FAILURE; - } + if (r < 0) + goto finish; - HASHMAP_FOREACH(service, all_services, j) { - q = load_sysv(service); - if (q < 0) - continue; - } + HASHMAP_FOREACH(service, all_services, j) + (void) load_sysv(service); HASHMAP_FOREACH(service, all_services, j) { - q = fix_order(service, all_services); - if (q < 0) - continue; - - q = generate_unit_file(service); - if (q < 0) - continue; + (void) fix_order(service, all_services); + (void) generate_unit_file(service); } - return EXIT_SUCCESS; + r = 0; + +finish: + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/test/test-af-list.c b/src/test/test-af-list.c index d69104f540..aeaa0929b1 100644 --- a/src/test/test-af-list.c +++ b/src/test/test-af-list.c @@ -17,17 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <string.h> +#include <sys/socket.h> #include "macro.h" +#include "string-util.h" #include "util.h" static const struct af_name* lookup_af(register const char *str, register unsigned int len); +#include "af-from-name.h" #include "af-list.h" #include "af-to-name.h" -#include "af-from-name.h" int main(int argc, const char *argv[]) { @@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) { assert_se(af_from_name("huddlduddl") == AF_UNSPEC); return 0; -}
\ No newline at end of file +} diff --git a/src/test/test-arphrd-list.c b/src/test/test-arphrd-list.c index d7c8eaa4a9..f3989ad201 100644 --- a/src/test/test-arphrd-list.c +++ b/src/test/test-arphrd-list.c @@ -21,13 +21,14 @@ #include <string.h> #include "macro.h" +#include "string-util.h" #include "util.h" static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len); +#include "arphrd-from-name.h" #include "arphrd-list.h" #include "arphrd-to-name.h" -#include "arphrd-from-name.h" int main(int argc, const char *argv[]) { @@ -45,4 +46,4 @@ int main(int argc, const char *argv[]) { assert_se(arphrd_from_name("huddlduddl") == 0); return 0; -}
\ No newline at end of file +} diff --git a/src/test/test-async.c b/src/test/test-async.c index abd36d693c..ada6d67c42 100644 --- a/src/test/test-async.c +++ b/src/test/test-async.c @@ -20,8 +20,9 @@ #include <unistd.h> #include "async.h" -#include "util.h" +#include "fileio.h" #include "macro.h" +#include "util.h" static bool test_async = false; diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index e4771c9dd7..33356f8387 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -21,23 +21,26 @@ #include <fcntl.h> -#include "log.h" +#include "btrfs-util.h" +#include "fd-util.h" #include "fileio.h" +#include "log.h" +#include "parse-util.h" +#include "string-util.h" #include "util.h" -#include "btrfs-util.h" int main(int argc, char *argv[]) { + BtrfsQuotaInfo quota; int r, fd; fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); if (fd < 0) log_error_errno(errno, "Failed to open root directory: %m"); else { - BtrfsSubvolInfo info; - BtrfsQuotaInfo quota; char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX]; + BtrfsSubvolInfo info; - r = btrfs_subvol_get_info_fd(fd, &info); + r = btrfs_subvol_get_info_fd(fd, 0, &info); if (r < 0) log_error_errno(r, "Failed to get subvolume info: %m"); else { @@ -45,7 +48,7 @@ int main(int argc, char *argv[]) { log_info("read-only (search): %s", yes_no(info.read_only)); } - r = btrfs_subvol_get_quota_fd(fd, "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..a69698d4ea 100644 --- a/src/test/test-conf-files.c +++ b/src/test/test-conf-files.c @@ -19,14 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdarg.h> +#include <stdio.h> +#include "alloc-util.h" #include "conf-files.h" +#include "fs-util.h" #include "macro.h" +#include "rm-rf.h" +#include "string-util.h" #include "strv.h" +#include "user-util.h" #include "util.h" -#include "rm-rf.h" static void setup_test_dir(char *tmp_dir, const char *files, ...) { va_list ap; diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 463906d304..b3a4c40339 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -18,10 +18,11 @@ ***/ #include "conf-parser.h" +#include "log.h" #include "macro.h" -#include "util.h" +#include "string-util.h" #include "strv.h" -#include "log.h" +#include "util.h" static void test_config_parse_path_one(const char *rvalue, const char *expected) { char *path = NULL; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index a03a68bd43..ad57cb0202 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -19,14 +19,18 @@ #include <unistd.h> +#include "alloc-util.h" #include "copy.h" -#include "path-util.h" +#include "fd-util.h" #include "fileio.h" +#include "fs-util.h" +#include "macro.h" #include "mkdir.h" +#include "path-util.h" +#include "rm-rf.h" +#include "string-util.h" #include "strv.h" -#include "macro.h" #include "util.h" -#include "rm-rf.h" static void test_copy_file(void) { _cleanup_free_ char *buf = NULL; diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index 7e0ac754d1..45fb554445 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -21,9 +21,22 @@ #include <unistd.h> -#include "systemd/sd-daemon.h" +#include "sd-daemon.h" + +#include "strv.h" int main(int argc, char*argv[]) { + _cleanup_strv_free_ char **l = NULL; + int n, i; + + n = sd_listen_fds_with_names(false, &l); + if (n < 0) { + log_error_errno(n, "Failed to get listening fds: %m"); + return EXIT_FAILURE; + } + + for (i = 0; i < n; i++) + log_info("fd=%i name=%s\n", SD_LISTEN_FDS_START + i, l[i]); sd_notify(0, "STATUS=Starting up"); @@ -49,5 +62,5 @@ int main(int argc, char*argv[]) { "STOPPING=1"); sleep(5); - return 0; + return EXIT_SUCCESS; } diff --git a/src/test/test-date.c b/src/test/test-date.c index 00b569080c..c6d8bf82ea 100644 --- a/src/test/test-date.c +++ b/src/test/test-date.c @@ -21,14 +21,16 @@ #include <string.h> +#include "alloc-util.h" +#include "string-util.h" #include "util.h" -static void test_one(const char *p) { +static void test_should_pass(const char *p) { usec_t t, q; char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX]; assert_se(parse_timestamp(p, &t) >= 0); - format_timestamp(buf, sizeof(buf), t); + format_timestamp_us(buf, sizeof(buf), t); log_info("%s", buf); /* Chop off timezone */ @@ -42,23 +44,57 @@ static void test_one(const char *p) { assert_se(parse_timestamp(buf, &q) >= 0); } +static void test_should_parse(const char *p) { + usec_t t; + + assert_se(parse_timestamp(p, &t) >= 0); +} + +static void test_should_fail(const char *p) { + usec_t t; + + assert_se(parse_timestamp(p, &t) < 0); +} + +static void test_one(const char *p) { + _cleanup_free_ char *with_utc; + + log_info("Test: %s", p); + with_utc = strjoin(p, " UTC", NULL); + test_should_pass(p); + test_should_pass(with_utc); +} + +static void test_one_noutc(const char *p) { + _cleanup_free_ char *with_utc; + + log_info("Test: %s", p); + with_utc = strjoin(p, " UTC", NULL); + test_should_pass(p); + test_should_fail(with_utc); +} + int main(int argc, char *argv[]) { test_one("17:41"); test_one("18:42:44"); + test_one("18:42:44.0"); + test_one("18:42:44.999999999999"); test_one("12-10-02 12:13:14"); test_one("12-10-2 12:13:14"); test_one("12-10-03 12:13"); test_one("2012-12-30 18:42"); test_one("2012-10-02"); test_one("Tue 2012-10-02"); - test_one("now"); + test_one_noutc("now"); test_one("yesterday"); test_one("today"); test_one("tomorrow"); - test_one("+2d"); - test_one("+2y 4d"); - test_one("5months ago"); - test_one("@1395716396"); + test_one_noutc("+2d"); + test_one_noutc("+2y 4d"); + test_one_noutc("5months ago"); + test_one_noutc("@1395716396"); + test_should_parse("today UTC"); + test_should_fail("today UTC UTC"); return 0; } diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c index 59ba4be087..646b168cc0 100644 --- a/src/test/test-device-nodes.c +++ b/src/test/test-device-nodes.c @@ -21,7 +21,9 @@ #include <sys/types.h> +#include "alloc-util.h" #include "device-nodes.h" +#include "string-util.h" #include "util.h" /* helpers for test_encode_devnode_name */ diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index 2193eb6f7d..d5778748a0 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "macro.h" +#include "alloc-util.h" #include "dns-domain.h" +#include "macro.h" +#include "string-util.h" static void test_dns_label_unescape_one(const char *what, const char *expect, size_t buffer_sz, int ret) { char buffer[buffer_sz]; diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c index 27df9089c3..c597d5aecd 100644 --- a/src/test/test-ellipsize.c +++ b/src/test/test-ellipsize.c @@ -21,9 +21,11 @@ #include <stdio.h> -#include "util.h" -#include "terminal-util.h" +#include "alloc-util.h" #include "def.h" +#include "string-util.h" +#include "terminal-util.h" +#include "util.h" static void test_one(const char *p) { _cleanup_free_ char *t; diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c index 2e28c0c49b..c1315bbf9f 100644 --- a/src/test/test-env-replace.c +++ b/src/test/test-env-replace.c @@ -21,9 +21,10 @@ #include <string.h> -#include "util.h" -#include "strv.h" #include "env-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" static void test_strv_env_delete(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; @@ -118,6 +119,8 @@ static void test_replace_env_arg(void) { "$FOO$FOO", "${FOO}${BAR}", "${FOO", + "FOO$$${FOO}", + "$$FOO${FOO}", NULL }; _cleanup_strv_free_ char **r = NULL; @@ -133,7 +136,9 @@ static void test_replace_env_arg(void) { assert_se(streq(r[6], "BAR")); assert_se(streq(r[7], "BAR BARwaldo")); assert_se(streq(r[8], "${FOO")); - assert_se(strv_length(r) == 9); + assert_se(streq(r[9], "FOO$BAR BAR")); + assert_se(streq(r[10], "$FOOBAR BAR")); + assert_se(strv_length(r) == 11); } static void test_env_clean(void) { diff --git a/src/test/test-execute.c b/src/test/test-execute.c index fa6336f1fb..e2ec53ee51 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -17,14 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <grp.h> +#include <pwd.h> #include <stdio.h> +#include <sys/types.h> -#include "unit.h" -#include "manager.h" -#include "util.h" +#include "fileio.h" +#include "fs-util.h" #include "macro.h" +#include "manager.h" #include "mkdir.h" +#include "path-util.h" #include "rm-rf.h" +#include "unit.h" +#include "util.h" typedef void (*test_function_t)(Manager *m); @@ -123,11 +129,17 @@ static void test_exec_systemcallerrornumber(Manager *m) { } static void test_exec_user(Manager *m) { - test(m, "exec-user.service", 0, CLD_EXITED); + if (getpwnam("nobody")) + test(m, "exec-user.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_user, could not find nobody user: %m"); } static void test_exec_group(Manager *m) { - test(m, "exec-group.service", 0, CLD_EXITED); + if (getgrnam("nobody")) + test(m, "exec-group.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_group, could not find nobody group: %m"); } static void test_exec_environment(Manager *m) { @@ -136,6 +148,26 @@ static void test_exec_environment(Manager *m) { test(m, "exec-environment-empty.service", 0, CLD_EXITED); } +static void test_exec_environmentfile(Manager *m) { + static const char e[] = + "VAR1='word1 word2'\n" + "VAR2=word3 \n" + "# comment1\n" + "\n" + "; comment2\n" + " ; # comment3\n" + "line without an equal\n" + "VAR3='$word 5 6'\n"; + int r; + + r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE); + assert_se(r == 0); + + test(m, "exec-environmentfile.service", 0, CLD_EXITED); + + unlink("/tmp/test-exec_environmentfile.conf"); +} + static void test_exec_umask(Manager *m) { test(m, "exec-umask-default.service", 0, CLD_EXITED); test(m, "exec-umask-0177.service", 0, CLD_EXITED); @@ -144,7 +176,51 @@ static void test_exec_umask(Manager *m) { static void test_exec_runtimedirectory(Manager *m) { test(m, "exec-runtimedirectory.service", 0, CLD_EXITED); test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED); - test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + if (getgrnam("nobody")) + test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED); + else + log_error_errno(errno, "Skipping test_exec_runtimedirectory-owner, could not find nobody group: %m"); +} + +static void test_exec_capabilityboundingset(Manager *m) { + int r; + + /* We use capsh to test if the capabilities are + * properly set, so be sure that it exists */ + r = find_binary("capsh", NULL); + if (r < 0) { + log_error_errno(r, "Skipping test_exec_capabilityboundingset, could not find capsh binary: %m"); + return; + } + + test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED); + test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED); +} + +static void test_exec_privatenetwork(Manager *m) { + int r; + + r = find_binary("ip", NULL); + if (r < 0) { + log_error_errno(r, "Skipping test_exec_privatenetwork, could not find ip binary: %m"); + return; + } + + test(m, "exec-privatenetwork-yes.service", 0, CLD_EXITED); +} + +static void test_exec_oomscoreadjust(Manager *m) { + test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED); + test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED); +} + +static void test_exec_ioschedulingclass(Manager *m) { + test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED); + test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED); } int main(int argc, char *argv[]) { @@ -154,13 +230,18 @@ int main(int argc, char *argv[]) { test_exec_ignoresigpipe, test_exec_privatetmp, test_exec_privatedevices, + test_exec_privatenetwork, test_exec_systemcallfilter, test_exec_systemcallerrornumber, test_exec_user, test_exec_group, test_exec_environment, + test_exec_environmentfile, test_exec_umask, test_exec_runtimedirectory, + test_exec_capabilityboundingset, + test_exec_oomscoreadjust, + test_exec_ioschedulingclass, NULL, }; test_function_t *test = NULL; @@ -177,7 +258,7 @@ int main(int argc, char *argv[]) { } assert_se(setenv("XDG_RUNTIME_DIR", "/tmp/", 1) == 0); - assert_se(set_unit_path(TEST_DIR) >= 0); + assert_se(set_unit_path(TEST_DIR "/test-execute/") >= 0); r = manager_new(MANAGER_USER, true, &m); if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c new file mode 100644 index 0000000000..09698c07c7 --- /dev/null +++ b/src/test/test-extract-word.c @@ -0,0 +1,546 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdlib.h> +#include <string.h> + +#include "extract-word.h" +#include "log.h" +#include "string-util.h" + +static void test_extract_first_word(void) { + const char *p, *original; + char *t; + + p = original = "foobar waldo"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 7); + + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\"foobar\"")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "\'waldo\'")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, NULL, 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\"")); + free(t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'"; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'")); + free(t); + assert_se(isempty(p)); + + p = original = "\'"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, 0) == 1); + assert_se(streq(t, "\'fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "\"fooo"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "yay\'foo\'bar"; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "yay\'foo\'bar")); + free(t); + assert_se(isempty(p)); + + p = original = "yay\'foo\'bar"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "yayfoobar")); + free(t); + assert_se(isempty(p)); + + p = original = " foobar "; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "foo\ba\x6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word(&p, &t, NULL, 0) > 0); + assert_se(streq(t, "foobax6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "föo")); + free(t); + assert_se(p == original + 13); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0); + assert_se(streq(t, "pi\360\237\222\251le")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "foo::bar"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "foo")); + free(t); + assert_se(p == original + 5); + + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "bar")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "foo\\:bar::waldo"; + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", 0) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word(&p, &t, ":", 0) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "foo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); + assert_se(p == original + 5); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(isempty(p)); + + p = original = "\\w+\\b"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(isempty(p)); + + p = original = "-N ''"; + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "-N")); + free(t); + assert_se(p == original + 3); + + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); + assert_se(streq(t, "")); + free(t); + assert_se(isempty(p)); + + p = original = ":foo\\:bar::waldo:"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 1); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "foo:bar")); + free(t); + assert_se(p == original + 10); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(t); + assert_se(streq(t, "")); + free(t); + assert_se(p == original + 11); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "waldo")); + free(t); + assert_se(p == original + 17); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); + assert_se(streq(t, "")); + free(t); + assert_se(p == NULL); + + assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0); + assert_se(!t); + assert_se(!p); +} + +static void test_extract_first_word_and_warn(void) { + const char *p, *original; + char *t; + + p = original = "foobar waldo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 7); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\"foobar\" \'waldo\'"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobar")); + free(t); + assert_se(p == original + 9); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "waldo")); + free(t); + assert_se(isempty(p)); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); + assert_se(!t); + assert_se(isempty(p)); + + p = original = "\""; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 1); + + p = original = "\'fooo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\'fooo"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo\ba\x6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " foo\\ba\\x6ar "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foobax6ar")); + free(t); + assert_se(isempty(p)); + + p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "föo")); + free(t); + assert_se(p == original + 13); + + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "pi\360\237\222\251le")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); + assert_se(p == original + 5); + + p = original = "\"foo\\"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "foo")); + free(t); + assert_se(isempty(p)); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo bar")); + free(t); + assert_se(p == original + 10); + + p = original = "fooo\\ bar quux"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "fooo\\ bar")); + free(t); + assert_se(p == original + 10); + + p = original = "\\w+@\\K[\\d.]+"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+@\\K[\\d.]+")); + free(t); + assert_se(isempty(p)); + + p = original = "\\w+\\b"; + assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); + assert_se(streq(t, "\\w+\b")); + free(t); + assert_se(isempty(p)); +} + +static void test_extract_many_words(void) { + const char *p, *original; + char *a, *b, *c; + + p = original = "foobar waldi piep"; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + assert_se(streq_ptr(b, "waldi")); + assert_se(streq_ptr(c, "piep")); + free(a); + free(b); + free(c); + + p = original = "'foobar' wa\"ld\"i "; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "'foobar'")); + assert_se(streq_ptr(b, "wa\"ld\"i")); + assert_se(streq_ptr(c, NULL)); + free(a); + free(b); + + p = original = "'foobar' wa\"ld\"i "; + assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + assert_se(streq_ptr(b, "waldi")); + assert_se(streq_ptr(c, NULL)); + free(a); + free(b); + + p = original = ""; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); + assert_se(streq_ptr(a, NULL)); + assert_se(streq_ptr(b, NULL)); + assert_se(streq_ptr(c, NULL)); + + p = original = " "; + assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); + assert_se(isempty(p)); + assert_se(streq_ptr(a, NULL)); + assert_se(streq_ptr(b, NULL)); + assert_se(streq_ptr(c, NULL)); + + p = original = "foobar"; + assert_se(extract_many_words(&p, NULL, 0, NULL) == 0); + assert_se(p == original); + + p = original = "foobar waldi"; + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); + assert_se(p == original+7); + assert_se(streq_ptr(a, "foobar")); + free(a); + + p = original = " foobar "; + assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); + assert_se(isempty(p)); + assert_se(streq_ptr(a, "foobar")); + free(a); +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_extract_first_word(); + test_extract_first_word_and_warn(); + test_extract_many_words(); + + return 0; +} diff --git a/src/test/test-fdset.c b/src/test/test-fdset.c index 242c5d9dc2..282aab1246 100644 --- a/src/test/test-fdset.c +++ b/src/test/test-fdset.c @@ -20,9 +20,11 @@ #include <fcntl.h> #include <unistd.h> +#include "fd-util.h" #include "fdset.h" -#include "util.h" +#include "fileio.h" #include "macro.h" +#include "util.h" static void test_fdset_new_fill(void) { int fd = -1; diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index be3a87958f..e588681b86 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -23,13 +23,17 @@ #include <fcntl.h> #include <unistd.h> -#include "util.h" -#include "process-util.h" +#include "alloc-util.h" +#include "ctype.h" +#include "def.h" +#include "env-util.h" +#include "fd-util.h" #include "fileio.h" +#include "parse-util.h" +#include "process-util.h" +#include "string-util.h" #include "strv.h" -#include "env-util.h" -#include "def.h" -#include "ctype.h" +#include "util.h" static void test_parse_env_file(void) { char t[] = "/tmp/test-fileio-in-XXXXXX", @@ -241,18 +245,18 @@ static void test_status_field(void) { unsigned long long total = 0, buffers = 0; int r; - assert_se(get_status_field("/proc/self/status", "\nThreads:", &t) == 0); + assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0); puts(t); assert_se(streq(t, "1")); - r = get_status_field("/proc/meminfo", "MemTotal:", &p); + r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p); if (r != -ENOENT) { assert_se(r == 0); puts(p); assert_se(safe_atollu(p, &total) == 0); } - r = get_status_field("/proc/meminfo", "\nBuffers:", &s); + r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s); if (r != -ENOENT) { assert_se(r == 0); puts(s); @@ -263,7 +267,7 @@ static void test_status_field(void) { assert_se(buffers < total); /* Seccomp should be a good test for field full of zeros. */ - r = get_status_field("/proc/meminfo", "\nSeccomp:", &z); + r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z); if (r != -ENOENT) { assert_se(r == 0); puts(z); diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index 50e5dee0a7..27816ac779 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -19,9 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "fstab-util.h" -#include "util.h" #include "log.h" +#include "string-util.h" +#include "util.h" /* int fstab_filter_options(const char *opts, const char *names, diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index 057b6c1dc1..6bf33306a9 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -17,9 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" +#include "hashmap.h" +#include "string-util.h" #include "strv.h" #include "util.h" -#include "hashmap.h" void test_hashmap_funcs(void); @@ -692,8 +694,8 @@ static void test_hashmap_get2(void) { hashmap_free_free_free(m); } -static unsigned long crippled_hashmap_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) { - return trivial_hash_func(p, hash_key) & 0xff; +static void crippled_hashmap_func(const void *p, struct siphash *state) { + return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p) & 0xff), state); } static const struct hash_ops crippled_hashmap_ops = { @@ -710,7 +712,7 @@ static void test_hashmap_many(void) { unsigned n_entries; } tests[] = { { .ops = NULL, .n_entries = 1 << 20 }, - { .ops = &crippled_hashmap_ops, .n_entries = 1 << 11 }, + { .ops = &crippled_hashmap_ops, .n_entries = 1 << 14 }, }; diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c index 6f5ef2615e..590175433c 100644 --- a/src/test/test-hostname-util.c +++ b/src/test/test-hostname-util.c @@ -21,9 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "alloc-util.h" #include "fileio.h" #include "hostname-util.h" +#include "string-util.h" +#include "util.h" static void test_hostname_is_valid(void) { assert_se(hostname_is_valid("foobar", false)); diff --git a/src/test/test-id128.c b/src/test/test-id128.c index a6a0cd77a1..32cf3f80ca 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -21,11 +21,13 @@ #include <string.h> -#include "systemd/sd-id128.h" +#include "sd-daemon.h" +#include "sd-id128.h" -#include "util.h" +#include "alloc-util.h" #include "macro.h" -#include "sd-daemon.h" +#include "string-util.h" +#include "util.h" #define ID128_WALDI SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10) #define STR_WALDI "0102030405060708090a0b0c0d0e0f10" diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 4944bf6ad9..5841cb3fb1 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -19,8 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "clean-ipc.h" +#include "user-util.h" +#include "util.h" int main(int argc, char *argv[]) { uid_t uid; diff --git a/src/test/test-json.c b/src/test/test-json.c index 1058c583c3..3995224eea 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -21,8 +21,10 @@ #include <math.h> -#include "util.h" +#include "alloc-util.h" #include "json.h" +#include "string-util.h" +#include "util.h" static void test_one(const char *data, ...) { void *state = NULL; diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index 34c49b969a..350eaf734d 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -18,12 +18,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <unistd.h> #include <getopt.h> +#include <stdio.h> #include <sys/epoll.h> +#include <unistd.h> #include "libudev.h" + +#include "string-util.h" #include "udev-util.h" #include "util.h" diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 7d7e08dc5d..5a12e959d4 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -21,9 +21,12 @@ #include <sys/socket.h> +#include "alloc-util.h" +#include "fd-util.h" #include "namespace.h" -#include "util.h" #include "process-util.h" +#include "string-util.h" +#include "util.h" static void test_tmpdir(const char *id, const char *A, const char *B) { _cleanup_free_ char *a, *b; diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c index 2879d7450f..a1e8774063 100644 --- a/src/test/test-netlink-manual.c +++ b/src/test/test-netlink-manual.c @@ -20,15 +20,16 @@ ***/ #include <arpa/inet.h> -#include <net/if.h> +#include <libkmod.h> #include <linux/ip.h> +#include <net/if.h> #include <linux/if_tunnel.h> -#include <libkmod.h> -#include "util.h" -#include "macro.h" #include "sd-netlink.h" +#include "macro.h" +#include "util.h" + static int load_module(const char *mod_name) { struct kmod_ctx *ctx; struct kmod_list *list = NULL, *l; diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c new file mode 100644 index 0000000000..d3ae0599ab --- /dev/null +++ b/src/test/test-parse-util.c @@ -0,0 +1,452 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2013 Thomas H.P. Andersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <locale.h> +#include <math.h> + +#include "log.h" +#include "parse-util.h" + +static void test_parse_boolean(void) { + assert_se(parse_boolean("1") == 1); + assert_se(parse_boolean("y") == 1); + assert_se(parse_boolean("Y") == 1); + assert_se(parse_boolean("yes") == 1); + assert_se(parse_boolean("YES") == 1); + assert_se(parse_boolean("true") == 1); + assert_se(parse_boolean("TRUE") == 1); + assert_se(parse_boolean("on") == 1); + assert_se(parse_boolean("ON") == 1); + + assert_se(parse_boolean("0") == 0); + assert_se(parse_boolean("n") == 0); + assert_se(parse_boolean("N") == 0); + assert_se(parse_boolean("no") == 0); + assert_se(parse_boolean("NO") == 0); + assert_se(parse_boolean("false") == 0); + assert_se(parse_boolean("FALSE") == 0); + assert_se(parse_boolean("off") == 0); + assert_se(parse_boolean("OFF") == 0); + + assert_se(parse_boolean("garbage") < 0); + assert_se(parse_boolean("") < 0); + assert_se(parse_boolean("full") < 0); +} + +static void test_parse_pid(void) { + int r; + pid_t pid; + + r = parse_pid("100", &pid); + assert_se(r == 0); + assert_se(pid == 100); + + r = parse_pid("0x7FFFFFFF", &pid); + assert_se(r == 0); + assert_se(pid == 2147483647); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("-100", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ + r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); + assert_se(r == -ERANGE); + assert_se(pid == 65); + + r = parse_pid("junk", &pid); + assert_se(r == -EINVAL); +} + +static void test_parse_mode(void) { + mode_t m; + + assert_se(parse_mode("-1", &m) < 0); + assert_se(parse_mode("", &m) < 0); + assert_se(parse_mode("888", &m) < 0); + assert_se(parse_mode("77777", &m) < 0); + + assert_se(parse_mode("544", &m) >= 0 && m == 0544); + assert_se(parse_mode("777", &m) >= 0 && m == 0777); + assert_se(parse_mode("7777", &m) >= 0 && m == 07777); + assert_se(parse_mode("0", &m) >= 0 && m == 0); +} + +static void test_parse_size(void) { + uint64_t bytes; + + assert_se(parse_size("111", 1024, &bytes) == 0); + assert_se(bytes == 111); + + assert_se(parse_size("111.4", 1024, &bytes) == 0); + assert_se(bytes == 111); + + assert_se(parse_size(" 112 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0); + assert_se(bytes == 112); + + assert_se(parse_size("3.5 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024 + 512); + + assert_se(parse_size("3. K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size("3.0 K", 1024, &bytes) == 0); + assert_se(bytes == 3*1024); + + assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL); + + assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0); + assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512); + + assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("3.5G3B", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3); + + assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0); + assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4); + + assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("4T3G3B", 1024, &bytes) == 0); + assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); + + assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0); + assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); + + assert_se(parse_size("12P", 1024, &bytes) == 0); + assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024); + + assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("3E 2P", 1024, &bytes) == 0); + assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024); + + assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL); + + assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); + assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE); + + assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); +} + +static void test_parse_range(void) { + unsigned lower, upper; + + /* Successful cases */ + assert_se(parse_range("111", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 111); + + assert_se(parse_range("111-123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("123-111", &lower, &upper) == 0); + assert_se(lower == 123); + assert_se(upper == 111); + + assert_se(parse_range("123-123", &lower, &upper) == 0); + assert_se(lower == 123); + assert_se(upper == 123); + + assert_se(parse_range("0", &lower, &upper) == 0); + assert_se(lower == 0); + assert_se(upper == 0); + + assert_se(parse_range("0-15", &lower, &upper) == 0); + assert_se(lower == 0); + assert_se(upper == 15); + + assert_se(parse_range("15-0", &lower, &upper) == 0); + assert_se(lower == 15); + assert_se(upper == 0); + + assert_se(parse_range("128-65535", &lower, &upper) == 0); + assert_se(lower == 128); + assert_se(upper == 65535); + + assert_se(parse_range("1024-4294967295", &lower, &upper) == 0); + assert_se(lower == 1024); + assert_se(upper == 4294967295); + + /* Leading whitespace is acceptable */ + assert_se(parse_range(" 111", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 111); + + assert_se(parse_range(" 111-123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("111- 123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range("\t111-\t123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + assert_se(parse_range(" \t 111- \t 123", &lower, &upper) == 0); + assert_se(lower == 111); + assert_se(upper == 123); + + /* Error cases, make sure they fail as expected */ + lower = upper = 9999; + assert_se(parse_range("111garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("garbage111", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123garbage", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111garbage-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Empty string */ + lower = upper = 9999; + assert_se(parse_range("", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* 111--123 will pass -123 to safe_atou which returns -ERANGE for negative */ + assert_se(parse_range("111--123", &lower, &upper) == -ERANGE); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("-111-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111.4-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123.4", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111,4-123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123,4", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Error on trailing dash */ + assert_se(parse_range("111-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123-", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111--", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111- ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Whitespace is not a separator */ + assert_se(parse_range("111 123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111\t123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 \t 123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Trailing whitespace is invalid (from safe_atou) */ + assert_se(parse_range("111 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111-123 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 -123", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 -123 ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111\t-123\t", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + assert_se(parse_range("111 \t -123 \t ", &lower, &upper) == -EINVAL); + assert_se(lower == 9999); + assert_se(upper == 9999); + + /* Out of the "unsigned" range, this is 1<<64 */ + assert_se(parse_range("0-18446744073709551616", &lower, &upper) == -ERANGE); + assert_se(lower == 9999); + assert_se(upper == 9999); +} + +static void test_safe_atolli(void) { + int r; + long long l; + + r = safe_atolli("12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atolli("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atou16(void) { + int r; + uint16_t l; + + r = safe_atou16("12345", &l); + assert_se(r == 0); + assert_se(l == 12345); + + r = safe_atou16("123456", &l); + assert_se(r == -ERANGE); + + r = safe_atou16("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atoi16(void) { + int r; + int16_t l; + + r = safe_atoi16("-12345", &l); + assert_se(r == 0); + assert_se(l == -12345); + + r = safe_atoi16("36536", &l); + assert_se(r == -ERANGE); + + r = safe_atoi16("junk", &l); + assert_se(r == -EINVAL); +} + +static void test_safe_atod(void) { + int r; + double d; + char *e; + + r = safe_atod("junk", &d); + assert_se(r == -EINVAL); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); + + /* Check if this really is locale independent */ + if (setlocale(LC_NUMERIC, "de_DE.utf8")) { + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001); + } + + /* And check again, reset */ + assert_se(setlocale(LC_NUMERIC, "C")); + + r = safe_atod("0.2244", &d); + assert_se(r == 0); + assert_se(fabs(d - 0.2244) < 0.000001); + + r = safe_atod("0,5", &d); + assert_se(r == -EINVAL); + + errno = 0; + strtod("0,5", &e); + assert_se(*e == ','); +} + +int main(int argc, char *argv[]) { + log_parse_environment(); + log_open(); + + test_parse_boolean(); + test_parse_pid(); + test_parse_mode(); + test_parse_size(); + test_parse_range(); + test_safe_atolli(); + test_safe_atou16(); + test_safe_atoi16(); + test_safe_atod(); + + return 0; +} diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index aa4bac6cdd..65cb894ff7 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -19,29 +19,39 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <stdlib.h> #include <sys/stat.h> -#include "path-lookup.h" #include "log.h" -#include "strv.h" +#include "path-lookup.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" static void test_paths(ManagerRunningAs running_as, bool personal) { char template[] = "/tmp/test-path-lookup.XXXXXXX"; - _cleanup_lookup_paths_free_ LookupPaths lp = {}; - char *exists, *not; + _cleanup_lookup_paths_free_ LookupPaths lp_without_env = {}; + _cleanup_lookup_paths_free_ LookupPaths lp_with_env = {}; + char *exists, *not, *systemd_unit_path; assert_se(mkdtemp(template)); exists = strjoina(template, "/exists"); assert_se(mkdir(exists, 0755) == 0); not = strjoina(template, "/not"); - assert_se(lookup_paths_init(&lp, running_as, personal, NULL, exists, not, not) == 0); + assert_se(unsetenv("SYSTEMD_UNIT_PATH") == 0); + assert_se(lookup_paths_init(&lp_without_env, running_as, personal, NULL, exists, not, not) == 0); + + assert_se(!strv_isempty(lp_without_env.unit_path)); + assert_se(strv_contains(lp_without_env.unit_path, exists)); + assert_se(strv_contains(lp_without_env.unit_path, not)); - assert_se(!strv_isempty(lp.unit_path)); - assert_se(strv_contains(lp.unit_path, exists)); - assert_se(strv_contains(lp.unit_path, not)); + systemd_unit_path = strjoina(template, "/systemd-unit-path"); + assert_se(setenv("SYSTEMD_UNIT_PATH", systemd_unit_path, 1) == 0); + assert_se(lookup_paths_init(&lp_with_env, running_as, personal, NULL, exists, not, not) == 0); + assert_se(strv_length(lp_with_env.unit_path) == 1); + assert_se(streq(lp_with_env.unit_path[0], systemd_unit_path)); assert_se(rm_rf(template, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0); } diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index fce4e81a09..3f0f0264ab 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -20,14 +20,18 @@ ***/ #include <stdio.h> -#include <unistd.h> #include <sys/mount.h> +#include <unistd.h> -#include "path-util.h" -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "macro.h" -#include "strv.h" +#include "mount-util.h" +#include "path-util.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" #define test_path_compare(a, b, result) { \ assert_se(path_compare(a, b) == result); \ @@ -75,20 +79,6 @@ static void test_path(void) { assert_se(streq(basename("/aa///file..."), "file...")); assert_se(streq(basename("file.../"), "")); -#define test_parent(x, y) { \ - _cleanup_free_ char *z = NULL; \ - int r = path_get_parent(x, &z); \ - printf("expected: %s\n", y ? y : "error"); \ - printf("actual: %s\n", r<0 ? "error" : z); \ - assert_se((y==NULL) ^ (r==0)); \ - assert_se(y==NULL || path_equal(z, y)); \ - } - - test_parent("./aa/bb/../file.da.", "./aa/bb/.."); - test_parent("/aa///.file", "/aa///"); - test_parent("/aa///file...", "/aa///"); - test_parent("file.../", NULL); - fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY); assert_se(fd >= 0); assert_se(fd_is_mount_point(fd, "/", 0) > 0); @@ -104,32 +94,28 @@ static void test_path(void) { } } -static void test_find_binary(const char *self, bool local) { +static void test_find_binary(const char *self) { char *p; - assert_se(find_binary("/bin/sh", local, &p) == 0); + assert_se(find_binary("/bin/sh", &p) == 0); puts(p); - assert_se(streq(p, "/bin/sh")); + assert_se(path_equal(p, "/bin/sh")); free(p); - assert_se(find_binary(self, local, &p) == 0); + assert_se(find_binary(self, &p) == 0); puts(p); assert_se(endswith(p, "/test-path-util")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("sh", local, &p) == 0); + assert_se(find_binary("sh", &p) == 0); puts(p); assert_se(endswith(p, "/sh")); assert_se(path_is_absolute(p)); free(p); - assert_se(find_binary("xxxx-xxxx", local, &p) == -ENOENT); - - assert_se(find_binary("/some/dir/xxxx-xxxx", local, &p) == - (local ? -ENOENT : 0)); - if (!local) - free(p); + assert_se(find_binary("xxxx-xxxx", &p) == -ENOENT); + assert_se(find_binary("/some/dir/xxxx-xxxx", &p) == -ENOENT); } static void test_prefixes(void) { @@ -210,9 +196,10 @@ static void test_fsck_exists(void) { unsetenv("PATH"); /* fsck.minix is provided by util-linux and will probably exist. */ - assert_se(fsck_exists("minix") == 0); + assert_se(fsck_exists("minix") == 1); - assert_se(fsck_exists("AbCdE") == -ENOENT); + assert_se(fsck_exists("AbCdE") == 0); + assert_se(fsck_exists("/../bin/") == 0); } static void test_make_relative(void) { @@ -450,8 +437,7 @@ static void test_path_is_mount_point(void) { int main(int argc, char **argv) { test_path(); - test_find_binary(argv[0], true); - test_find_binary(argv[0], false); + test_find_binary(argv[0]); test_prefixes(); test_path_join(); test_fsck_exists(); diff --git a/src/test/test-path.c b/src/test/test-path.c index 676c9f1793..8302bdd283 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -17,16 +17,20 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> -#include "unit.h" -#include "manager.h" -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "macro.h" -#include "strv.h" +#include "manager.h" #include "mkdir.h" #include "rm-rf.h" +#include "string-util.h" +#include "strv.h" +#include "unit.h" +#include "util.h" typedef void (*test_function_t)(Manager *m); @@ -254,7 +258,7 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - assert_se(set_unit_path(TEST_DIR) >= 0); + assert_se(set_unit_path(TEST_DIR "/test-path/") >= 0); for (test = tests; test && *test; test++) { int r; diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c index dfedc9b8dc..07273ffe79 100644 --- a/src/test/test-prioq.c +++ b/src/test/test-prioq.c @@ -21,10 +21,11 @@ #include <stdlib.h> -#include "util.h" -#include "set.h" +#include "alloc-util.h" #include "prioq.h" +#include "set.h" #include "siphash24.h" +#include "util.h" #define SET_SIZE 1024*4 @@ -89,13 +90,10 @@ static int test_compare(const void *a, const void *b) { return 0; } -static unsigned long test_hash(const void *a, const uint8_t hash_key[HASH_KEY_SIZE]) { +static void test_hash(const void *a, struct siphash *state) { const struct test *x = a; - uint64_t u; - - siphash24((uint8_t*) &u, &x->value, sizeof(x->value), hash_key); - return (unsigned long) u; + siphash24_compress(&x->value, sizeof(x->value), state); } static const struct hash_ops test_hash_ops = { diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index eb0f443a43..48be5a3a87 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -18,17 +18,19 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> #include <sys/wait.h> #include <unistd.h> -#include "process-util.h" +#include "alloc-util.h" #include "log.h" -#include "util.h" #include "macro.h" -#include "virt.h" +#include "process-util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" +#include "virt.h" static void test_get_process_comm(void) { struct stat st; @@ -53,7 +55,7 @@ static void test_get_process_comm(void) { assert_se(get_process_cmdline(1, 8, false, &d) >= 0); log_info("pid1 cmdline truncated: '%s'", d); - assert_se(get_parent_of_pid(1, &e) >= 0); + assert_se(get_process_ppid(1, &e) >= 0); log_info("pid1 ppid: "PID_FMT, e); assert_se(e == 0); diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c index b1d42d77fd..2de2091561 100644 --- a/src/test/test-replace-var.c +++ b/src/test/test-replace-var.c @@ -21,9 +21,10 @@ #include <string.h> -#include "util.h" #include "macro.h" #include "replace-var.h" +#include "string-util.h" +#include "util.h" static char *lookup(const char *variable, void *userdata) { return strjoin("<<<", variable, ">>>", NULL); diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c index f5bae65bef..b3ccc7509d 100644 --- a/src/test/test-sigbus.c +++ b/src/test/test-sigbus.c @@ -21,8 +21,9 @@ #include <sys/mman.h> -#include "util.h" +#include "fd-util.h" #include "sigbus.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_close_ int fd = -1; diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c new file mode 100644 index 0000000000..2402da6a6f --- /dev/null +++ b/src/test/test-siphash24.c @@ -0,0 +1,70 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "util.h" +#include "siphash24.h" + +#define ITERATIONS 10000000ULL + +/* see https://131002.net/siphash/siphash.pdf, Appendix A */ +int main(int argc, char *argv[]) { + struct siphash state = {}; + const uint8_t in[15] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e }; + const uint8_t key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; + uint64_t out = 0; + unsigned i, j; + + siphash24((uint8_t *)&out, in, sizeof(in), key); + assert_se(out == htole64(0xa129ca6149be45e5)); + + /* verify the internal state as given in the above paper */ + siphash24_init(&state, key); + assert_se(state.v0 == 0x7469686173716475); + assert_se(state.v1 == 0x6b617f6d656e6665); + assert_se(state.v2 == 0x6b7f62616d677361); + assert_se(state.v3 == 0x7b6b696e727e6c7b); + siphash24_compress(in, sizeof(in), &state); + assert_se(state.v0 == 0x4a017198de0a59e0); + assert_se(state.v1 == 0x0d52f6f62a4f59a4); + assert_se(state.v2 == 0x634cb3577b01fd3d); + assert_se(state.v3 == 0xa5224d6f55c7d9c8); + siphash24_finalize((uint8_t*)&out, &state); + assert_se(out == htole64(0xa129ca6149be45e5)); + assert_se(state.v0 == 0xf6bcd53893fecff1); + assert_se(state.v1 == 0x54b9964c7ea0d937); + assert_se(state.v2 == 0x1b38329c099bb55a); + assert_se(state.v3 == 0x1814bb89ad7be679); + + /* verify that decomposing the input in three chunks gives the + same result */ + for (i = 0; i < sizeof(in); i++) { + for (j = i; j < sizeof(in); j++) { + siphash24_init(&state, key); + siphash24_compress(in, i, &state); + siphash24_compress(&in[i], j - i, &state); + siphash24_compress(&in[j], sizeof(in) - j, &state); + siphash24_finalize((uint8_t*)&out, &state); + assert_se(out == htole64(0xa129ca6149be45e5)); + } + } +} diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 2c18090ae5..b9699b2028 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -17,12 +17,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "socket-util.h" +#include "alloc-util.h" +#include "async.h" +#include "fd-util.h" #include "in-addr-util.h" -#include "util.h" -#include "macro.h" #include "log.h" -#include "async.h" +#include "macro.h" +#include "socket-util.h" +#include "string-util.h" +#include "util.h" static void test_socket_address_parse(void) { SocketAddress a; diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c index 4ec648ae66..1d8eda0c15 100644 --- a/src/test/test-strbuf.c +++ b/src/test/test-strbuf.c @@ -23,6 +23,7 @@ #include <string.h> #include "strbuf.h" +#include "string-util.h" #include "strv.h" #include "util.h" diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c new file mode 100644 index 0000000000..25444c794a --- /dev/null +++ b/src/test/test-string-util.c @@ -0,0 +1,61 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "string-util.h" + +static void test_string_erase(void) { + char *x; + + x = strdupa(""); + assert_se(streq(string_erase(x), "")); + + x = strdupa("1"); + assert_se(streq(string_erase(x), "x")); + + x = strdupa("12"); + assert_se(streq(string_erase(x), "xx")); + + x = strdupa("123"); + assert_se(streq(string_erase(x), "xxx")); + + x = strdupa("1234"); + assert_se(streq(string_erase(x), "xxxx")); + + x = strdupa("12345"); + assert_se(streq(string_erase(x), "xxxxx")); + + x = strdupa("123456"); + assert_se(streq(string_erase(x), "xxxxxx")); + + x = strdupa("1234567"); + assert_se(streq(string_erase(x), "xxxxxxx")); + + x = strdupa("12345678"); + assert_se(streq(string_erase(x), "xxxxxxxx")); + + x = strdupa("123456789"); + assert_se(streq(string_erase(x), "xxxxxxxxx")); +} + +int main(int argc, char *argv[]) { + test_string_erase(); + return 0; +} diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c index 6cec8768b1..10fc98ced5 100644 --- a/src/test/test-strip-tab-ansi.c +++ b/src/test/test-strip-tab-ansi.c @@ -21,8 +21,9 @@ #include <stdio.h> -#include "util.h" +#include "string-util.h" #include "terminal-util.h" +#include "util.h" int main(int argc, char *argv[]) { char *p; diff --git a/src/test/test-strv.c b/src/test/test-strv.c index bff43950a9..c27f15283e 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -22,9 +22,11 @@ #include <string.h> -#include "util.h" +#include "alloc-util.h" #include "specifier.h" +#include "string-util.h" #include "strv.h" +#include "util.h" static void test_specifier_printf(void) { static const Specifier table[] = { @@ -155,7 +157,7 @@ static void test_strv_join(void) { static void test_strv_quote_unquote(const char* const *split, const char *quoted) { _cleanup_free_ char *p; - _cleanup_strv_free_ char **s; + _cleanup_strv_free_ char **s = NULL; char **t; int r; @@ -166,7 +168,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted assert_se(streq(p, quoted)); r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); - assert_se(r == 0); + assert_se(r == (int) strv_length(s)); assert_se(s); STRV_FOREACH(t, s) { assert_se(*t); @@ -183,7 +185,7 @@ static void test_strv_unquote(const char *quoted, char **list) { int r; r = strv_split_extract(&s, quoted, WHITESPACE, EXTRACT_QUOTES); - assert_se(r == 0); + assert_se(r == (int) strv_length(list)); assert_se(s); j = strv_join(s, " | "); assert_se(j); @@ -225,7 +227,7 @@ static void test_strv_split_extract(void) { int r; r = strv_split_extract(&l, str, ":", EXTRACT_DONT_COALESCE_SEPARATORS); - assert_se(r == 0); + assert_se(r == (int) strv_length(l)); assert_se(streq_ptr(l[0], "")); assert_se(streq_ptr(l[1], "foo:bar")); assert_se(streq_ptr(l[2], "")); @@ -341,11 +343,11 @@ static void test_strv_extend_strv(void) { _cleanup_strv_free_ char **a = NULL, **b = NULL; a = strv_new("abc", "def", "ghi", NULL); - b = strv_new("jkl", "mno", "pqr", NULL); + b = strv_new("jkl", "mno", "abc", "pqr", NULL); assert_se(a); assert_se(b); - assert_se(strv_extend_strv(&a, b) >= 0); + assert_se(strv_extend_strv(&a, b, true) == 3); assert_se(streq(a[0], "abc")); assert_se(streq(a[1], "def")); @@ -569,6 +571,77 @@ static void test_strv_shell_escape(void) { assert_se(streq_ptr(v[3], NULL)); } +static void test_strv_skip_one(char **a, size_t n, char **b) { + a = strv_skip(a, n); + assert_se(strv_equal(a, b)); +} + +static void test_strv_skip(void) { + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz")); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz")); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz")); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 3, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 4, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 55, STRV_MAKE(NULL)); + + test_strv_skip_one(STRV_MAKE("quux"), 0, STRV_MAKE("quux")); + test_strv_skip_one(STRV_MAKE("quux"), 1, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE("quux"), 55, STRV_MAKE(NULL)); + + test_strv_skip_one(STRV_MAKE(NULL), 0, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE(NULL), 1, STRV_MAKE(NULL)); + test_strv_skip_one(STRV_MAKE(NULL), 55, STRV_MAKE(NULL)); +} + +static void test_strv_extend_n(void) { + _cleanup_strv_free_ char **v = NULL; + + v = strv_new("foo", "bar", NULL); + assert_se(v); + + assert_se(strv_extend_n(&v, "waldo", 3) >= 0); + assert_se(strv_extend_n(&v, "piep", 2) >= 0); + + assert_se(streq(v[0], "foo")); + assert_se(streq(v[1], "bar")); + assert_se(streq(v[2], "waldo")); + assert_se(streq(v[3], "waldo")); + assert_se(streq(v[4], "waldo")); + assert_se(streq(v[5], "piep")); + assert_se(streq(v[6], "piep")); + assert_se(v[7] == NULL); + + v = strv_free(v); + + assert_se(strv_extend_n(&v, "foo", 1) >= 0); + assert_se(strv_extend_n(&v, "bar", 0) >= 0); + + assert_se(streq(v[0], "foo")); + assert_se(v[1] == NULL); +} + +static void test_strv_make_nulstr_one(char **l) { + _cleanup_free_ char *b = NULL, *c = NULL; + _cleanup_strv_free_ char **q = NULL; + size_t n, m; + + assert_se(strv_make_nulstr(l, &b, &n) >= 0); + assert_se(q = strv_parse_nulstr(b, n)); + assert_se(strv_equal(l, q)); + + assert_se(strv_make_nulstr(q, &c, &m) >= 0); + assert_se(m == n); + assert_se(memcmp(b, c, m) == 0); +} + +static void test_strv_make_nulstr(void) { + test_strv_make_nulstr_one(NULL); + test_strv_make_nulstr_one(STRV_MAKE(NULL)); + test_strv_make_nulstr_one(STRV_MAKE("foo")); + test_strv_make_nulstr_one(STRV_MAKE("foo", "bar")); + test_strv_make_nulstr_one(STRV_MAKE("foo", "bar", "quuux")); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -627,6 +700,9 @@ int main(int argc, char *argv[]) { test_strv_is_uniq(); test_strv_reverse(); test_strv_shell_escape(); + test_strv_skip(); + test_strv_extend_n(); + test_strv_make_nulstr(); return 0; } diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c index 858a4081da..e411d479ab 100644 --- a/src/test/test-strxcpyx.c +++ b/src/test/test-strxcpyx.c @@ -21,8 +21,9 @@ #include <string.h> -#include "util.h" +#include "string-util.h" #include "strxcpyx.h" +#include "util.h" static void test_strpcpy(void) { char target[25]; diff --git a/src/test/test-tables.c b/src/test/test-tables.c index 0e5ab1645f..ed4abdbf12 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -17,7 +17,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "architecture.h" #include "automount.h" +#include "bus-xml-policy.h" +#include "busname.h" #include "cgroup.h" #include "compress.h" #include "condition.h" @@ -25,7 +28,10 @@ #include "execute.h" #include "install.h" #include "job.h" +#include "journald-server.h" #include "kill.h" +#include "link-config.h" +#include "locale-util.h" #include "log.h" #include "logs-show.h" #include "mount.h" @@ -42,12 +48,7 @@ #include "unit-name.h" #include "unit.h" #include "util.h" -#include "architecture.h" -#include "link-config.h" -#include "bus-xml-policy.h" -#include "busname.h" -#include "journald-server.h" -#include "locale-util.h" +#include "rlimit-util.h" #include "test-tables.h" diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index d81fdb9923..e940b5a204 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -21,10 +21,12 @@ #include <stdio.h> #include <stdbool.h> -#include "terminal-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "log.h" #include "macro.h" +#include "terminal-util.h" #include "util.h" -#include "log.h" static void test_default_term_for_tty(void) { puts(default_term_for_tty("/dev/tty23")); diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index 221dd67eb2..a8bd722e44 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -20,12 +20,16 @@ ***/ #include <fcntl.h> -#include <unistd.h> -#include <stdlib.h> #include <stdio.h> +#include <stdlib.h> +#include <unistd.h> -#include "util.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "formats-util.h" +#include "string-util.h" +#include "util.h" int main(int argc, char** argv) { const char *p = argv[1] ?: "/tmp"; diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 2b765a3e90..9cc64f7c68 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -18,19 +18,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> #include <errno.h> -#include <unistd.h> #include <sched.h> +#include <stdio.h> +#include <stdlib.h> #include <sys/mount.h> #include <sys/signalfd.h> +#include <unistd.h> +#include "fs-util.h" #include "missing.h" #include "selinux-util.h" #include "signal-util.h" -#include "udev.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" static int fake_filesystems(void) { static const struct fakefs { @@ -42,7 +44,7 @@ static int fake_filesystems(void) { { "test/dev", "/dev", "failed to mount test /dev" }, { "test/run", "/run", "failed to mount test /run" }, { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d" }, - { "test/run", "/usr/lib/udev/rules.d", "failed to mount empty /usr/lib/udev/rules.d" }, + { "test/run", UDEVLIBEXECDIR "/rules.d","failed to mount empty " UDEVLIBEXECDIR "/rules.d" }, }; unsigned int i; int err; @@ -64,7 +66,7 @@ static int fake_filesystems(void) { err = mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL); if (err < 0) { err = -errno; - fprintf(stderr, "%s %m", fakefss[i].error); + fprintf(stderr, "%s %m\n", fakefss[i].error); return err; } } diff --git a/src/test/test-uid-range.c b/src/test/test-uid-range.c index bc5baa2fcb..4dcf10e26d 100644 --- a/src/test/test-uid-range.c +++ b/src/test/test-uid-range.c @@ -21,8 +21,10 @@ #include <stddef.h> -#include "util.h" +#include "alloc-util.h" #include "uid-range.h" +#include "user-util.h" +#include "util.h" int main(int argc, char *argv[]) { _cleanup_free_ UidRange *p = NULL; diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index 8358789e6f..f9107e0d0d 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -20,23 +20,27 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <fcntl.h> #include <stddef.h> +#include <stdio.h> #include <string.h> +#include <sys/capability.h> #include <unistd.h> -#include <fcntl.h> -#include "install.h" -#include "install-printf.h" -#include "specifier.h" -#include "util.h" -#include "macro.h" +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" #include "hashmap.h" +#include "hostname-util.h" +#include "install-printf.h" +#include "install.h" #include "load-fragment.h" +#include "macro.h" +#include "specifier.h" +#include "string-util.h" #include "strv.h" -#include "fileio.h" #include "test-helper.h" -#include "hostname-util.h" +#include "util.h" static int test_unit_file_get_set(void) { int r; @@ -626,6 +630,57 @@ static void test_install_printf(void) { expect(i4, "%U", "0"); } +static uint64_t make_cap(int cap) { + return ((uint64_t) 1ULL << (uint64_t) cap); +} + +static void test_config_parse_bounding_set(void) { + /* int config_parse_bounding_set( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ + int r; + uint64_t capability_bounding_set_drop = 0; + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_RAW", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW)); + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL)); + + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, "~", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == (uint64_t) 0ULL); + + capability_bounding_set_drop = 0; + r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage", + &capability_bounding_set_drop, NULL); + assert_se(r >= 0); + assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); +} + int main(int argc, char *argv[]) { int r; @@ -634,6 +689,7 @@ int main(int argc, char *argv[]) { r = test_unit_file_get_set(); test_config_parse_exec(); + test_config_parse_bounding_set(); test_load_env_file_1(); test_load_env_file_2(); test_load_env_file_3(); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index e5405fb7f3..9db7853dd4 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -21,21 +21,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <pwd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <pwd.h> +#include "alloc-util.h" +#include "hostname-util.h" +#include "macro.h" #include "manager.h" -#include "unit.h" +#include "path-util.h" +#include "specifier.h" +#include "string-util.h" +#include "test-helper.h" #include "unit-name.h" #include "unit-printf.h" -#include "specifier.h" +#include "unit.h" #include "util.h" -#include "macro.h" -#include "path-util.h" -#include "test-helper.h" -#include "hostname-util.h" static void test_unit_name_is_valid(void) { assert_se(unit_name_is_valid("foo.service", UNIT_NAME_ANY)); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c new file mode 100644 index 0000000000..09d37087e5 --- /dev/null +++ b/src/test/test-user-util.c @@ -0,0 +1,54 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include "alloc-util.h" +#include "macro.h" +#include "string-util.h" +#include "user-util.h" +#include "util.h" + +static void test_uid_to_name_one(uid_t uid, const char *name) { + _cleanup_free_ char *t = NULL; + + assert_se(t = uid_to_name(uid)); + assert_se(streq_ptr(t, name)); +} + +static void test_gid_to_name_one(gid_t gid, const char *name) { + _cleanup_free_ char *t = NULL; + + assert_se(t = gid_to_name(gid)); + assert_se(streq_ptr(t, name)); +} + +int main(int argc, char*argv[]) { + + test_uid_to_name_one(0, "root"); + test_uid_to_name_one(0xFFFF, "65535"); + test_uid_to_name_one(0xFFFFFFFF, "4294967295"); + + test_gid_to_name_one(0, "root"); + test_gid_to_name_one(TTY_GID, "tty"); + test_gid_to_name_one(0xFFFF, "65535"); + test_gid_to_name_one(0xFFFFFFFF, "4294967295"); + + return 0; +} diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index 346f8524c6..0af8349732 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "utf8.h" #include "util.h" +#include "string-util.h" static void test_utf8_is_printable(void) { assert_se(utf8_is_printable("ascii is valid\tunicode", 22)); diff --git a/src/test/test-util.c b/src/test/test-util.c index f434c5ceba..f6ed55878c 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -20,25 +20,43 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <locale.h> #include <errno.h> +#include <fcntl.h> #include <signal.h> -#include <math.h> +#include <string.h> +#include <sys/types.h> #include <sys/wait.h> +#include <sys/xattr.h> +#include <unistd.h> -#include "util.h" -#include "mkdir.h" -#include "rm-rf.h" -#include "strv.h" +#include "alloc-util.h" +#include "conf-parser.h" +#include "cpu-set-util.h" #include "def.h" +#include "escape.h" +#include "fd-util.h" #include "fileio.h" -#include "conf-parser.h" -#include "virt.h" +#include "fs-util.h" +#include "fstab-util.h" +#include "glob-util.h" +#include "hexdecoct.h" +#include "io-util.h" +#include "mkdir.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "process-util.h" +#include "rm-rf.h" #include "signal-util.h" +#include "special.h" +#include "stat-util.h" +#include "string-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" +#include "virt.h" +#include "web-util.h" +#include "xattr-util.h" static void test_streq_ptr(void) { assert_se(streq_ptr(NULL, NULL)); @@ -218,63 +236,6 @@ static void test_close_many(void) { unlink(name2); } -static void test_parse_boolean(void) { - assert_se(parse_boolean("1") == 1); - assert_se(parse_boolean("y") == 1); - assert_se(parse_boolean("Y") == 1); - assert_se(parse_boolean("yes") == 1); - assert_se(parse_boolean("YES") == 1); - assert_se(parse_boolean("true") == 1); - assert_se(parse_boolean("TRUE") == 1); - assert_se(parse_boolean("on") == 1); - assert_se(parse_boolean("ON") == 1); - - assert_se(parse_boolean("0") == 0); - assert_se(parse_boolean("n") == 0); - assert_se(parse_boolean("N") == 0); - assert_se(parse_boolean("no") == 0); - assert_se(parse_boolean("NO") == 0); - assert_se(parse_boolean("false") == 0); - assert_se(parse_boolean("FALSE") == 0); - assert_se(parse_boolean("off") == 0); - assert_se(parse_boolean("OFF") == 0); - - assert_se(parse_boolean("garbage") < 0); - assert_se(parse_boolean("") < 0); - assert_se(parse_boolean("full") < 0); -} - -static void test_parse_pid(void) { - int r; - pid_t pid; - - r = parse_pid("100", &pid); - assert_se(r == 0); - assert_se(pid == 100); - - r = parse_pid("0x7FFFFFFF", &pid); - assert_se(r == 0); - assert_se(pid == 2147483647); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("0", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("-100", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - pid = 65; /* pid is left unchanged on ERANGE. Set to known arbitrary value. */ - r = parse_pid("0xFFFFFFFFFFFFFFFFF", &pid); - assert_se(r == -ERANGE); - assert_se(pid == 65); - - r = parse_pid("junk", &pid); - assert_se(r == -EINVAL); -} - static void test_parse_uid(void) { int r; uid_t uid; @@ -290,96 +251,6 @@ static void test_parse_uid(void) { assert_se(r == -EINVAL); } -static void test_safe_atou16(void) { - int r; - uint16_t l; - - r = safe_atou16("12345", &l); - assert_se(r == 0); - assert_se(l == 12345); - - r = safe_atou16("123456", &l); - assert_se(r == -ERANGE); - - r = safe_atou16("junk", &l); - assert_se(r == -EINVAL); -} - -static void test_safe_atoi16(void) { - int r; - int16_t l; - - r = safe_atoi16("-12345", &l); - assert_se(r == 0); - assert_se(l == -12345); - - r = safe_atoi16("36536", &l); - assert_se(r == -ERANGE); - - r = safe_atoi16("junk", &l); - assert_se(r == -EINVAL); -} - -static void test_safe_atolli(void) { - int r; - long long l; - - r = safe_atolli("12345", &l); - assert_se(r == 0); - assert_se(l == 12345); - - r = safe_atolli("junk", &l); - assert_se(r == -EINVAL); -} - -static void test_safe_atod(void) { - int r; - double d; - char *e; - - r = safe_atod("junk", &d); - assert_se(r == -EINVAL); - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - strtod("0,5", &e); - assert_se(*e == ','); - - /* Check if this really is locale independent */ - if (setlocale(LC_NUMERIC, "de_DE.utf8")) { - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - assert_se(fabs(strtod("0,5", &e) - 0.5) < 0.00001); - } - - /* And check again, reset */ - assert_se(setlocale(LC_NUMERIC, "C")); - - r = safe_atod("0.2244", &d); - assert_se(r == 0); - assert_se(fabs(d - 0.2244) < 0.000001); - - r = safe_atod("0,5", &d); - assert_se(r == -EINVAL); - - errno = 0; - strtod("0,5", &e); - assert_se(*e == ','); -} - static void test_strappend(void) { _cleanup_free_ char *t1, *t2, *t3, *t4; @@ -892,81 +763,13 @@ static void test_protect_errno(void) { assert_se(errno == 12); } -static void test_parse_size(void) { - uint64_t bytes; - - assert_se(parse_size("111", 1024, &bytes) == 0); - assert_se(bytes == 111); - - assert_se(parse_size("111.4", 1024, &bytes) == 0); - assert_se(bytes == 111); - - assert_se(parse_size(" 112 B", 1024, &bytes) == 0); - assert_se(bytes == 112); - - assert_se(parse_size(" 112.6 B", 1024, &bytes) == 0); - assert_se(bytes == 112); - - assert_se(parse_size("3.5 K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024 + 512); - - assert_se(parse_size("3. K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024); - - assert_se(parse_size("3.0 K", 1024, &bytes) == 0); - assert_se(bytes == 3*1024); - - assert_se(parse_size("3. 0 K", 1024, &bytes) == -EINVAL); - - assert_se(parse_size(" 4 M 11.5K", 1024, &bytes) == 0); - assert_se(bytes == 4*1024*1024 + 11 * 1024 + 512); - - assert_se(parse_size("3B3.5G", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("3.5G3B", 1024, &bytes) == 0); - assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 3); - - assert_se(parse_size("3.5G 4B", 1024, &bytes) == 0); - assert_se(bytes == 3ULL*1024*1024*1024 + 512*1024*1024 + 4); - - assert_se(parse_size("3B3G4T", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("4T3G3B", 1024, &bytes) == 0); - assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); - - assert_se(parse_size(" 4 T 3 G 3 B", 1024, &bytes) == 0); - assert_se(bytes == (4ULL*1024 + 3)*1024*1024*1024 + 3); - - assert_se(parse_size("12P", 1024, &bytes) == 0); - assert_se(bytes == 12ULL * 1024*1024*1024*1024*1024); - - assert_se(parse_size("12P12P", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("3E 2P", 1024, &bytes) == 0); - assert_se(bytes == (3 * 1024 + 2ULL) * 1024*1024*1024*1024*1024); - - assert_se(parse_size("12X", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("12.5X", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("12.5e3", 1024, &bytes) == -EINVAL); - - assert_se(parse_size("1024E", 1024, &bytes) == -ERANGE); - assert_se(parse_size("-1", 1024, &bytes) == -ERANGE); - assert_se(parse_size("-1024E", 1024, &bytes) == -ERANGE); - - assert_se(parse_size("-1024P", 1024, &bytes) == -ERANGE); - - assert_se(parse_size("-10B 20K", 1024, &bytes) == -ERANGE); -} - static void test_parse_cpu_set(void) { cpu_set_t *c = NULL; int ncpus; int cpu; /* Simple range (from CPUAffinity example) */ - ncpus = parse_cpu_set("1 2", &c, NULL, "fake", 1, "CPUAffinity"); + ncpus = parse_cpu_set_and_warn("1 2", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus >= 1024); assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); assert_se(CPU_ISSET_S(2, CPU_ALLOC_SIZE(ncpus), c)); @@ -974,7 +777,7 @@ static void test_parse_cpu_set(void) { c = mfree(c); /* A more interesting range */ - ncpus = parse_cpu_set("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); + ncpus = parse_cpu_set_and_warn("0 1 2 3 8 9 10 11", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus >= 1024); assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); for (cpu = 0; cpu < 4; cpu++) @@ -984,7 +787,7 @@ static void test_parse_cpu_set(void) { c = mfree(c); /* Quoted strings */ - ncpus = parse_cpu_set("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); + ncpus = parse_cpu_set_and_warn("8 '9' 10 \"11\"", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus >= 1024); assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 4); for (cpu = 8; cpu < 12; cpu++) @@ -992,28 +795,85 @@ static void test_parse_cpu_set(void) { c = mfree(c); /* Use commas as separators */ - ncpus = parse_cpu_set("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); - assert_se(ncpus < 0); - assert_se(!c); + ncpus = parse_cpu_set_and_warn("0,1,2,3 8,9,10,11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Commas with spaces (and trailing comma, space) */ + ncpus = parse_cpu_set_and_warn("0, 1, 2, 3, 4, 5, 6, 7, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 8; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); /* Ranges */ - ncpus = parse_cpu_set("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); + ncpus = parse_cpu_set_and_warn("0-3,8-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Ranges with trailing comma, space */ + ncpus = parse_cpu_set_and_warn("0-3 8-11, ", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 8); + for (cpu = 0; cpu < 4; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 8; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Negative range (returns empty cpu_set) */ + ncpus = parse_cpu_set_and_warn("3-0", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 0); + c = mfree(c); + + /* Overlapping ranges */ + ncpus = parse_cpu_set_and_warn("0-7 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 12); + for (cpu = 0; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Mix ranges and individual CPUs */ + ncpus = parse_cpu_set_and_warn("0,1 4-11", &c, NULL, "fake", 1, "CPUAffinity"); + assert_se(ncpus >= 1024); + assert_se(CPU_COUNT_S(CPU_ALLOC_SIZE(ncpus), c) == 10); + assert_se(CPU_ISSET_S(0, CPU_ALLOC_SIZE(ncpus), c)); + assert_se(CPU_ISSET_S(1, CPU_ALLOC_SIZE(ncpus), c)); + for (cpu = 4; cpu < 12; cpu++) + assert_se(CPU_ISSET_S(cpu, CPU_ALLOC_SIZE(ncpus), c)); + c = mfree(c); + + /* Garbage */ + ncpus = parse_cpu_set_and_warn("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus < 0); assert_se(!c); - /* Garbage */ - ncpus = parse_cpu_set("0 1 2 3 garbage", &c, NULL, "fake", 1, "CPUAffinity"); + /* Range with garbage */ + ncpus = parse_cpu_set_and_warn("0-3 8-garbage", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus < 0); assert_se(!c); /* Empty string */ c = NULL; - ncpus = parse_cpu_set("", &c, NULL, "fake", 1, "CPUAffinity"); + ncpus = parse_cpu_set_and_warn("", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus == 0); /* empty string returns 0 */ assert_se(!c); /* Runnaway quoted string */ - ncpus = parse_cpu_set("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); + ncpus = parse_cpu_set_and_warn("0 1 2 3 \"4 5 6 7 ", &c, NULL, "fake", 1, "CPUAffinity"); assert_se(ncpus < 0); assert_se(!c); } @@ -1551,507 +1411,6 @@ static void test_execute_directory(void) { (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL); } -static void test_extract_first_word(void) { - const char *p, *original; - char *t; - - p = original = "foobar waldo"; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 7); - - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, NULL, 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "\"foobar\"")); - free(t); - assert_se(p == original + 9); - - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "\'waldo\'")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, NULL, 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 9); - - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, NULL, 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\""; - assert_se(extract_first_word(&p, &t, NULL, 0) == 1); - assert_se(streq(t, "\"")); - free(t); - assert_se(isempty(p)); - - p = original = "\""; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'"; - assert_se(extract_first_word(&p, &t, NULL, 0) == 1); - assert_se(streq(t, "\'")); - free(t); - assert_se(isempty(p)); - - p = original = "\'"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, 0) == 1); - assert_se(streq(t, "\'fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\'fooo"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "yay\'foo\'bar"; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "yay\'foo\'bar")); - free(t); - assert_se(isempty(p)); - - p = original = "yay\'foo\'bar"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "yayfoobar")); - free(t); - assert_se(isempty(p)); - - p = original = " foobar "; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); - assert_se(streq(t, "foo\ba\x6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word(&p, &t, NULL, 0) > 0); - assert_se(streq(t, "foobax6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) > 0); - assert_se(streq(t, "föo")); - free(t); - assert_se(p == original + 13); - - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE) > 0); - assert_se(streq(t, "pi\360\237\222\251le")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, 0) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(isempty(p)); - - p = original = "foo::bar"; - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "foo")); - free(t); - assert_se(p == original + 5); - - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "bar")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, ":", 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "foo\\:bar::waldo"; - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "foo:bar")); - free(t); - assert_se(p == original + 10); - - assert_se(extract_first_word(&p, &t, ":", 0) == 1); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word(&p, &t, ":", 0) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "foo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "foo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); - assert_se(p == original + 5); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "fooo\\ bar")); - free(t); - assert_se(p == original + 10); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "\\w+@\\K[\\d.]+")); - free(t); - assert_se(isempty(p)); - - p = original = "\\w+\\b"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); - assert_se(streq(t, "\\w+\b")); - free(t); - assert_se(isempty(p)); - - p = original = "-N ''"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "-N")); - free(t); - assert_se(p == original + 3); - - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_QUOTES) > 0); - assert_se(streq(t, "")); - free(t); - assert_se(isempty(p)); - - p = original = ":foo\\:bar::waldo:"; - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(t); - assert_se(streq(t, "")); - free(t); - assert_se(p == original + 1); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(streq(t, "foo:bar")); - free(t); - assert_se(p == original + 10); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(t); - assert_se(streq(t, "")); - free(t); - assert_se(p == original + 11); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(streq(t, "waldo")); - free(t); - assert_se(p == original + 17); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 1); - assert_se(streq(t, "")); - free(t); - assert_se(p == NULL); - - assert_se(extract_first_word(&p, &t, ":", EXTRACT_DONT_COALESCE_SEPARATORS) == 0); - assert_se(!t); - assert_se(!p); -} - -static void test_extract_first_word_and_warn(void) { - const char *p, *original; - char *t; - - p = original = "foobar waldo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 7); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\"foobar\" \'waldo\'"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobar")); - free(t); - assert_se(p == original + 9); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "waldo")); - free(t); - assert_se(isempty(p)); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) == 0); - assert_se(!t); - assert_se(isempty(p)); - - p = original = "\""; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 1); - - p = original = "\'fooo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\'fooo"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo\ba\x6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " foo\\ba\\x6ar "; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foobax6ar")); - free(t); - assert_se(isempty(p)); - - p = original = " f\\u00f6o \"pi\\U0001F4A9le\" "; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "föo")); - free(t); - assert_se(p == original + 13); - - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "pi\360\237\222\251le")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(isempty(p)); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, NULL, "fake", 1, original) == -EINVAL); - assert_se(p == original + 5); - - p = original = "\"foo\\"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "foo")); - free(t); - assert_se(isempty(p)); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_RELAX, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, 0, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo bar")); - free(t); - assert_se(p == original + 10); - - p = original = "fooo\\ bar quux"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "fooo\\ bar")); - free(t); - assert_se(p == original + 10); - - p = original = "\\w+@\\K[\\d.]+"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "\\w+@\\K[\\d.]+")); - free(t); - assert_se(isempty(p)); - - p = original = "\\w+\\b"; - assert_se(extract_first_word_and_warn(&p, &t, NULL, EXTRACT_CUNESCAPE, NULL, "fake", 1, original) > 0); - assert_se(streq(t, "\\w+\b")); - free(t); - assert_se(isempty(p)); -} - -static void test_extract_many_words(void) { - const char *p, *original; - char *a, *b, *c; - - p = original = "foobar waldi piep"; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 3); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "foobar")); - assert_se(streq_ptr(b, "waldi")); - assert_se(streq_ptr(c, "piep")); - free(a); - free(b); - free(c); - - p = original = "'foobar' wa\"ld\"i "; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 2); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "'foobar'")); - assert_se(streq_ptr(b, "wa\"ld\"i")); - assert_se(streq_ptr(c, NULL)); - free(a); - free(b); - - p = original = "'foobar' wa\"ld\"i "; - assert_se(extract_many_words(&p, NULL, EXTRACT_QUOTES, &a, &b, &c, NULL) == 2); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "foobar")); - assert_se(streq_ptr(b, "waldi")); - assert_se(streq_ptr(c, NULL)); - free(a); - free(b); - - p = original = ""; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); - assert_se(isempty(p)); - assert_se(streq_ptr(a, NULL)); - assert_se(streq_ptr(b, NULL)); - assert_se(streq_ptr(c, NULL)); - - p = original = " "; - assert_se(extract_many_words(&p, NULL, 0, &a, &b, &c, NULL) == 0); - assert_se(isempty(p)); - assert_se(streq_ptr(a, NULL)); - assert_se(streq_ptr(b, NULL)); - assert_se(streq_ptr(c, NULL)); - - p = original = "foobar"; - assert_se(extract_many_words(&p, NULL, 0, NULL) == 0); - assert_se(p == original); - - p = original = "foobar waldi"; - assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); - assert_se(p == original+7); - assert_se(streq_ptr(a, "foobar")); - free(a); - - p = original = " foobar "; - assert_se(extract_many_words(&p, NULL, 0, &a, NULL) == 1); - assert_se(isempty(p)); - assert_se(streq_ptr(a, "foobar")); - free(a); -} - static int parse_item(const char *key, const char *value) { assert_se(key); @@ -2200,20 +1559,6 @@ static void test_shell_maybe_quote(void) { test_shell_maybe_quote_one("foo$bar", "\"foo\\$bar\""); } -static void test_parse_mode(void) { - mode_t m; - - assert_se(parse_mode("-1", &m) < 0); - assert_se(parse_mode("", &m) < 0); - assert_se(parse_mode("888", &m) < 0); - assert_se(parse_mode("77777", &m) < 0); - - assert_se(parse_mode("544", &m) >= 0 && m == 0544); - assert_se(parse_mode("777", &m) >= 0 && m == 0777); - assert_se(parse_mode("7777", &m) >= 0 && m == 07777); - assert_se(parse_mode("0", &m) >= 0 && m == 0); -} - static void test_tempfn(void) { char *ret = NULL, *p; @@ -2262,6 +1607,44 @@ static void test_strcmp_ptr(void) { assert_se(strcmp_ptr("", "") == 0); } +static void test_fgetxattrat_fake(void) { + char t[] = "/var/tmp/xattrtestXXXXXX"; + _cleanup_close_ int fd = -1; + const char *x; + char v[3] = {}; + int r; + + assert_se(mkdtemp(t)); + x = strjoina(t, "/test"); + assert_se(touch(x) >= 0); + + r = setxattr(x, "user.foo", "bar", 3, 0); + if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */ + goto cleanup; + assert_se(r >= 0); + + fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + + assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0); + assert_se(memcmp(v, "bar", 3) == 0); + + safe_close(fd); + fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY); + assert_se(fd >= 0); + assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA); + +cleanup: + assert_se(unlink(x) >= 0); + assert_se(rmdir(t) >= 0); +} + +static void test_runlevel_to_target(void) { + assert_se(streq_ptr(runlevel_to_target(NULL), NULL)); + assert_se(streq_ptr(runlevel_to_target("unknown-runlevel"), NULL)); + assert_se(streq_ptr(runlevel_to_target("3"), SPECIAL_MULTI_USER_TARGET)); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -2274,13 +1657,7 @@ int main(int argc, char *argv[]) { test_div_round_up(); test_first_word(); test_close_many(); - test_parse_boolean(); - test_parse_pid(); test_parse_uid(); - test_safe_atou16(); - test_safe_atoi16(); - test_safe_atolli(); - test_safe_atod(); test_strappend(); test_strstrip(); test_delete_chars(); @@ -2307,7 +1684,6 @@ int main(int argc, char *argv[]) { test_memdup_multiply(); test_u64log2(); test_protect_errno(); - test_parse_size(); test_parse_cpu_set(); test_config_parse_iec_uint64(); test_strextend(); @@ -2339,9 +1715,6 @@ int main(int argc, char *argv[]) { test_search_and_fopen_nulstr(); test_glob_exists(); test_execute_directory(); - test_extract_first_word(); - test_extract_first_word_and_warn(); - test_extract_many_words(); test_parse_proc_cmdline(); test_raw_clone(); test_same_fd(); @@ -2349,9 +1722,10 @@ int main(int argc, char *argv[]) { test_sparse_write(); test_shell_escape(); test_shell_maybe_quote(); - test_parse_mode(); test_tempfn(); test_strcmp_ptr(); + test_fgetxattrat_fake(); + test_runlevel_to_target(); return 0; } diff --git a/src/test/test-xml.c b/src/test/test-xml.c index ea109fbde0..548d75a3c3 100644 --- a/src/test/test-xml.c +++ b/src/test/test-xml.c @@ -21,8 +21,10 @@ #include <stdarg.h> -#include "xml.h" +#include "alloc-util.h" +#include "string-util.h" #include "util.h" +#include "xml.h" static void test_one(const char *data, ...) { void *state = NULL; diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 12a7ed6718..564d72773a 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -20,20 +20,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stdbool.h> #include <getopt.h> #include <locale.h> +#include <stdbool.h> +#include <stdlib.h> #include "sd-bus.h" -#include "bus-util.h" + #include "bus-error.h" -#include "util.h" +#include "bus-util.h" +#include "pager.h" +#include "parse-util.h" #include "spawn-polkit-agent.h" -#include "build.h" #include "strv.h" -#include "pager.h" #include "terminal-util.h" +#include "util.h" static bool arg_no_pager = false; static bool arg_ask_password = true; @@ -374,9 +375,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case 'H': arg_transport = BUS_TRANSPORT_REMOTE; @@ -502,7 +501,7 @@ int main(int argc, char *argv[]) { if (r <= 0) goto finish; - r = bus_open_transport(arg_transport, arg_host, false, &bus); + r = bus_connect_transport(arg_transport, arg_host, false, &bus); if (r < 0) { log_error_errno(r, "Failed to create bus connection: %m"); goto finish; diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 6de9e246f6..968ef8a788 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -23,21 +23,24 @@ #include <string.h> #include <unistd.h> -#include "sd-messages.h" -#include "sd-event.h" #include "sd-bus.h" +#include "sd-event.h" +#include "sd-messages.h" -#include "util.h" -#include "strv.h" -#include "def.h" -#include "clock-util.h" -#include "path-util.h" -#include "fileio-label.h" -#include "bus-util.h" -#include "bus-error.h" +#include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-error.h" +#include "bus-util.h" +#include "clock-util.h" +#include "def.h" #include "event-util.h" +#include "fileio-label.h" +#include "fs-util.h" +#include "path-util.h" #include "selinux-util.h" +#include "strv.h" +#include "user-util.h" +#include "util.h" #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index df4d89a620..001a0f4d41 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -19,14 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ - +#include "alloc-util.h" +#include "def.h" +#include "extract-word.h" +#include "string-util.h" +#include "timesyncd-conf.h" #include "timesyncd-manager.h" #include "timesyncd-server.h" -#include "timesyncd-conf.h" int manager_parse_server_string(Manager *m, ServerType type, const char *string) { - const char *word, *state; - size_t length; ServerName *first; int r; @@ -35,17 +36,20 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string) first = type == SERVER_FALLBACK ? m->fallback_servers : m->system_servers; - FOREACH_WORD_QUOTED(word, length, string, state) { - char buffer[length+1]; + for (;;) { + _cleanup_free_ char *word = NULL; bool found = false; ServerName *n; - memcpy(buffer, word, length); - buffer[length] = 0; + r = extract_first_word(&string, &word, NULL, 0); + if (r < 0) + return log_error_errno(r, "Failed to parse timesyncd server syntax \"%s\": %m", string); + if (r == 0) + break; /* Filter out duplicates */ LIST_FOREACH(names, n, first) - if (streq_ptr(n->string, buffer)) { + if (streq_ptr(n->string, word)) { found = true; break; } @@ -53,7 +57,7 @@ int manager_parse_server_string(Manager *m, ServerType type, const char *string) if (found) continue; - r = server_name_new(m, NULL, type, buffer); + r = server_name_new(m, NULL, type, word); if (r < 0) return r; } @@ -85,7 +89,7 @@ int config_parse_servers( else { r = manager_parse_server_string(m, ltype, rvalue); if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to parse NTP server string '%s'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NTP server string '%s'. Ignoring.", rvalue); return 0; } } diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index 40e0fd31fe..8dca538b3b 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -19,31 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.h> -#include <time.h> #include <math.h> #include <netinet/in.h> #include <netinet/ip.h> +#include <resolv.h> +#include <stdlib.h> +#include <sys/socket.h> #include <sys/timerfd.h> #include <sys/timex.h> -#include <sys/socket.h> -#include <resolv.h> #include <sys/types.h> +#include <time.h> -#include "missing.h" -#include "util.h" -#include "sparse-endian.h" -#include "log.h" -#include "socket-util.h" +#include "sd-daemon.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "list.h" +#include "log.h" +#include "missing.h" +#include "network-util.h" #include "ratelimit.h" +#include "socket-util.h" +#include "sparse-endian.h" +#include "string-util.h" #include "strv.h" -#include "sd-daemon.h" -#include "network-util.h" +#include "time-util.h" #include "timesyncd-conf.h" #include "timesyncd-manager.h" -#include "time-util.h" +#include "util.h" #ifndef ADJ_SETOFFSET #define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */ @@ -365,7 +370,7 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) { r = clock_adjtime(CLOCK_REALTIME, &tmx); if (r < 0) - return r; + return -errno; touch("/var/lib/systemd/clock"); @@ -662,7 +667,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re m->sync = true; r = manager_adjust_clock(m, offset, leap_sec); if (r < 0) - log_error_errno(errno, "Failed to call clock_adjtime(): %m"); + log_error_errno(r, "Failed to call clock_adjtime(): %m"); } log_debug("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s", diff --git a/src/timesync/timesyncd-server.c b/src/timesync/timesyncd-server.c index ec3fe1fc4e..f98e6b4cf0 100644 --- a/src/timesync/timesyncd-server.c +++ b/src/timesync/timesyncd-server.c @@ -19,6 +19,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "timesyncd-server.h" int server_address_new( diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 3cb7d435cd..7f70eaaea0 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -19,15 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "sd-event.h" #include "sd-daemon.h" -#include "capability.h" +#include "sd-event.h" + +#include "capability-util.h" #include "clock-util.h" +#include "fd-util.h" +#include "fs-util.h" #include "network-util.h" #include "signal-util.h" - -#include "timesyncd-manager.h" #include "timesyncd-conf.h" +#include "timesyncd-manager.h" +#include "user-util.h" static int load_clock_timestamp(uid_t uid, gid_t gid) { _cleanup_close_ int fd = -1; @@ -57,12 +60,12 @@ static int load_clock_timestamp(uid_t uid, gid_t gid) { /* Try to fix the access mode, so that we can still touch the file after dropping priviliges */ - fchmod(fd, 0644); - fchown(fd, uid, gid); + (void) fchmod(fd, 0644); + (void) fchown(fd, uid, gid); } else /* create stamp file with the compiled-in date */ - touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644); + (void) touch_file("/var/lib/systemd/clock", true, min, uid, gid, 0644); ct = now(CLOCK_REALTIME); if (ct < min) { @@ -150,7 +153,7 @@ int main(int argc, char *argv[]) { /* if we got an authoritative time, store it in the file system */ if (m->sync) - touch("/var/lib/systemd/clock"); + (void) touch("/var/lib/systemd/clock"); sd_event_get_exit_code(m->event, &r); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 8f29256c6d..ffae91a3ca 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -20,43 +20,59 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <fcntl.h> +#include <dirent.h> #include <errno.h> -#include <string.h> +#include <fcntl.h> +#include <fnmatch.h> +#include <getopt.h> +#include <glob.h> #include <limits.h> -#include <dirent.h> +#include <linux/fs.h> +#include <stdbool.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> -#include <getopt.h> -#include <stdbool.h> -#include <time.h> -#include <glob.h> -#include <fnmatch.h> +#include <string.h> #include <sys/stat.h> #include <sys/xattr.h> -#include <linux/fs.h> +#include <time.h> +#include <unistd.h> +#include "acl-util.h" +#include "alloc-util.h" +#include "btrfs-util.h" +#include "capability-util.h" +#include "chattr-util.h" +#include "conf-files.h" +#include "copy.h" +#include "def.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "formats-util.h" +#include "fs-util.h" +#include "glob-util.h" +#include "io-util.h" +#include "label.h" #include "log.h" -#include "util.h" #include "macro.h" #include "missing.h" #include "mkdir.h" +#include "mount-util.h" +#include "parse-util.h" #include "path-util.h" -#include "strv.h" -#include "label.h" -#include "set.h" -#include "conf-files.h" -#include "capability.h" -#include "specifier.h" -#include "build.h" -#include "copy.h" #include "rm-rf.h" #include "selinux-util.h" -#include "btrfs-util.h" -#include "acl-util.h" -#include "formats-util.h" +#include "set.h" +#include "specifier.h" +#include "stat-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "umask-util.h" +#include "user-util.h" +#include "util.h" /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates * them in the file system. This is intended to be used to create @@ -70,6 +86,8 @@ typedef enum ItemType { CREATE_DIRECTORY = 'd', TRUNCATE_DIRECTORY = 'D', CREATE_SUBVOLUME = 'v', + CREATE_SUBVOLUME_INHERIT_QUOTA = 'q', + CREATE_SUBVOLUME_NEW_QUOTA = 'Q', CREATE_FIFO = 'p', CREATE_SYMLINK = 'L', CREATE_CHAR_DEVICE = 'c', @@ -181,6 +199,8 @@ static bool takes_ownership(ItemType t) { CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, + CREATE_SUBVOLUME_INHERIT_QUOTA, + CREATE_SUBVOLUME_NEW_QUOTA, CREATE_FIFO, CREATE_SYMLINK, CREATE_CHAR_DEVICE, @@ -1199,16 +1219,16 @@ static int create_item(Item *i) { case CREATE_DIRECTORY: case TRUNCATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: RUN_WITH_UMASK(0000) mkdir_parents_label(i->path, 0755); - if (i->type == CREATE_SUBVOLUME) - RUN_WITH_UMASK((~i->mode) & 0777) { + if (IN_SET(i->type, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) { + RUN_WITH_UMASK((~i->mode) & 0777) r = btrfs_subvol_make(i->path); - log_debug_errno(r, "Creating subvolume \"%s\": %m", i->path); - } - else + } else r = 0; if (IN_SET(i->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY) || r == -ENOTTY) @@ -1237,6 +1257,24 @@ static int create_item(Item *i) { log_debug("%s directory \"%s\".", creation_mode_verb_to_string(creation), i->path); + if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) { + r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA); + if (r == -ENOTTY) { + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path); + return 0; + } + if (r == -EROFS) { + log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path); + if (r > 0) + log_debug("Adjusted quota for subvolume \"%s\".", i->path); + if (r == 0) + log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path); + } + r = path_set_perms(i, i->path); if (r < 0) return r; @@ -1493,6 +1531,8 @@ static int remove_item(Item *i) { case TRUNCATE_FILE: case CREATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: case CREATE_FIFO: case CREATE_SYMLINK: case CREATE_CHAR_DEVICE: @@ -1562,8 +1602,7 @@ static int clean_item_instance(Item *i, const char* instance) { if (fstatat(dirfd(d), "..", &ps, AT_SYMLINK_NOFOLLOW) != 0) return log_error_errno(errno, "stat(%s/..) failed: %m", i->path); - mountpoint = s.st_dev != ps.st_dev || - (s.st_dev == ps.st_dev && s.st_ino == ps.st_ino); + mountpoint = s.st_dev != ps.st_dev || s.st_ino == ps.st_ino; log_debug("Cleanup threshold for %s \"%s\" is %s", mountpoint ? "mount point" : "directory", @@ -1584,6 +1623,8 @@ static int clean_item(Item *i) { switch (i->type) { case CREATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: case TRUNCATE_DIRECTORY: case IGNORE_PATH: case COPY_FILES: @@ -1820,6 +1861,8 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { case CREATE_DIRECTORY: case CREATE_SUBVOLUME: + case CREATE_SUBVOLUME_INHERIT_QUOTA: + case CREATE_SUBVOLUME_NEW_QUOTA: case TRUNCATE_DIRECTORY: case CREATE_FIFO: case IGNORE_PATH: @@ -1984,8 +2027,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) { i.mode = m; i.mode_set = true; } else - i.mode = IN_SET(i.type, CREATE_DIRECTORY, CREATE_SUBVOLUME, TRUNCATE_DIRECTORY) - ? 0755 : 0644; + i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644; if (!isempty(age) && !streq(age, "-")) { const char *a = age; @@ -2076,7 +2118,7 @@ static int parse_argv(int argc, char *argv[]) { {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -2090,9 +2132,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_CREATE: arg_create = true; @@ -2121,12 +2161,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - free(arg_root); - arg_root = path_make_absolute_cwd(optarg); - if (!arg_root) - return log_oom(); - - path_kill_slashes(arg_root); + r = parse_path_argument_and_warn(optarg, true, &arg_root); + if (r < 0) + return r; break; case '?': @@ -2189,7 +2226,7 @@ static int read_config_file(const char *fn, bool ignore_enoent) { continue; ORDERED_HASHMAP_FOREACH(j, items, iter) { - if (j->type != CREATE_DIRECTORY && j->type != TRUNCATE_DIRECTORY && j->type != CREATE_SUBVOLUME) + if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA)) continue; if (path_equal(j->path, i->path)) { diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 82cbf95f1e..8cfe10330d 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -19,32 +19,36 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <poll.h> +#include <stdbool.h> +#include <stddef.h> #include <string.h> +#include <sys/inotify.h> +#include <sys/signalfd.h> #include <sys/socket.h> #include <sys/un.h> -#include <stddef.h> -#include <poll.h> -#include <sys/inotify.h> #include <unistd.h> -#include <getopt.h> -#include <sys/signalfd.h> -#include <fcntl.h> -#include "util.h" +#include "alloc-util.h" +#include "ask-password-api.h" +#include "conf-parser.h" +#include "def.h" +#include "dirent-util.h" +#include "fd-util.h" +#include "io-util.h" #include "mkdir.h" #include "path-util.h" -#include "conf-parser.h" -#include "utmp-wtmp.h" +#include "process-util.h" +#include "signal-util.h" #include "socket-util.h" -#include "ask-password-api.h" +#include "string-util.h" #include "strv.h" -#include "build.h" -#include "def.h" -#include "process-util.h" #include "terminal-util.h" -#include "signal-util.h" +#include "util.h" +#include "utmp-wtmp.h" static enum { ACTION_LIST, @@ -59,9 +63,9 @@ static bool arg_console = false; static int ask_password_plymouth( const char *message, usec_t until, + AskPasswordFlags flags, const char *flag_file, - bool accept_cached, - char ***_passphrases) { + char ***ret) { _cleanup_close_ int fd = -1, notify = -1; union sockaddr_union sa = PLYMOUTH_SOCKET; @@ -76,7 +80,7 @@ static int ask_password_plymouth( POLL_INOTIFY }; - assert(_passphrases); + assert(ret); if (flag_file) { notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK); @@ -94,17 +98,15 @@ static int ask_password_plymouth( r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)); if (r < 0) - return log_error_errno(errno, "Failed to connect to Plymouth: %m"); + return -errno; - if (accept_cached) { + if (flags & ASK_PASSWORD_ACCEPT_CACHED) { packet = strdup("c"); n = 1; - } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), - message, &n) < 0) + } else if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) packet = NULL; - if (!packet) - return log_oom(); + return -ENOMEM; r = loop_write(fd, packet, n + 1, true); if (r < 0) @@ -123,33 +125,48 @@ static int ask_password_plymouth( y = now(CLOCK_MONOTONIC); - if (y > until) - return -ETIME; + if (y > until) { + r = -ETIME; + goto finish; + } sleep_for = (int) ((until - y) / USEC_PER_MSEC); } - if (flag_file && access(flag_file, F_OK) < 0) - return -errno; + if (flag_file && access(flag_file, F_OK) < 0) { + r = -errno; + goto finish; + } - j = poll(pollfd, notify > 0 ? 2 : 1, sleep_for); + j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); if (j < 0) { if (errno == EINTR) continue; - return -errno; - } else if (j == 0) - return -ETIME; + r = -errno; + goto finish; + } else if (j == 0) { + r = -ETIME; + goto finish; + } - if (notify > 0 && pollfd[POLL_INOTIFY].revents != 0) + if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) flush_fd(notify); if (pollfd[POLL_SOCKET].revents == 0) continue; k = read(fd, buffer + p, sizeof(buffer) - p); - if (k <= 0) - return r = k < 0 ? -errno : -EIO; + if (k < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + + r = -errno; + goto finish; + } else if (k == 0) { + r = -EIO; + goto finish; + } p += k; @@ -158,26 +175,29 @@ static int ask_password_plymouth( if (buffer[0] == 5) { - if (accept_cached) { + if (flags & ASK_PASSWORD_ACCEPT_CACHED) { /* Hmm, first try with cached * passwords failed, so let's retry * with a normal password request */ packet = mfree(packet); - if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) - return -ENOMEM; + if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) { + r = -ENOMEM; + goto finish; + } r = loop_write(fd, packet, n+1, true); if (r < 0) - return r; + goto finish; - accept_cached = false; + flags &= ~ASK_PASSWORD_ACCEPT_CACHED; p = 0; continue; } /* No password, because UI not shown */ - return -ENOENT; + r = -ENOENT; + goto finish; } else if (buffer[0] == 2 || buffer[0] == 9) { uint32_t size; @@ -189,32 +209,43 @@ static int ask_password_plymouth( memcpy(&size, buffer+1, sizeof(size)); size = le32toh(size); - if (size + 5 > sizeof(buffer)) - return -EIO; + if (size + 5 > sizeof(buffer)) { + r = -EIO; + goto finish; + } if (p-5 < size) continue; l = strv_parse_nulstr(buffer + 5, size); - if (!l) - return -ENOMEM; + if (!l) { + r = -ENOMEM; + goto finish; + } - *_passphrases = l; + *ret = l; break; - } else + } else { /* Unknown packet */ - return -EIO; + r = -EIO; + goto finish; + } } - return 0; + r = 0; + +finish: + memory_erase(buffer, sizeof(buffer)); + return r; } static int parse_password(const char *filename, char **wall) { _cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL; + bool accept_cached = false, echo = false; + size_t packet_length = 0; uint64_t not_after = 0; unsigned pid = 0; - bool accept_cached = false, echo = false; const ConfigTableItem items[] = { { "Ask", "Socket", config_parse_string, 0, &socket_name }, @@ -257,7 +288,7 @@ static int parse_password(const char *filename, char **wall) { if (asprintf(&_wall, "%s%sPassword entry required for \'%s\' (PID %u).\r\n" "Please enter password with the systemd-tty-ask-password-agent tool!", - *wall ? *wall : "", + strempty(*wall), *wall ? "\r\n\r\n" : "", message, pid) < 0) @@ -268,7 +299,6 @@ static int parse_password(const char *filename, char **wall) { } else { union sockaddr_union sa = {}; - size_t packet_length = 0; _cleanup_close_ int socket_fd = -1; assert(arg_action == ACTION_QUERY || @@ -282,9 +312,9 @@ static int parse_password(const char *filename, char **wall) { } if (arg_plymouth) { - _cleanup_strv_free_ char **passwords = NULL; + _cleanup_strv_free_erase_ char **passwords = NULL; - r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords); + r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords); if (r >= 0) { char **p; @@ -306,19 +336,23 @@ static int parse_password(const char *filename, char **wall) { } } else { + _cleanup_string_free_erase_ char *password = NULL; int tty_fd = -1; - _cleanup_free_ char *password = NULL; if (arg_console) { tty_fd = acquire_terminal("/dev/console", false, false, false, USEC_INFINITY); if (tty_fd < 0) - return tty_fd; + return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m"); + + r = reset_terminal_fd(tty_fd, true); + if (r < 0) + log_warning_errno(r, "Failed to reset terminal, ignoring: %m"); } - r = ask_password_tty(message, not_after, echo, filename, &password); + r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password); if (arg_console) { - safe_close(tty_fd); + tty_fd = safe_close(tty_fd); release_terminal(); } @@ -334,67 +368,79 @@ static int parse_password(const char *filename, char **wall) { } } - if (IN_SET(r, -ETIME, -ENOENT)) + if (IN_SET(r, -ETIME, -ENOENT)) { /* If the query went away, that's OK */ - return 0; - - if (r < 0) - return log_error_errno(r, "Failed to query password: %m"); + r = 0; + goto finish; + } + if (r < 0) { + log_error_errno(r, "Failed to query password: %m"); + goto finish; + } socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (socket_fd < 0) - return log_error_errno(errno, "socket(): %m"); + if (socket_fd < 0) { + r = log_error_errno(errno, "socket(): %m"); + goto finish; + } sa.un.sun_family = AF_UNIX; strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); - r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, - offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)); - if (r < 0) { - log_error_errno(errno, "Failed to send: %m"); - return r; - } + r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)); + memory_erase(packet, packet_length); + if (r < 0) + return log_error_errno(errno, "Failed to send: %m"); } return 0; + +finish: + memory_erase(packet, packet_length); + return r; } static int wall_tty_block(void) { _cleanup_free_ char *p = NULL; - int fd, r; dev_t devnr; + int fd, r; r = get_ctty_devnr(0, &devnr); + if (r == -ENXIO) /* We have no controlling tty */ + return -ENOTTY; if (r < 0) - return r; + return log_error_errno(r, "Failed to get controlling TTY: %m"); if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0) - return -ENOMEM; + return log_oom(); mkdir_parents_label(p, 0700); mkfifo(p, 0600); fd = open(p, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); if (fd < 0) - return -errno; + return log_debug_errno(errno, "Failed to open %s: %m", p); return fd; } static bool wall_tty_match(const char *path, void *userdata) { - int fd, r; - struct stat st; _cleanup_free_ char *p = NULL; + _cleanup_close_ int fd = -1; + struct stat st; if (!path_is_absolute(path)) path = strjoina("/dev/", path); - r = lstat(path, &st); - if (r < 0) + if (lstat(path, &st) < 0) { + log_debug_errno(errno, "Failed to stat %s: %m", path); return true; + } - if (!S_ISCHR(st.st_mode)) + if (!S_ISCHR(st.st_mode)) { + log_debug("%s is not a character device.", path); return true; + } /* We use named pipes to ensure that wall messages suggesting * password entry are not printed over password prompts @@ -404,16 +450,19 @@ static bool wall_tty_match(const char *path, void *userdata) { * advantage that the block will automatically go away if the * process dies. */ - if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) + if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0) { + log_oom(); return true; + } fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY); - if (fd < 0) - return true; + if (fd < 0) { + log_debug_errno(errno, "Failed top open the wall pipe: %m"); + return 1; + } /* What, we managed to open the pipe? Then this tty is filtered. */ - safe_close(fd); - return false; + return 0; } static int show_passwords(void) { @@ -426,11 +475,10 @@ static int show_passwords(void) { if (errno == ENOENT) return 0; - log_error_errno(errno, "opendir(/run/systemd/ask-password): %m"); - return -errno; + return log_error_errno(errno, "Failed to open /run/systemd/ask-password: %m"); } - while ((de = readdir(d))) { + FOREACH_DIRENT_ALL(de, d, return log_error_errno(errno, "Failed to read directory: %m")) { _cleanup_free_ char *p = NULL, *wall = NULL; int q; @@ -455,7 +503,7 @@ static int show_passwords(void) { r = q; if (wall) - utmp_wall(wall, NULL, NULL, wall_tty_match, NULL); + (void) utmp_wall(wall, NULL, NULL, wall_tty_match, NULL); } return r; @@ -475,14 +523,14 @@ static int watch_passwords(void) { tty_block_fd = wall_tty_block(); - mkdir_p_label("/run/systemd/ask-password", 0755); + (void) mkdir_p_label("/run/systemd/ask-password", 0755); notify = inotify_init1(IN_CLOEXEC); if (notify < 0) - return -errno; + return log_error_errno(errno, "Failed to allocate directory watch: %m"); if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) - return -errno; + return log_error_errno(errno, "Failed to add /run/systemd/ask-password to directory watch: %m"); assert_se(sigemptyset(&mask) >= 0); assert_se(sigset_add_many(&mask, SIGINT, SIGTERM, -1) >= 0); @@ -490,7 +538,7 @@ static int watch_passwords(void) { signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); if (signal_fd < 0) - return -errno; + return log_error_errno(errno, "Failed to allocate signal file descriptor: %m"); pollfd[FD_INOTIFY].fd = notify; pollfd[FD_INOTIFY].events = POLLIN; @@ -510,7 +558,7 @@ static int watch_passwords(void) { } if (pollfd[FD_INOTIFY].revents != 0) - flush_fd(notify); + (void) flush_fd(notify); if (pollfd[FD_SIGNAL].revents != 0) break; @@ -571,9 +619,7 @@ static int parse_argv(int argc, char *argv[]) { return 0; case ARG_VERSION: - puts(PACKAGE_STRING); - puts(SYSTEMD_FEATURES); - return 0; + return version(); case ARG_LIST: arg_action = ACTION_LIST; @@ -628,8 +674,8 @@ int main(int argc, char *argv[]) { goto finish; if (arg_console) { - setsid(); - release_terminal(); + (void) setsid(); + (void) release_terminal(); } if (IN_SET(arg_action, ACTION_WATCH, ACTION_WALL)) @@ -637,9 +683,6 @@ int main(int argc, char *argv[]) { else r = show_passwords(); - if (r < 0) - log_error_errno(r, "Error: %m"); - finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/udev/.gitignore b/src/udev/.gitignore index ba112ce218..f5d8be3dc1 100644 --- a/src/udev/.gitignore +++ b/src/udev/.gitignore @@ -1,5 +1,4 @@ /udev.pc /keyboard-keys-from-name.gperf /keyboard-keys-from-name.h -/keyboard-keys-to-name.h /keyboard-keys-list.txt diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c index 1d1798dd10..1e414664ce 100644 --- a/src/udev/ata_id/ata_id.c +++ b/src/udev/ata_id/ata_id.c @@ -19,28 +19,30 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <unistd.h> -#include <fcntl.h> #include <ctype.h> -#include <string.h> #include <errno.h> +#include <fcntl.h> #include <getopt.h> +#include <linux/bsg.h> +#include <linux/hdreg.h> #include <scsi/scsi.h> -#include <scsi/sg.h> #include <scsi/scsi_ioctl.h> +#include <scsi/sg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> -#include <sys/types.h> #include <sys/stat.h> -#include <linux/hdreg.h> -#include <linux/bsg.h> +#include <sys/types.h> +#include <unistd.h> #include "libudev.h" + +#include "fd-util.h" #include "libudev-private.h" -#include "udev-util.h" #include "log.h" +#include "udev-util.h" #define COMMAND_TIMEOUT_MSEC (30 * 1000) diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c index 001bae7a24..72f284f710 100644 --- a/src/udev/cdrom_id/cdrom_id.c +++ b/src/udev/cdrom_id/cdrom_id.c @@ -17,24 +17,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <limits.h> -#include <fcntl.h> #include <errno.h> +#include <fcntl.h> #include <getopt.h> -#include <time.h> +#include <limits.h> +#include <linux/cdrom.h> #include <scsi/sg.h> -#include <sys/types.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> #include <sys/stat.h> #include <sys/time.h> -#include <sys/ioctl.h> -#include <linux/cdrom.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> #include "libudev.h" + #include "libudev-private.h" #include "random-util.h" diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c index b3a1f0bca1..b6c95cd452 100644 --- a/src/udev/collect/collect.c +++ b/src/udev/collect/collect.c @@ -19,13 +19,15 @@ * */ -#include <stdio.h> -#include <stddef.h> #include <errno.h> #include <getopt.h> +#include <stddef.h> +#include <stdio.h> +#include "alloc-util.h" #include "libudev-private.h" #include "macro.h" +#include "string-util.h" #define BUFSIZE 16 #define UDEV_ALARM_TIMEOUT 180 diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c index a4b05d1bec..0647008d90 100644 --- a/src/udev/net/ethtool-util.c +++ b/src/udev/net/ethtool-util.c @@ -19,17 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/ioctl.h> #include <net/if.h> +#include <sys/ioctl.h> #include <linux/ethtool.h> #include <linux/sockios.h> +#include "conf-parser.h" #include "ethtool-util.h" - +#include "log.h" +#include "string-table.h" #include "strxcpyx.h" #include "util.h" -#include "log.h" -#include "conf-parser.h" static const char* const duplex_table[_DUP_MAX] = { [DUP_FULL] = "full", diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 63e54db56e..776674e994 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -22,22 +22,28 @@ #include <netinet/ether.h> #include <linux/netdevice.h> +#include "sd-netlink.h" -#include "missing.h" -#include "link-config.h" +#include "alloc-util.h" +#include "conf-files.h" +#include "conf-parser.h" #include "ethtool-util.h" - +#include "fd-util.h" #include "libudev-private.h" -#include "sd-netlink.h" -#include "util.h" +#include "link-config.h" #include "log.h" -#include "strv.h" -#include "path-util.h" -#include "conf-parser.h" -#include "conf-files.h" +#include "missing.h" #include "netlink-util.h" #include "network-internal.h" +#include "parse-util.h" +#include "path-util.h" +#include "proc-cmdline.h" #include "random-util.h" +#include "stat-util.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" struct link_config_ctx { LIST_HEAD(link_config, links); @@ -460,6 +466,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config, mac = &generated_mac; } break; + case MACPOLICY_NONE: default: mac = config->mac; } @@ -492,7 +499,8 @@ int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret static const char* const mac_policy_table[_MACPOLICY_MAX] = { [MACPOLICY_PERSISTENT] = "persistent", - [MACPOLICY_RANDOM] = "random" + [MACPOLICY_RANDOM] = "random", + [MACPOLICY_NONE] = "none" }; DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy); diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 9875057e84..4fcbee8b92 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -21,10 +21,11 @@ #pragma once -#include "ethtool-util.h" +#include "libudev.h" + #include "condition.h" +#include "ethtool-util.h" #include "list.h" -#include "libudev.h" typedef struct link_config_ctx link_config_ctx; typedef struct link_config link_config; @@ -32,6 +33,7 @@ typedef struct link_config link_config; typedef enum MACPolicy { MACPOLICY_PERSISTENT, MACPOLICY_RANDOM, + MACPOLICY_NONE, _MACPOLICY_MAX, _MACPOLICY_INVALID = -1 } MACPolicy; diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c index adb91869df..4655691642 100644 --- a/src/udev/scsi_id/scsi_id.c +++ b/src/udev/scsi_id/scsi_id.c @@ -16,22 +16,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <signal.h> #include <stdarg.h> #include <stdbool.h> -#include <unistd.h> -#include <signal.h> -#include <fcntl.h> -#include <errno.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <ctype.h> -#include <getopt.h> #include <sys/stat.h> +#include <unistd.h> #include "libudev.h" + +#include "fd-util.h" #include "libudev-private.h" #include "scsi_id.h" +#include "string-util.h" #include "udev-util.h" static const struct option options[] = { diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c index de3b4f7581..c7ef783684 100644 --- a/src/udev/scsi_id/scsi_serial.c +++ b/src/udev/scsi_id/scsi_serial.c @@ -17,27 +17,29 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/stat.h> -#include <stdio.h> #include <errno.h> -#include <string.h> #include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <time.h> #include <inttypes.h> +#include <linux/bsg.h> +#include <linux/types.h> #include <scsi/scsi.h> #include <scsi/sg.h> -#include <linux/types.h> -#include <linux/bsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <time.h> +#include <unistd.h> #include "libudev.h" + #include "libudev-private.h" +#include "random-util.h" #include "scsi.h" #include "scsi_id.h" -#include "random-util.h" +#include "string-util.h" /* * A priority based list of id, naa, and binary/ascii for the identifier diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index b8066ea6e9..d0e47ec6d8 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -18,18 +18,22 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +#include <blkid/blkid.h> #include <errno.h> #include <fcntl.h> #include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/stat.h> -#include <blkid/blkid.h> #include "sd-id128.h" -#include "gpt.h" + +#include "alloc-util.h" #include "efivars.h" +#include "fd-util.h" +#include "gpt.h" +#include "string-util.h" #include "udev.h" static void print_property(struct udev_device *dev, bool test, const char *name, const char *value) { diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 3352821567..cfaa463804 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -17,15 +17,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <fcntl.h> +#include <stdlib.h> #include <sys/ioctl.h> #ifdef HAVE_LINUX_BTRFS_H #include <linux/btrfs.h> #endif +#include "fd-util.h" #include "missing.h" +#include "string-util.h" #include "udev.h" static int builtin_btrfs(struct udev_device *dev, int argc, char *argv[], bool test) { diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c index 72109d93d2..f4a065a97d 100644 --- a/src/udev/udev-builtin-hwdb.c +++ b/src/udev/udev-builtin-hwdb.c @@ -17,16 +17,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdlib.h> #include <fnmatch.h> #include <getopt.h> +#include <stdio.h> +#include <stdlib.h> -#include "udev.h" #include "sd-hwdb.h" +#include "alloc-util.h" #include "hwdb-util.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" static sd_hwdb *hwdb; diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index e3fa4bc162..fddafbd4dc 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -21,15 +21,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> #include <string.h> -#include <errno.h> +#include <unistd.h> #include <linux/limits.h> #include <linux/input.h> +#include "fd-util.h" +#include "string-util.h" #include "udev.h" #include "util.h" diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index d63a8e2760..aa10beafb0 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -18,11 +18,15 @@ ***/ #include <stdio.h> -#include <string.h> #include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> #include <linux/input.h> +#include "fd-util.h" +#include "parse-util.h" +#include "stdio-util.h" +#include "string-util.h" #include "udev.h" static const struct key *keyboard_lookup_key(const char *str, unsigned len); diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c index 81e78a8aa3..9665f678fd 100644 --- a/src/udev/udev-builtin-kmod.c +++ b/src/udev/udev-builtin-kmod.c @@ -18,12 +18,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> #include <errno.h> #include <libkmod.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include "string-util.h" #include "udev.h" static struct kmod_ctx *ctx = NULL; diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index 589f1f7822..bf5c9c6b77 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -27,7 +27,7 @@ * http://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames * * Two character prefixes based on the type of interface: - * en -- ethernet + * en -- Ethernet * sl -- serial line IP (slip) * wl -- wlan * ww -- wwan @@ -53,17 +53,17 @@ * exported. * The usual USB configuration == 1 and interface == 0 values are suppressed. * - * PCI ethernet card with firmware index "1": + * PCI Ethernet card with firmware index "1": * ID_NET_NAME_ONBOARD=eno1 * ID_NET_NAME_ONBOARD_LABEL=Ethernet Port 1 * - * PCI ethernet card in hotplug slot with firmware index number: + * PCI Ethernet card in hotplug slot with firmware index number: * /sys/devices/pci0000:00/0000:00:1c.3/0000:05:00.0/net/ens1 * ID_NET_NAME_MAC=enx000000000466 * ID_NET_NAME_PATH=enp5s0 * ID_NET_NAME_SLOT=ens1 * - * PCI ethernet multi-function card with 2 ports: + * PCI Ethernet multi-function card with 2 ports: * /sys/devices/pci0000:00/0000:00:1c.0/0000:02:00.0/net/enp2s0f0 * ID_NET_NAME_MAC=enx78e7d1ea46da * ID_NET_NAME_PATH=enp2s0f0 @@ -87,19 +87,21 @@ * ID_NET_NAME_PATH=enp0s29u1u2 */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> #include <errno.h> +#include <fcntl.h> #include <net/if.h> #include <net/if_arp.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #include <linux/pci_regs.h> -#include "udev.h" +#include "fd-util.h" #include "fileio.h" +#include "string-util.h" +#include "udev.h" enum netname_type{ NET_UNDEF, diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index d4589470fb..f72894b5c5 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -19,9 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "alloc-util.h" #include "link-config.h" -#include "udev.h" #include "log.h" +#include "udev.h" static link_config_ctx *ctx = NULL; diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 01e2c659ae..1e190140b2 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -19,17 +19,19 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> -#include <string.h> #include <ctype.h> -#include <fcntl.h> -#include <errno.h> #include <dirent.h> +#include <errno.h> +#include <fcntl.h> #include <getopt.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "alloc-util.h" +#include "string-util.h" #include "udev.h" _printf_(2,3) diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index 7bf4e7f24d..bbda9de08c 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -22,7 +22,9 @@ #include <stdlib.h> #include <errno.h> -#include "systemd/sd-login.h" +#include "sd-login.h" + +#include "login-util.h" #include "logind-acl.h" #include "udev.h" #include "util.h" @@ -56,7 +58,7 @@ static int builtin_uaccess(struct udev_device *dev, int argc, char *argv[], bool r = devnode_acl(path, true, false, 0, true, uid); if (r < 0) { - log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path); + log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_ERR, r, "Failed to apply ACL on %s: %m", path); goto finish; } diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c index d309dc31cb..587649eff0 100644 --- a/src/udev/udev-builtin-usb_id.c +++ b/src/udev/udev-builtin-usb_id.c @@ -20,15 +20,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> #include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <unistd.h> #include <string.h> -#include <ctype.h> -#include <fcntl.h> -#include <errno.h> +#include <unistd.h> +#include "alloc-util.h" +#include "fd-util.h" +#include "string-util.h" #include "udev.h" static void set_usb_iftype(char *to, int if_class_num, size_t len) { diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index 4f625251d6..e6b36f124f 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -17,10 +17,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <getopt.h> #include <stdio.h> #include <string.h> -#include <getopt.h> +#include "string-util.h" #include "udev.h" static bool initialized; diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 56277f551f..1e05be51a5 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -18,8 +18,10 @@ #include <sys/socket.h> #include <sys/un.h> -#include "socket-util.h" +#include "alloc-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "socket-util.h" #include "udev.h" /* wire protocol magic must match */ diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 1e34cbc2f5..5d6542d3ad 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -15,26 +15,29 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> #include <ctype.h> -#include <string.h> +#include <errno.h> +#include <fcntl.h> #include <net/if.h> -#include <sys/prctl.h> #include <poll.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/epoll.h> -#include <sys/wait.h> +#include <sys/prctl.h> #include <sys/signalfd.h> +#include <sys/wait.h> +#include <unistd.h> -#include "netlink-util.h" +#include "alloc-util.h" #include "event-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "netlink-util.h" #include "process-util.h" #include "signal-util.h" +#include "string-util.h" #include "udev.h" typedef struct Spawn { @@ -438,9 +441,7 @@ static int spawn_exec(struct udev_event *event, execve(argv[0], argv, envp); /* exec failed */ - log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd); - - return -errno; + return log_error_errno(errno, "failed to execute '%s' '%s': %m", argv[0], cmd); } static void spawn_read(struct udev_event *event, diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index e730fb45f1..c2edf2c5cd 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -15,20 +15,22 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <string.h> -#include <stdio.h> -#include <stddef.h> -#include <stdbool.h> -#include <fcntl.h> -#include <unistd.h> -#include <errno.h> #include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> #include <sys/stat.h> +#include <unistd.h> -#include "udev.h" -#include "smack-util.h" -#include "selinux-util.h" #include "formats-util.h" +#include "fs-util.h" +#include "selinux-util.h" +#include "smack-util.h" +#include "string-util.h" +#include "udev.h" static int node_symlink(struct udev_device *dev, const char *node, const char *slink) { struct stat stats; @@ -261,8 +263,7 @@ static int node_permissions_apply(struct udev_device *dev, bool apply, mode |= S_IFCHR; if (lstat(devnode, &stats) != 0) { - err = -errno; - log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode); + err = log_debug_errno(errno, "can not stat() node '%s' (%m)", devnode); goto out; } diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 98c33171d4..c06ace09cf 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -15,27 +15,34 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stddef.h> -#include <limits.h> -#include <stdlib.h> -#include <stdbool.h> -#include <string.h> -#include <stdio.h> -#include <fcntl.h> #include <ctype.h> -#include <unistd.h> -#include <errno.h> #include <dirent.h> +#include <errno.h> +#include <fcntl.h> #include <fnmatch.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <time.h> +#include <unistd.h> -#include "udev.h" -#include "path-util.h" +#include "alloc-util.h" #include "conf-files.h" +#include "escape.h" +#include "fd-util.h" +#include "glob-util.h" +#include "path-util.h" +#include "stat-util.h" #include "strbuf.h" +#include "string-util.h" #include "strv.h" -#include "util.h" #include "sysctl-util.h" +#include "udev.h" +#include "user-util.h" +#include "util.h" #define PREALLOC_TOKEN 2048 @@ -51,7 +58,8 @@ static const char* const rules_dirs[] = { "/etc/udev/rules.d", "/run/udev/rules.d", UDEVLIBEXECDIR "/rules.d", - NULL}; + NULL +}; struct udev_rules { struct udev *udev; @@ -1937,7 +1945,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules, break; } } - if (!match && (cur->key.op != OP_NOMATCH)) + if ((!match && (cur->key.op != OP_NOMATCH)) || + (match && (cur->key.op == OP_NOMATCH))) goto nomatch; break; } @@ -2514,7 +2523,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); r = sysctl_write(filename, value); if (r < 0) - log_error("error writing SYSCTL{%s}='%s': %s", filename, value, strerror(-r)); + log_error_errno(r, "error writing SYSCTL{%s}='%s': %m", filename, value); break; } case TK_A_RUN_BUILTIN: diff --git a/src/udev/udev.h b/src/udev/udev.h index d17fc8c1ea..1f9c8120c0 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -18,16 +18,17 @@ #pragma once -#include <sys/types.h> #include <sys/param.h> +#include <sys/types.h> -#include "macro.h" -#include "sd-netlink.h" #include "libudev.h" -#include "libudev-private.h" -#include "util.h" +#include "sd-netlink.h" + #include "label.h" +#include "libudev-private.h" +#include "macro.h" #include "strv.h" +#include "util.h" struct udev_event { struct udev *udev; diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 00609e31b5..031a099d77 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -17,18 +17,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <ctype.h> #include <getopt.h> +#include <stdlib.h> #include <string.h> -#include <ctype.h> -#include "util.h" -#include "strbuf.h" +#include "alloc-util.h" #include "conf-files.h" - -#include "udev.h" +#include "fileio.h" +#include "fs-util.h" #include "hwdb-internal.h" #include "hwdb-util.h" +#include "strbuf.h" +#include "string-util.h" +#include "udev.h" +#include "util.h" /* * Generic udev properties, key/value database based on modalias strings. diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index b3d5565c48..7182668f23 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -15,19 +15,21 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <string.h> -#include <stdio.h> -#include <stddef.h> #include <ctype.h> -#include <unistd.h> #include <dirent.h> #include <errno.h> -#include <getopt.h> #include <fcntl.h> +#include <getopt.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> #include <sys/stat.h> +#include <unistd.h> -#include "udev.h" +#include "fd-util.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" #include "udevadm-util.h" static bool skip_attribute(const char *name) { diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index 5e93955186..30aa53feb2 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -25,9 +25,10 @@ #include <sys/time.h> #include <sys/epoll.h> -#include "udev.h" -#include "udev-util.h" +#include "fd-util.h" #include "formats-util.h" +#include "udev-util.h" +#include "udev.h" static bool udev_exit; diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 79f45610db..c25071b0fe 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -26,6 +26,7 @@ #include <getopt.h> #include <poll.h> +#include "parse-util.h" #include "udev.h" #include "util.h" @@ -65,10 +66,9 @@ static int adm_settle(struct udev *udev, int argc, char *argv[]) { r = safe_atou(optarg, &timeout); if (r < 0) { - fprintf(stderr, "Invalid timeout value '%s': %s\n", - optarg, strerror(-r)); - exit(EXIT_FAILURE); - }; + log_error_errno(r, "Invalid timeout value '%s': %m", optarg); + return EXIT_FAILURE; + } break; } diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index 35a7349439..0b180d03eb 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -15,12 +15,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stddef.h> -#include <stdio.h> #include <errno.h> #include <getopt.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include "string-util.h" #include "udev.h" static void help(struct udev *udev) { diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index d04e618d0d..ff427cf292 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -16,17 +16,18 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> #include <errno.h> -#include <signal.h> #include <getopt.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> #include <sys/signalfd.h> +#include <unistd.h> -#include "udev.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" static void help(void) { diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 7af9665f8a..9d52345d92 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -15,16 +15,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> #include <stddef.h> -#include <string.h> #include <stdio.h> +#include <string.h> #include <unistd.h> -#include <getopt.h> -#include <errno.h> -#include <fcntl.h> -#include "udev.h" +#include "string-util.h" #include "udev-util.h" +#include "udev.h" #include "udevadm-util.h" #include "util.h" diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index 3f0e45e26c..3539c1d6ab 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -15,6 +15,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "string-util.h" #include "udevadm-util.h" struct udev_device *find_device(struct udev *udev, diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index b86d8921f3..60f122ebda 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -16,12 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stddef.h> #include <errno.h> #include <getopt.h> +#include <stddef.h> +#include <stdio.h> #include "selinux-util.h" +#include "string-util.h" #include "udev.h" static int adm_version(struct udev *udev, int argc, char *argv[]) { diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 20497ae8be..5364b92a57 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -18,44 +18,54 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stddef.h> -#include <signal.h> -#include <unistd.h> #include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <signal.h> +#include <stdbool.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> -#include <stdbool.h> #include <string.h> -#include <fcntl.h> -#include <getopt.h> +#include <sys/epoll.h> #include <sys/file.h> -#include <sys/time.h> +#include <sys/inotify.h> +#include <sys/ioctl.h> +#include <sys/mount.h> #include <sys/prctl.h> -#include <sys/socket.h> #include <sys/signalfd.h> -#include <sys/epoll.h> -#include <sys/mount.h> -#include <sys/wait.h> +#include <sys/socket.h> #include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/inotify.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <unistd.h> #include "sd-daemon.h" #include "sd-event.h" -#include "terminal-util.h" -#include "signal-util.h" -#include "event-util.h" -#include "netlink-util.h" +#include "alloc-util.h" #include "cgroup-util.h" -#include "process-util.h" +#include "cpu-set-util.h" #include "dev-setup.h" +#include "event-util.h" +#include "fd-util.h" #include "fileio.h" -#include "selinux-util.h" -#include "udev.h" -#include "udev-util.h" #include "formats-util.h" +#include "fs-util.h" #include "hashmap.h" +#include "io-util.h" +#include "netlink-util.h" +#include "parse-util.h" +#include "proc-cmdline.h" +#include "process-util.h" +#include "selinux-util.h" +#include "signal-util.h" +#include "socket-util.h" +#include "string-util.h" +#include "terminal-util.h" +#include "udev-util.h" +#include "udev.h" +#include "user-util.h" static bool arg_debug = false; static int arg_daemonize = false; @@ -1548,7 +1558,7 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg r = sd_event_default(&manager->event); if (r < 0) - return log_error_errno(errno, "could not allocate event loop: %m"); + return log_error_errno(r, "could not allocate event loop: %m"); r = sd_event_add_signal(manager->event, NULL, SIGINT, on_sigterm, manager); if (r < 0) diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c index 5c57db44c1..607d78a019 100644 --- a/src/udev/v4l_id/v4l_id.c +++ b/src/udev/v4l_id/v4l_id.c @@ -26,6 +26,7 @@ #include <sys/ioctl.h> #include <linux/videodev2.h> +#include "fd-util.h" #include "util.h" int main(int argc, char *argv[]) { diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 01bbde8455..4c44d50613 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -19,8 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" +#include "fd-util.h" +#include "io-util.h" #include "selinux-util.h" +#include "util.h" #define MESSAGE \ "This file was created by systemd-update-done. Its only \n" \ diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index b2998dce43..d50063cbcd 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -29,15 +29,16 @@ #include "sd-bus.h" +#include "alloc-util.h" +#include "bus-error.h" +#include "bus-util.h" +#include "formats-util.h" #include "log.h" #include "macro.h" -#include "util.h" #include "special.h" -#include "utmp-wtmp.h" -#include "bus-util.h" -#include "bus-error.h" #include "unit-name.h" -#include "formats-util.h" +#include "util.h" +#include "utmp-wtmp.h" typedef struct Context { sd_bus *bus; @@ -62,7 +63,7 @@ static usec_t get_startup_time(Context *c) { &error, 't', &t); if (r < 0) { - log_error("Failed to get timestamp: %s", bus_error_message(&error, -r)); + log_error_errno(r, "Failed to get timestamp: %s", bus_error_message(&error, r)); return 0; } @@ -105,10 +106,8 @@ static int get_current_runlevel(Context *c) { "ActiveState", &error, &state); - if (r < 0) { - log_warning("Failed to get state: %s", bus_error_message(&error, -r)); - return r; - } + if (r < 0) + return log_warning_errno(r, "Failed to get state: %s", bus_error_message(&error, r)); if (streq(state, "active") || streq(state, "reloading")) return table[i].runlevel; @@ -130,8 +129,7 @@ static int on_reboot(Context *c) { if (c->audit_fd >= 0) if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_BOOT, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM) { - r = log_error_errno(errno, - "Failed to send audit message: %m"); + r = log_error_errno(errno, "Failed to send audit message: %m"); } #endif @@ -160,8 +158,7 @@ static int on_shutdown(Context *c) { if (c->audit_fd >= 0) if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_SHUTDOWN, "", "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM) { - r = log_error_errno(errno, - "Failed to send audit message: %m"); + r = log_error_errno(errno, "Failed to send audit message: %m"); } #endif @@ -211,8 +208,7 @@ static int on_runlevel(Context *c) { return log_oom(); if (audit_log_user_comm_message(c->audit_fd, AUDIT_SYSTEM_RUNLEVEL, s, "systemd-update-utmp", NULL, NULL, NULL, 1) < 0 && errno != EPERM) - r = log_error_errno(errno, - "Failed to send audit message: %m"); + r = log_error_errno(errno, "Failed to send audit message: %m"); } #endif @@ -256,7 +252,7 @@ int main(int argc, char *argv[]) { if (c.audit_fd < 0 && errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT) log_error_errno(errno, "Failed to connect to audit log: %m"); #endif - r = bus_open_system_systemd(&c.bus); + r = bus_connect_system_systemd(&c.bus); if (r < 0) { log_error_errno(r, "Failed to get D-Bus connection: %m"); r = -EIO; @@ -284,6 +280,6 @@ finish: audit_close(c.audit_fd); #endif - sd_bus_unref(c.bus); + sd_bus_flush_close_unref(c.bus); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 7c736c44d2..252cbdb26c 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -19,12 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> +#include <unistd.h> +#include "fileio.h" #include "log.h" +#include "string-util.h" #include "util.h" -#include "fileio.h" int main(int argc, char*argv[]) { diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index 6353579283..a5f4529cfd 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -19,25 +19,30 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <unistd.h> -#include <stdlib.h> #include <errno.h> #include <fcntl.h> -#include <stdbool.h> #include <limits.h> -#include <sys/ioctl.h> -#include <linux/tiocl.h> #include <linux/kd.h> +#include <linux/tiocl.h> #include <linux/vt.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <unistd.h> -#include "util.h" -#include "log.h" -#include "virt.h" +#include "alloc-util.h" +#include "fd-util.h" #include "fileio.h" +#include "io-util.h" +#include "locale-util.h" +#include "log.h" #include "process-util.h" -#include "terminal-util.h" #include "signal-util.h" +#include "string-util.h" +#include "terminal-util.h" +#include "util.h" +#include "virt.h" static bool is_vconsole(int fd) { unsigned char data[1]; @@ -270,7 +275,7 @@ int main(int argc, char **argv) { fd = open_terminal(vc, O_RDWR|O_CLOEXEC); if (fd < 0) { - log_error_errno(errno, "Failed to open %s: %m", vc); + log_error_errno(fd, "Failed to open %s: %m", vc); return EXIT_FAILURE; } diff --git a/systemd-master/catalog/systemd.da.catalog b/systemd-master/catalog/systemd.da.catalog new file mode 100644 index 0000000000..dc3f8b552e --- /dev/null +++ b/systemd-master/catalog/systemd.da.catalog @@ -0,0 +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.
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/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..e2b09e1550 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-invert.service @@ -0,0 +1,6 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | grep "cap_chown"); echo $c; exit $(test -z $c)' +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..b0f4732529 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-merge.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | cut -f 2 -d "="); echo $c; exit $(test $c = "cap_chown,cap_fowner,cap_kill")' +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..51092ab0d5 --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-reset.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | cut -f 2 -d "="); echo $c; exit $(test -z $c)' +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..b9037a0ddf --- /dev/null +++ b/test/test-execute/exec-capabilityboundingset-simple.service @@ -0,0 +1,6 @@ +[Unit] +Description=Test for CapabilityBoundingSet + +[Service] +ExecStart=/bin/sh -c 'c=$(capsh --print | grep "Bounding set " | cut -f 2 -d "="); echo $c; exit $(test $c = "cap_fowner,cap_kill")' +CapabilityBoundingSet=CAP_FOWNER CAP_KILL diff --git a/test/exec-environment-empty.service b/test/test-execute/exec-environment-empty.service index 0219ca4fd7..0219ca4fd7 100644 --- a/test/exec-environment-empty.service +++ b/test/test-execute/exec-environment-empty.service diff --git a/test/exec-environment-multiple.service b/test/test-execute/exec-environment-multiple.service index 479005a5d8..479005a5d8 100644 --- a/test/exec-environment-multiple.service +++ b/test/test-execute/exec-environment-multiple.service diff --git a/test/exec-environment.service b/test/test-execute/exec-environment.service index 4586b4c4a9..4586b4c4a9 100644 --- a/test/exec-environment.service +++ b/test/test-execute/exec-environment.service diff --git a/test/test-execute/exec-environmentfile.service b/test/test-execute/exec-environmentfile.service new file mode 100644 index 0000000000..848f2a120c --- /dev/null +++ b/test/test-execute/exec-environmentfile.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for EnvironmentFile + +[Service] +ExecStart=/bin/sh -c 'exit $(test "$VAR1" = "word1 word2") && $(test "$VAR2" = word3) && $(test "$VAR3" = \'$word 5 6\')' +Type=oneshot +EnvironmentFile=/tmp/test-exec_environmentfile.conf diff --git a/test/exec-group.service b/test/test-execute/exec-group.service index 1aa04b5bd2..1aa04b5bd2 100644 --- a/test/exec-group.service +++ b/test/test-execute/exec-group.service diff --git a/test/exec-ignoresigpipe-no.service b/test/test-execute/exec-ignoresigpipe-no.service index 69b2e9d8a8..69b2e9d8a8 100644 --- a/test/exec-ignoresigpipe-no.service +++ b/test/test-execute/exec-ignoresigpipe-no.service diff --git a/test/exec-ignoresigpipe-yes.service b/test/test-execute/exec-ignoresigpipe-yes.service index 877ec8aed0..877ec8aed0 100644 --- a/test/exec-ignoresigpipe-yes.service +++ b/test/test-execute/exec-ignoresigpipe-yes.service 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..56e2718505 --- /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/bash -c 'c=$(ionice); echo $c; [[ "$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..b45795cab7 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-idle.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=idle + +[Service] +ExecStart=/bin/bash -c 'c=$(ionice); echo $c; [[ "$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..36b546ca01 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-none.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=none + +[Service] +ExecStart=/bin/bash -c 'c=$(ionice); echo $c; [[ "$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..74936d8079 --- /dev/null +++ b/test/test-execute/exec-ioschedulingclass-realtime.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for IOSchedulingClass=realtime + +[Service] +ExecStart=/bin/bash -c 'c=$(ionice); echo $c; [[ "$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..63ab501c63 --- /dev/null +++ b/test/test-execute/exec-oomscoreadjust-negative.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for OOMScoreAdjust + +[Service] +ExecStart=/bin/bash -c 'c=$(cat /proc/self/oom_score_adj); echo $c; exit $(test $c -eq -100)' +OOMScoreAdjust=-100 +Type=oneshot diff --git a/test/test-execute/exec-oomscoreadjust-positive.service b/test/test-execute/exec-oomscoreadjust-positive.service new file mode 100644 index 0000000000..e47a4f1392 --- /dev/null +++ b/test/test-execute/exec-oomscoreadjust-positive.service @@ -0,0 +1,7 @@ +[Unit] +Description=Test for OOMScoreAdjust + +[Service] +ExecStart=/bin/bash -c 'c=$(cat /proc/self/oom_score_adj); echo $c; exit $(test $c -eq 100)' +OOMScoreAdjust=100 +Type=oneshot diff --git a/test/exec-personality-s390.service b/test/test-execute/exec-personality-s390.service index f3c3b03e3d..f3c3b03e3d 100644 --- a/test/exec-personality-s390.service +++ b/test/test-execute/exec-personality-s390.service diff --git a/test/exec-personality-x86-64.service b/test/test-execute/exec-personality-x86-64.service index 5bb5d910d0..5bb5d910d0 100644 --- a/test/exec-personality-x86-64.service +++ b/test/test-execute/exec-personality-x86-64.service diff --git a/test/exec-personality-x86.service b/test/test-execute/exec-personality-x86.service index 0b370a6480..0b370a6480 100644 --- a/test/exec-personality-x86.service +++ b/test/test-execute/exec-personality-x86.service diff --git a/test/exec-privatedevices-no.service b/test/test-execute/exec-privatedevices-no.service index cf4f275fb6..cf4f275fb6 100644 --- a/test/exec-privatedevices-no.service +++ b/test/test-execute/exec-privatedevices-no.service diff --git a/test/exec-privatedevices-yes.service b/test/test-execute/exec-privatedevices-yes.service index 85b3f4f981..85b3f4f981 100644 --- a/test/exec-privatedevices-yes.service +++ b/test/test-execute/exec-privatedevices-yes.service diff --git a/test/test-execute/exec-privatenetwork-yes.service b/test/test-execute/exec-privatenetwork-yes.service new file mode 100644 index 0000000000..494712e6a7 --- /dev/null +++ b/test/test-execute/exec-privatenetwork-yes.service @@ -0,0 +1,6 @@ +[Unit] +Description=Test for PrivateNetwork + +[Service] +ExecStart=/bin/sh -c 'i=$(ip link | grep ": " | grep -v lo); echo $i; exit $(test -z $i)' +PrivateNetwork=yes diff --git a/test/exec-privatetmp-no.service b/test/test-execute/exec-privatetmp-no.service index d69e552a63..d69e552a63 100644 --- a/test/exec-privatetmp-no.service +++ b/test/test-execute/exec-privatetmp-no.service diff --git a/test/exec-privatetmp-yes.service b/test/test-execute/exec-privatetmp-yes.service index 881a040b87..881a040b87 100644 --- a/test/exec-privatetmp-yes.service +++ b/test/test-execute/exec-privatetmp-yes.service diff --git a/test/exec-runtimedirectory-mode.service b/test/test-execute/exec-runtimedirectory-mode.service index ba6d7ee39f..ba6d7ee39f 100644 --- a/test/exec-runtimedirectory-mode.service +++ b/test/test-execute/exec-runtimedirectory-mode.service diff --git a/test/exec-runtimedirectory-owner.service b/test/test-execute/exec-runtimedirectory-owner.service index 077e08d1c5..077e08d1c5 100644 --- a/test/exec-runtimedirectory-owner.service +++ b/test/test-execute/exec-runtimedirectory-owner.service diff --git a/test/exec-runtimedirectory.service b/test/test-execute/exec-runtimedirectory.service index c12a6c63d6..c12a6c63d6 100644 --- a/test/exec-runtimedirectory.service +++ b/test/test-execute/exec-runtimedirectory.service diff --git a/test/exec-systemcallerrornumber.service b/test/test-execute/exec-systemcallerrornumber.service index 255a8b231a..b11a952bd6 100644 --- a/test/exec-systemcallerrornumber.service +++ b/test/test-execute/exec-systemcallerrornumber.service @@ -2,6 +2,6 @@ Description=Test for SystemCallErrorNumber [Service] -ExecStart=/usr/bin/uname -a +ExecStart=/bin/sh -c 'uname -a' SystemCallFilter=~uname SystemCallErrorNumber=EACCES diff --git a/test/exec-systemcallfilter-failing.service b/test/test-execute/exec-systemcallfilter-failing.service index c6ce9368c9..c6ce9368c9 100644 --- a/test/exec-systemcallfilter-failing.service +++ b/test/test-execute/exec-systemcallfilter-failing.service diff --git a/test/exec-systemcallfilter-failing2.service b/test/test-execute/exec-systemcallfilter-failing2.service index b7f7c2aff9..b7f7c2aff9 100644 --- a/test/exec-systemcallfilter-failing2.service +++ b/test/test-execute/exec-systemcallfilter-failing2.service diff --git a/test/exec-systemcallfilter-not-failing.service b/test/test-execute/exec-systemcallfilter-not-failing.service index feb206ab6d..feb206ab6d 100644 --- a/test/exec-systemcallfilter-not-failing.service +++ b/test/test-execute/exec-systemcallfilter-not-failing.service diff --git a/test/exec-systemcallfilter-not-failing2.service b/test/test-execute/exec-systemcallfilter-not-failing2.service index cca469aa3d..cca469aa3d 100644 --- a/test/exec-systemcallfilter-not-failing2.service +++ b/test/test-execute/exec-systemcallfilter-not-failing2.service diff --git a/test/exec-umask-0177.service b/test/test-execute/exec-umask-0177.service index af9295888e..af9295888e 100644 --- a/test/exec-umask-0177.service +++ b/test/test-execute/exec-umask-0177.service diff --git a/test/exec-umask-default.service b/test/test-execute/exec-umask-default.service index 41e20a60a1..41e20a60a1 100644 --- a/test/exec-umask-default.service +++ b/test/test-execute/exec-umask-default.service diff --git a/test/exec-user.service b/test/test-execute/exec-user.service index 2ca08ebb42..2ca08ebb42 100644 --- a/test/exec-user.service +++ b/test/test-execute/exec-user.service diff --git a/test/exec-workingdirectory.service b/test/test-execute/exec-workingdirectory.service index 10855d682a..10855d682a 100644 --- a/test/exec-workingdirectory.service +++ b/test/test-execute/exec-workingdirectory.service diff --git a/test/test-functions b/test/test-functions index 8272e52e17..ab77576573 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 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/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 049371884a..c89740df05 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -59,7 +59,7 @@ /systemd-resolved.service /systemd-resolved.service.m4 /systemd-hibernate-resume@.service -/systemd-rfkill@.service +/systemd-rfkill.service /systemd-suspend.service /systemd-sysctl.service /systemd-sysusers.service @@ -78,4 +78,5 @@ /systemd-update-utmp.service /systemd-user-sessions.service /systemd-vconsole-setup.service +/tmp.mount /user@.service diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in index cc88ecd0db..b7079e4a7c 100644 --- a/units/systemd-hostnamed.service.in +++ b/units/systemd-hostnamed.service.in @@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/hostnamed ExecStart=@rootlibexecdir@/systemd-hostnamed BusName=org.freedesktop.hostname1 CapabilityBoundingSet=CAP_SYS_ADMIN -WatchdogSec=1min +WatchdogSec=3min PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes diff --git a/units/systemd-importd.service.in b/units/systemd-importd.service.in index 403f15316d..d3238cf8f5 100644 --- a/units/systemd-importd.service.in +++ b/units/systemd-importd.service.in @@ -14,5 +14,5 @@ ExecStart=@rootlibexecdir@/systemd-importd BusName=org.freedesktop.import1 CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP CAP_DAC_OVERRIDE NoNewPrivileges=yes -WatchdogSec=1min +WatchdogSec=3min KillMode=mixed diff --git a/units/systemd-journal-remote.service.in b/units/systemd-journal-remote.service.in index 4a898d62f3..2928a23021 100644 --- a/units/systemd-journal-remote.service.in +++ b/units/systemd-journal-remote.service.in @@ -18,7 +18,7 @@ Group=systemd-journal-remote PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes -WatchdogSec=10min +WatchdogSec=3min [Install] Also=systemd-journal-remote.socket diff --git a/units/systemd-journal-upload.service.in b/units/systemd-journal-upload.service.in index b2e3c769cc..a757673a62 100644 --- a/units/systemd-journal-upload.service.in +++ b/units/systemd-journal-upload.service.in @@ -15,7 +15,7 @@ ExecStart=@rootlibexecdir@/systemd-journal-upload \ User=systemd-journal-upload PrivateTmp=yes PrivateDevices=yes -WatchdogSec=20min +WatchdogSec=3min # If there are many split up journal files we need a lot of fds to # access them all and combine diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in index a3540c65d2..41bfde5be3 100644 --- a/units/systemd-journald.service.in +++ b/units/systemd-journald.service.in @@ -22,7 +22,7 @@ RestartSec=0 NotifyAccess=all StandardOutput=null CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE -WatchdogSec=1min +WatchdogSec=3min FileDescriptorStoreMax=1024 # Increase the default a bit in order to allow many simultaneous diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in index bfa097844f..9b13f901a3 100644 --- a/units/systemd-localed.service.in +++ b/units/systemd-localed.service.in @@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/localed ExecStart=@rootlibexecdir@/systemd-localed BusName=org.freedesktop.locale1 CapabilityBoundingSet= -WatchdogSec=1min +WatchdogSec=3min PrivateTmp=yes PrivateDevices=yes PrivateNetwork=yes diff --git a/units/systemd-logind.service.in b/units/systemd-logind.service.in index f087e99ce2..ff049134ee 100644 --- a/units/systemd-logind.service.in +++ b/units/systemd-logind.service.in @@ -24,7 +24,7 @@ Restart=always RestartSec=0 BusName=org.freedesktop.login1 CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG -WatchdogSec=1min +WatchdogSec=3min # Increase the default a bit in order to allow many simultaneous # logins since we keep one fd open per session. diff --git a/units/systemd-machine-id-commit.service.in b/units/systemd-machine-id-commit.service.in index cccbf7b626..1f3f5da0f3 100644 --- a/units/systemd-machine-id-commit.service.in +++ b/units/systemd-machine-id-commit.service.in @@ -18,5 +18,5 @@ ConditionPathIsMountPoint=/etc/machine-id [Service] Type=oneshot RemainAfterExit=yes -ExecStart=@rootlibexecdir@/systemd-machine-id-commit +ExecStart=@rootbindir@/systemd-machine-id-setup --commit TimeoutSec=30s diff --git a/units/systemd-machined.service.in b/units/systemd-machined.service.in index fb1f383cdc..3710c595ca 100644 --- a/units/systemd-machined.service.in +++ b/units/systemd-machined.service.in @@ -16,7 +16,7 @@ After=machine.slice ExecStart=@rootlibexecdir@/systemd-machined BusName=org.freedesktop.machine1 CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID -WatchdogSec=1min +WatchdogSec=3min # Note that machined cannot be placed in a mount namespace, since it # needs access to the host's mount namespace in order to implement the diff --git a/units/systemd-networkd.service.m4.in b/units/systemd-networkd.service.m4.in index 35be713ade..27d4d58962 100644 --- a/units/systemd-networkd.service.m4.in +++ b/units/systemd-networkd.service.m4.in @@ -30,7 +30,7 @@ ExecStart=@rootlibexecdir@/systemd-networkd CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER ProtectSystem=full ProtectHome=yes -WatchdogSec=1min +WatchdogSec=3min [Install] WantedBy=multi-user.target diff --git a/units/systemd-networkd.socket b/units/systemd-networkd.socket index 8cd7bab67a..9e4e9dd338 100644 --- a/units/systemd-networkd.socket +++ b/units/systemd-networkd.socket @@ -6,7 +6,7 @@ # (at your option) any later version. [Unit] -Description=networkd rtnetlink socket +Description=Network Service Netlink Socket Documentation=man:systemd-networkd.service(8) man:rtnetlink(7) ConditionCapability=CAP_NET_ADMIN DefaultDependencies=no @@ -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 6b86e0a7f7..2e79adff44 100644 --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@ -35,5 +35,11 @@ DeviceAllow=/dev/net/tun rwm DeviceAllow=/dev/pts/ptmx rw DeviceAllow=char-pts rw +# nspawn itself needs access to /dev/loop-control and /dev/loop, to +# 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/systemd-resolved.service.m4.in b/units/systemd-resolved.service.m4.in index dce5402458..c674b27ced 100644 --- a/units/systemd-resolved.service.m4.in +++ b/units/systemd-resolved.service.m4.in @@ -23,7 +23,7 @@ ExecStart=@rootlibexecdir@/systemd-resolved CapabilityBoundingSet=CAP_SETUID CAP_SETGID CAP_SETPCAP CAP_CHOWN CAP_DAC_OVERRIDE CAP_FOWNER ProtectSystem=full ProtectHome=yes -WatchdogSec=1min +WatchdogSec=3min [Install] WantedBy=multi-user.target diff --git a/units/systemd-rfkill@.service.in b/units/systemd-rfkill.service.in index e53bf5fbba..780a19b996 100644 --- a/units/systemd-rfkill@.service.in +++ b/units/systemd-rfkill.service.in @@ -6,18 +6,16 @@ # (at your option) any later version. [Unit] -Description=Load/Save RF Kill Switch Status of %I -Documentation=man:systemd-rfkill@.service(8) +Description=Load/Save RF Kill Switch Status +Documentation=man:systemd-rfkill.service(8) DefaultDependencies=no -BindsTo=sys-subsystem-rfkill-devices-%i.device RequiresMountsFor=/var/lib/systemd/rfkill +BindsTo=sys-devices-virtual-misc-rfkill.device Conflicts=shutdown.target -After=systemd-remount-fs.service -Before=sysinit.target shutdown.target +After=sys-devices-virtual-misc-rfkill.device systemd-remount-fs.service +Before=shutdown.target [Service] -Type=oneshot -RemainAfterExit=yes -ExecStart=@rootlibexecdir@/systemd-rfkill load %I -ExecStop=@rootlibexecdir@/systemd-rfkill save %I +Type=notify +ExecStart=@rootlibexecdir@/systemd-rfkill TimeoutSec=30s diff --git a/units/systemd-rfkill.socket b/units/systemd-rfkill.socket new file mode 100644 index 0000000000..20ae2f8adb --- /dev/null +++ b/units/systemd-rfkill.socket @@ -0,0 +1,19 @@ +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Load/Save RF Kill Switch Status /dev/rfkill Watch +Documentation=man:systemd-rfkill.socket(8) +DefaultDependencies=no +BindsTo=sys-devices-virtual-misc-rfkill.device +After=sys-devices-virtual-misc-rfkill.device +Conflicts=shutdown.target +Before=shutdown.target + +[Socket] +ListenSpecial=/dev/rfkill +Writable=yes diff --git a/units/systemd-timedated.service.in b/units/systemd-timedated.service.in index fe5ccb4601..0c9599db20 100644 --- a/units/systemd-timedated.service.in +++ b/units/systemd-timedated.service.in @@ -14,7 +14,7 @@ Documentation=http://www.freedesktop.org/wiki/Software/systemd/timedated ExecStart=@rootlibexecdir@/systemd-timedated BusName=org.freedesktop.timedate1 CapabilityBoundingSet=CAP_SYS_TIME -WatchdogSec=1min +WatchdogSec=3min PrivateTmp=yes ProtectSystem=yes ProtectHome=yes diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in index 8219c95a08..a856dad709 100644 --- a/units/systemd-timesyncd.service.in +++ b/units/systemd-timesyncd.service.in @@ -27,7 +27,7 @@ PrivateTmp=yes PrivateDevices=yes ProtectSystem=full ProtectHome=yes -WatchdogSec=1min +WatchdogSec=3min [Install] WantedBy=sysinit.target diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in index e7216d61f2..79f28c87c6 100644 --- a/units/systemd-udevd.service.in +++ b/units/systemd-udevd.service.in @@ -23,4 +23,4 @@ RestartSec=0 ExecStart=@rootlibexecdir@/systemd-udevd MountFlags=slave KillMode=mixed -WatchdogSec=1min +WatchdogSec=3min diff --git a/units/tmp.mount b/units/tmp.mount.m4 index 00a0d28722..6402200c62 100644 --- a/units/tmp.mount +++ b/units/tmp.mount.m4 @@ -19,3 +19,6 @@ What=tmpfs Where=/tmp Type=tmpfs Options=mode=1777,strictatime +m4_ifdef(`HAVE_SMACK', +SmackFileSystemRootLabel=* +)m4_dnl 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 |