diff options
500 files changed, 11395 insertions, 3712 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..70b6c0f139 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig configuration for systemd +# http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file, utf-8 charset +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +# match config files, set indent to spaces with width of eight +[*.{c,h}] +indent_style = space +indent_size = 8 diff --git a/.gitignore b/.gitignore index b0abc0d4e9..98eb29d657 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.a *.cache -*.html *.la *.lo *.log @@ -1,4 +1,8 @@ " 'set exrc' in ~/.vimrc will read .vimrc from the current directory +" Warning: Enabling exrc is dangerous! You can do nearly everything from a +" vimrc configuration file, including write operations and shell execution. +" You should consider setting 'set secure' as well, which is highly +" recommended! set tabstop=8 set shiftwidth=8 set expandtab diff --git a/Makefile-man.am b/Makefile-man.am index c792c89324..db0416f9d1 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -26,6 +26,7 @@ MANPAGES += \ man/os-release.5 \ man/sd-bus-errors.3 \ man/sd-daemon.3 \ + man/sd-event.3 \ man/sd-id128.3 \ man/sd-journal.3 \ man/sd_booted.3 \ @@ -47,12 +48,23 @@ MANPAGES += \ man/sd_bus_request_name.3 \ man/sd_event_add_child.3 \ man/sd_event_add_defer.3 \ + man/sd_event_add_io.3 \ man/sd_event_add_signal.3 \ man/sd_event_add_time.3 \ + man/sd_event_exit.3 \ man/sd_event_get_fd.3 \ man/sd_event_new.3 \ + man/sd_event_now.3 \ man/sd_event_run.3 \ - man/sd_event_set_name.3 \ + man/sd_event_set_watchdog.3 \ + man/sd_event_source_get_event.3 \ + man/sd_event_source_get_pending.3 \ + man/sd_event_source_set_description.3 \ + man/sd_event_source_set_enabled.3 \ + man/sd_event_source_set_prepare.3 \ + man/sd_event_source_set_priority.3 \ + man/sd_event_source_set_userdata.3 \ + man/sd_event_source_unref.3 \ man/sd_event_wait.3 \ man/sd_id128_get_machine.3 \ man/sd_id128_randomize.3 \ @@ -199,6 +211,19 @@ MANPAGES_ALIAS += \ man/SD_DEBUG.3 \ man/SD_EMERG.3 \ man/SD_ERR.3 \ + man/SD_EVENT_ARMED.3 \ + man/SD_EVENT_EXITING.3 \ + man/SD_EVENT_FINISHED.3 \ + man/SD_EVENT_INITIAL.3 \ + man/SD_EVENT_OFF.3 \ + man/SD_EVENT_ON.3 \ + man/SD_EVENT_ONESHOT.3 \ + man/SD_EVENT_PENDING.3 \ + man/SD_EVENT_PREPARING.3 \ + man/SD_EVENT_PRIORITY_IDLE.3 \ + man/SD_EVENT_PRIORITY_IMPORTANT.3 \ + man/SD_EVENT_PRIORITY_NORMAL.3 \ + man/SD_EVENT_RUNNING.3 \ man/SD_ID128_CONST_STR.3 \ man/SD_ID128_FORMAT_STR.3 \ man/SD_ID128_FORMAT_VAL.3 \ @@ -295,21 +320,41 @@ MANPAGES_ALIAS += \ man/sd_bus_ref.3 \ man/sd_bus_release_name.3 \ man/sd_bus_unref.3 \ + man/sd_event.3 \ man/sd_event_add_exit.3 \ man/sd_event_add_post.3 \ + man/sd_event_child_handler_t.3 \ man/sd_event_default.3 \ man/sd_event_dispatch.3 \ - man/sd_event_get_name.3 \ + man/sd_event_get_exit_code.3 \ + man/sd_event_get_state.3 \ + man/sd_event_get_tid.3 \ + man/sd_event_get_watchdog.3 \ + man/sd_event_handler_t.3 \ + man/sd_event_io_handler_t.3 \ man/sd_event_loop.3 \ man/sd_event_prepare.3 \ man/sd_event_ref.3 \ + man/sd_event_signal_handler_t.3 \ + man/sd_event_source.3 \ man/sd_event_source_get_child_pid.3 \ + man/sd_event_source_get_description.3 \ + man/sd_event_source_get_enabled.3 \ + man/sd_event_source_get_io_events.3 \ + man/sd_event_source_get_io_fd.3 \ + man/sd_event_source_get_io_revents.3 \ + man/sd_event_source_get_priority.3 \ man/sd_event_source_get_signal.3 \ man/sd_event_source_get_time.3 \ man/sd_event_source_get_time_accuracy.3 \ man/sd_event_source_get_time_clock.3 \ + man/sd_event_source_get_userdata.3 \ + man/sd_event_source_ref.3 \ + man/sd_event_source_set_io_events.3 \ + man/sd_event_source_set_io_fd.3 \ man/sd_event_source_set_time.3 \ man/sd_event_source_set_time_accuracy.3 \ + man/sd_event_time_handler_t.3 \ man/sd_event_unref.3 \ man/sd_id128_equal.3 \ man/sd_id128_from_string.3 \ @@ -489,6 +534,19 @@ man/SD_CRIT.3: man/sd-daemon.3 man/SD_DEBUG.3: man/sd-daemon.3 man/SD_EMERG.3: man/sd-daemon.3 man/SD_ERR.3: man/sd-daemon.3 +man/SD_EVENT_ARMED.3: man/sd_event_wait.3 +man/SD_EVENT_EXITING.3: man/sd_event_wait.3 +man/SD_EVENT_FINISHED.3: man/sd_event_wait.3 +man/SD_EVENT_INITIAL.3: man/sd_event_wait.3 +man/SD_EVENT_OFF.3: man/sd_event_source_set_enabled.3 +man/SD_EVENT_ON.3: man/sd_event_source_set_enabled.3 +man/SD_EVENT_ONESHOT.3: man/sd_event_source_set_enabled.3 +man/SD_EVENT_PENDING.3: man/sd_event_wait.3 +man/SD_EVENT_PREPARING.3: man/sd_event_wait.3 +man/SD_EVENT_PRIORITY_IDLE.3: man/sd_event_source_set_priority.3 +man/SD_EVENT_PRIORITY_IMPORTANT.3: man/sd_event_source_set_priority.3 +man/SD_EVENT_PRIORITY_NORMAL.3: man/sd_event_source_set_priority.3 +man/SD_EVENT_RUNNING.3: man/sd_event_wait.3 man/SD_ID128_CONST_STR.3: man/sd-id128.3 man/SD_ID128_FORMAT_STR.3: man/sd-id128.3 man/SD_ID128_FORMAT_VAL.3: man/sd-id128.3 @@ -585,21 +643,41 @@ 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 +man/sd_event.3: man/sd_event_new.3 man/sd_event_add_exit.3: man/sd_event_add_defer.3 man/sd_event_add_post.3: man/sd_event_add_defer.3 +man/sd_event_child_handler_t.3: man/sd_event_add_child.3 man/sd_event_default.3: man/sd_event_new.3 man/sd_event_dispatch.3: man/sd_event_wait.3 -man/sd_event_get_name.3: man/sd_event_set_name.3 +man/sd_event_get_exit_code.3: man/sd_event_exit.3 +man/sd_event_get_state.3: man/sd_event_wait.3 +man/sd_event_get_tid.3: man/sd_event_new.3 +man/sd_event_get_watchdog.3: man/sd_event_set_watchdog.3 +man/sd_event_handler_t.3: man/sd_event_add_defer.3 +man/sd_event_io_handler_t.3: man/sd_event_add_io.3 man/sd_event_loop.3: man/sd_event_run.3 man/sd_event_prepare.3: man/sd_event_wait.3 man/sd_event_ref.3: man/sd_event_new.3 +man/sd_event_signal_handler_t.3: man/sd_event_add_signal.3 +man/sd_event_source.3: man/sd_event_add_io.3 man/sd_event_source_get_child_pid.3: man/sd_event_add_child.3 +man/sd_event_source_get_description.3: man/sd_event_source_set_description.3 +man/sd_event_source_get_enabled.3: man/sd_event_source_set_enabled.3 +man/sd_event_source_get_io_events.3: man/sd_event_add_io.3 +man/sd_event_source_get_io_fd.3: man/sd_event_add_io.3 +man/sd_event_source_get_io_revents.3: man/sd_event_add_io.3 +man/sd_event_source_get_priority.3: man/sd_event_source_set_priority.3 man/sd_event_source_get_signal.3: man/sd_event_add_signal.3 man/sd_event_source_get_time.3: man/sd_event_add_time.3 man/sd_event_source_get_time_accuracy.3: man/sd_event_add_time.3 man/sd_event_source_get_time_clock.3: man/sd_event_add_time.3 +man/sd_event_source_get_userdata.3: man/sd_event_source_set_userdata.3 +man/sd_event_source_ref.3: man/sd_event_source_unref.3 +man/sd_event_source_set_io_events.3: man/sd_event_add_io.3 +man/sd_event_source_set_io_fd.3: man/sd_event_add_io.3 man/sd_event_source_set_time.3: man/sd_event_add_time.3 man/sd_event_source_set_time_accuracy.3: man/sd_event_add_time.3 +man/sd_event_time_handler_t.3: man/sd_event_add_time.3 man/sd_event_unref.3: man/sd_event_new.3 man/sd_id128_equal.3: man/sd-id128.3 man/sd_id128_from_string.3: man/sd_id128_to_string.3 @@ -857,6 +935,45 @@ man/SD_EMERG.html: man/sd-daemon.html man/SD_ERR.html: man/sd-daemon.html $(html-alias) +man/SD_EVENT_ARMED.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_EXITING.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_FINISHED.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_INITIAL.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_OFF.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/SD_EVENT_ON.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/SD_EVENT_ONESHOT.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/SD_EVENT_PENDING.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_PREPARING.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_PRIORITY_IDLE.html: man/sd_event_source_set_priority.html + $(html-alias) + +man/SD_EVENT_PRIORITY_IMPORTANT.html: man/sd_event_source_set_priority.html + $(html-alias) + +man/SD_EVENT_PRIORITY_NORMAL.html: man/sd_event_source_set_priority.html + $(html-alias) + +man/SD_EVENT_RUNNING.html: man/sd_event_wait.html + $(html-alias) + man/SD_ID128_CONST_STR.html: man/sd-id128.html $(html-alias) @@ -1145,19 +1262,40 @@ man/sd_bus_release_name.html: man/sd_bus_request_name.html man/sd_bus_unref.html: man/sd_bus_new.html $(html-alias) +man/sd_event.html: man/sd_event_new.html + $(html-alias) + man/sd_event_add_exit.html: man/sd_event_add_defer.html $(html-alias) man/sd_event_add_post.html: man/sd_event_add_defer.html $(html-alias) +man/sd_event_child_handler_t.html: man/sd_event_add_child.html + $(html-alias) + man/sd_event_default.html: man/sd_event_new.html $(html-alias) man/sd_event_dispatch.html: man/sd_event_wait.html $(html-alias) -man/sd_event_get_name.html: man/sd_event_set_name.html +man/sd_event_get_exit_code.html: man/sd_event_exit.html + $(html-alias) + +man/sd_event_get_state.html: man/sd_event_wait.html + $(html-alias) + +man/sd_event_get_tid.html: man/sd_event_new.html + $(html-alias) + +man/sd_event_get_watchdog.html: man/sd_event_set_watchdog.html + $(html-alias) + +man/sd_event_handler_t.html: man/sd_event_add_defer.html + $(html-alias) + +man/sd_event_io_handler_t.html: man/sd_event_add_io.html $(html-alias) man/sd_event_loop.html: man/sd_event_run.html @@ -1169,9 +1307,33 @@ man/sd_event_prepare.html: man/sd_event_wait.html man/sd_event_ref.html: man/sd_event_new.html $(html-alias) +man/sd_event_signal_handler_t.html: man/sd_event_add_signal.html + $(html-alias) + +man/sd_event_source.html: man/sd_event_add_io.html + $(html-alias) + man/sd_event_source_get_child_pid.html: man/sd_event_add_child.html $(html-alias) +man/sd_event_source_get_description.html: man/sd_event_source_set_description.html + $(html-alias) + +man/sd_event_source_get_enabled.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/sd_event_source_get_io_events.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_get_io_fd.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_get_io_revents.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_get_priority.html: man/sd_event_source_set_priority.html + $(html-alias) + man/sd_event_source_get_signal.html: man/sd_event_add_signal.html $(html-alias) @@ -1184,12 +1346,27 @@ man/sd_event_source_get_time_accuracy.html: man/sd_event_add_time.html man/sd_event_source_get_time_clock.html: man/sd_event_add_time.html $(html-alias) +man/sd_event_source_get_userdata.html: man/sd_event_source_set_userdata.html + $(html-alias) + +man/sd_event_source_ref.html: man/sd_event_source_unref.html + $(html-alias) + +man/sd_event_source_set_io_events.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_set_io_fd.html: man/sd_event_add_io.html + $(html-alias) + man/sd_event_source_set_time.html: man/sd_event_add_time.html $(html-alias) man/sd_event_source_set_time_accuracy.html: man/sd_event_add_time.html $(html-alias) +man/sd_event_time_handler_t.html: man/sd_event_add_time.html + $(html-alias) + man/sd_event_unref.html: man/sd_event_new.html $(html-alias) @@ -2264,6 +2441,7 @@ EXTRA_DIST += \ man/runlevel.xml \ man/sd-bus-errors.xml \ man/sd-daemon.xml \ + man/sd-event.xml \ man/sd-id128.xml \ man/sd-journal.xml \ man/sd-login.xml \ @@ -2286,12 +2464,23 @@ EXTRA_DIST += \ man/sd_bus_request_name.xml \ man/sd_event_add_child.xml \ man/sd_event_add_defer.xml \ + man/sd_event_add_io.xml \ man/sd_event_add_signal.xml \ man/sd_event_add_time.xml \ + man/sd_event_exit.xml \ man/sd_event_get_fd.xml \ man/sd_event_new.xml \ + man/sd_event_now.xml \ man/sd_event_run.xml \ - man/sd_event_set_name.xml \ + man/sd_event_set_watchdog.xml \ + man/sd_event_source_get_event.xml \ + man/sd_event_source_get_pending.xml \ + man/sd_event_source_set_description.xml \ + man/sd_event_source_set_enabled.xml \ + man/sd_event_source_set_prepare.xml \ + man/sd_event_source_set_priority.xml \ + man/sd_event_source_set_userdata.xml \ + man/sd_event_source_unref.xml \ man/sd_event_wait.xml \ man/sd_get_seats.xml \ man/sd_id128_get_machine.xml \ diff --git a/Makefile.am b/Makefile.am index 1a5857263b..6597d305d1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,9 +42,9 @@ LIBUDEV_CURRENT=7 LIBUDEV_REVISION=4 LIBUDEV_AGE=6 -LIBSYSTEMD_CURRENT=12 +LIBSYSTEMD_CURRENT=13 LIBSYSTEMD_REVISION=0 -LIBSYSTEMD_AGE=12 +LIBSYSTEMD_AGE=13 # The following four libraries only exist for compatibility reasons, # their version info should not be bumped anymore @@ -426,6 +426,7 @@ dist_bashcompletion_DATA = \ shell-completion/bash/systemd-delta \ shell-completion/bash/systemd-detect-virt \ shell-completion/bash/systemd-nspawn \ + shell-completion/bash/systemd-path \ shell-completion/bash/systemd-run \ shell-completion/bash/udevadm \ shell-completion/bash/kernel-install @@ -660,6 +661,7 @@ EXTRA_DIST += \ README.md \ autogen.sh \ .dir-locals.el \ + .editorconfig \ .vimrc \ .ycm_extra_conf.py \ .travis.yml \ @@ -1399,7 +1401,8 @@ nodist_rpmmacros_DATA = \ EXTRA_DIST += \ src/core/systemd.pc.in \ - src/core/macros.systemd.in + src/core/macros.systemd.in \ + src/core/triggers.systemd.in # ------------------------------------------------------------------------------ @@ -5137,6 +5140,8 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-manager.h \ src/resolve/resolved-conf.c \ src/resolve/resolved-conf.h \ + src/resolve/resolved-resolv-conf.c \ + src/resolve/resolved-resolv-conf.h \ src/resolve/resolved-bus.c \ src/resolve/resolved-bus.h \ src/resolve/resolved-link.h \ @@ -5160,6 +5165,8 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-dns-scope.c \ src/resolve/resolved-dns-server.h \ src/resolve/resolved-dns-server.c \ + src/resolve/resolved-dns-search-domain.h \ + src/resolve/resolved-dns-search-domain.c \ src/resolve/resolved-dns-cache.h \ src/resolve/resolved-dns-cache.c \ src/resolve/resolved-dns-zone.h \ @@ -5368,6 +5375,11 @@ networkctl_LDADD = \ libshared.la \ libsystemd-network.la +if ENABLE_BASH_COMPLETION +dist_bashcompletion_DATA += \ + shell-completion/bash/networkctl +endif + test_network_SOURCES = \ src/network/test-network.c @@ -5668,6 +5680,9 @@ EXTRA_DIST += \ test/TEST-03-JOBS/Makefile \ test/TEST-03-JOBS/test-jobs.sh \ test/TEST-03-JOBS/test.sh \ + test/TEST-04-JOURNAL/Makefile \ + test/TEST-04-JOURNAL/test-journal.sh \ + test/TEST-04-JOURNAL/test.sh \ test/test-functions EXTRA_DIST += \ @@ -5880,7 +5895,7 @@ sysctl.d/%: sysctl.d/%.in %.conf: %.conf.in $(SED_PROCESS) -src/core/macros.%: src/core/macros.%.in +src/core/%.systemd: src/core/%.systemd.in $(SED_PROCESS) src/%.policy.in: src/%.policy.in.in @@ -16,6 +16,10 @@ CHANGES WITH 228: possible to pass in a set of file descriptors to use as STDIN/STDOUT/STDERR for the invoked process. + * Slice units may now be created transiently via the bus APIs, + similar to the way service and scope units may already be + created transiently. + * Wherever systemd expects a calendar timestamp specification (like in journalctl's --since= and --until= switches) UTC timestamps are now supported. Timestamps suffixed with "UTC" @@ -34,6 +38,13 @@ CHANGES WITH 228: hierarchy when used on a btrfs file system with quota enabled. + * tmpfiles' "v", "q" and "Q" will now create a plain directory + instead of a subvolume (even on a btrfs file system) if the + root directory is a plain directory, and not a + subvolume. This should simplify things with certain chroot() + environments which are not aware of the concept of btrfs + subvolumes. + * systemd-detect-virt gained a new --chroot switch to detect whether execution takes place in a chroot() environment. @@ -46,6 +57,28 @@ CHANGES WITH 228: limit settings understand the usual min, h, day, ... suffixes now. + * There's a new system.conf setting DefaultTasksMax= to + control the default TasksMax= setting for services and + scopes running on the system. (TasksMax= is the primary + setting that exposes the "pids" cgroup controller on systemd + and was introduced in the previous systemd release.) The + setting now defaults to 512, which means services that are + not explicitly configured otherwise will only be able to + create 512 processes or threads at maximum, from this + version on. Note that this means that thread- or + process-heavy services might need to be reconfigured to set + TasksMax= to a higher value. It is sufficient to set + TasksMax= in these specific unit files to a higher value, or + even "infinity". Similar, there's now a logind.conf setting + UserTasksMax= that defaults to 4096 and limits the total + number of processes or tasks each user may own + concurrently. nspawn containers also have the TasksMax= + value set by default now, to 8192. Note that all of this + only has an effect if the "pids" cgroup controller is + enabled in the kernel. The general benefit of these changes + should be a more robust and safer system, that provides a + certain amount of per-service fork() bomb protection. + * systemd-nspawn gained the new --network-veth-extra= switch to define additional and arbitrarily-named virtual Ethernet links between the host and the container. @@ -55,6 +88,14 @@ CHANGES WITH 228: from PID1's environment block into the environment block of the service. + * Timer units gained support for a new RemainAfterElapse= + setting which takes a boolean argument. It defaults on on, + exposing behaviour unchanged to previous releases. If set to + off, timer units are unloaded after they elapsed if they + cannot elapse again. This is particularly useful for + transient timer units, which shall not stay around longer + than until they first elapse. + * systemd will now bump the net.unix.max_dgram_qlen to 512 by default now (the kernel default is 16). This is beneficial for avoiding blocking on AF_UNIX/SOCK_DGRAM sockets since it @@ -142,19 +183,20 @@ CHANGES WITH 228: Contributions from: Andrew Jones, Beniamino Galvani, Boyuan Yang, Daniel Machon, Daniel Mack, David Herrmann, David Reynolds, David Strauss, Dongsu Park, Evgeny Vereshchagin, - Filipe Brandenburger, Franck Bui, Hristo Venev, Iago López - Galeiras, Jan Engelhardt, Jan Janssen, Jan Synacek, Jesus - Ornelas Aguayo, Karel Zak, kayrus, Kay Sievers, Lennart - Poettering, Mantas Mikulėnas, Marcel Holtmann, Marcin Bachry, - Marcos Alano, Marcos Mello, Mark Theunissen, Martin Pitt, - Michael Marineau, Michael Olbrich, Michal Schmidt, Michal - Sekletar, Mirco Tischler, Nick Owens, Nicolas Cornu, Patrik - Flykt, Peter Hutterer, reverendhomer, Ronny Chevalier, - Sangjung Woo, Seong-ho Cho, Shawn Landden, Susant Sahani, - Thomas Haller, Thomas Hindoe Paaboel Andersen, Tom Gundersen, - Torstein Husebø, Vito Caputo, Zbigniew Jędrzejewski-Szmek + Felipe Sateler, Filipe Brandenburger, Franck Bui, Hristo + Venev, Iago López Galeiras, Jan Engelhardt, Jan Janssen, Jan + Synacek, Jesus Ornelas Aguayo, Karel Zak, kayrus, Kay Sievers, + Lennart Poettering, Liu Yuan Yuan, Mantas Mikulėnas, Marcel + Holtmann, Marcin Bachry, Marcos Alano, Marcos Mello, Mark + Theunissen, Martin Pitt, Michael Marineau, Michael Olbrich, + Michal Schmidt, Michal Sekletar, Mirco Tischler, Nick Owens, + Nicolas Cornu, Patrik Flykt, Peter Hutterer, reverendhomer, + Ronny Chevalier, Sangjung Woo, Seong-ho Cho, Shawn Landden, + Susant Sahani, Thomas Haller, Thomas Hindoe Paaboel Andersen, + Tom Gundersen, Torstein Husebø, Vito Caputo, Zbigniew + Jędrzejewski-Szmek - -- Berlin, 2015-11-XX + -- Berlin, 2015-11-18 CHANGES WITH 227: @@ -48,22 +48,14 @@ Features: * push CPUAffinity= also into the "cpuset" cgroup controller (only after the cpuset controller got ported to the unified hierarchy) -* add a concept of RemainAfterExit= to scope units - * add a new command "systemctl revert" or so, that removes all dropin snippets in /run and /etc, and all unit files with counterparts in /usr, and thus undoes what "systemctl set-property" and "systemctl edit" create. Maybe even add "systemctl revert -a" to do this for all units. -* sd-event: maybe add support for inotify events - * PID 1 should send out sd_notify("WATCHDOG=1") messages (for usage in the --user mode, and when run via nspawn) -* nspawn should send out sd_notify("WATCHDOG=1") messages - -* nspawn should optionally support receiving WATCHDOG=1 messages from its payload PID 1... - * consider throwing a warning if a service declares it wants to be "Before=" a .device unit. * "systemctl edit" should know a mode to create a new unit file @@ -73,62 +65,15 @@ Features: prefixed with /sys generally special. http://lists.freedesktop.org/archives/systemd-devel/2015-June/032962.html -* nspawn: fix logic always print a final newline on output. - https://github.com/systemd/systemd/pull/272#issuecomment-113153176 - * man: document that unless you use StandardError=null the shell >/dev/stderr won't work in shell scripts in services * "systemctl daemon-reload" should result in /etc/systemd/system.conf being reloaded by systemd * install: include generator dirs in unit file search paths -* logind: follow PropertiesChanged state more closely, to deal with quick logouts and relogins - -* invent a better systemd-run scheme for naming scopes, that works with remoting - -* add journalctl -H that talks via ssh to a remote peer and passes through binary logs data - -* change journalctl -M to acquire fd to journal directory via machined, and then operate on that via openat() instead of absolute paths - -* add a version of --merge which also merges /var/log/journal/remote - -* log accumulated resource usage after each service invocation - -* nspawn: a nice way to boot up without machine id set, so that it is set at boot automatically for supporting --ephemeral. Maybe hash the host machine id together with the machine name to generate the machine id for the container - -* logind: rename session scope so that it includes the UID. THat way - the session scope can be arranged freely in slices and we don't have - make assumptions about their slice anymore. - -* journalctl: -m should access container journals directly by enumerating them via machined, and also watch containers coming and going. Benefit: nspawn --ephemeral would start working nicely with the journal. - -* nspawn: don't copy /etc/resolv.conf from host into container unless we are in shared-network mode - -* nspawn: optionally automatically add FORWARD rules to iptables whenever nspawn is running, remove them when shut down. - -* importd: generate a nice warning if mkfs.btrfs is missing - -* nspawn: add a logic for cleaning up read-only, hidden container images in /var/lib/machines that are not ancestors of any non-hidden containers - -* nspawn: Improve error message when --bind= is used on a non-existing source directory - -* nspawn: maybe make copying of /etc/resolv.conf optional, and skip it if --read-only is used - -* man: document how update dkr images works with machinectl - http://lists.freedesktop.org/archives/systemd-devel/2015-February/028630.html - -* nspawn: as soon as networkd has a bus interface, hook up --network-interface=, --network-bridge= with networkd, to trigger netdev creation should an interface be missing - * rework C11 utf8.[ch] to use char32_t instead of uint32_t when referring to unicode chars, to make things more expressive. -* "machinectl migrate" or similar to copy a container from or to a - difference host, via ssh - -* tmpfiles: creating new directories/subvolumes/fifos/device nodes - should not follow symlinks. None of the other adjustment or creation - calls follow symlinks. - * fstab-generator: default to tmpfs-as-root if only usr= is specified on the kernel cmdline * docs: bring http://www.freedesktop.org/wiki/Software/systemd/MyServiceCantGetRealtime up to date @@ -145,84 +90,21 @@ Features: * Maybe add support for the equivalent of "ethtool advertise" to .link files? http://lists.freedesktop.org/archives/systemd-devel/2015-April/030112.html -* .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC - -* When logging about multiple units (stopping BoundTo units, conflicts, etc.), - log both units as UNIT=, so that journalctl -u triggers on both. - -* to allow "linking" of nspawn containers, extend --network-bridge= so - that it can dynamically create bridge interfaces that are refcounted - by the containers on them. For each group of containers to link together - -* journalctl --verify: don't show files that are currently being - written to as FAIL, but instead show that their are being written - to. - -* assign MESSAGE_ID to log messages about failed services - -* coredump: make the handler check /proc/$PID/rlimits for RLIMIT_CORE, - and supress coredump if turned off. Then change RLIMIT_CORE to - infinity by default for all services. This then allows per-service - control of coredumping. - -* generate better errors when people try to set transient properties - that are not supported... - http://lists.freedesktop.org/archives/systemd-devel/2015-February/028076.html - -* maybe introduce WantsMountsFor=? Usecase: - http://lists.freedesktop.org/archives/systemd-devel/2015-January/027729.html - * 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 picked up by systemd unless they contain a medium. This would mirror the behaviour we already have for CD drives. -* nspawn: emulate /dev/kmsg using CUSE and turn off the syslog syscall - with seccomp. That should provide us with a useful log buffer that - systemd can log to during early boot, and disconnect container logs - from the kernel's logs. - * networkd/udev: implement SR_IOV configuration in .link files: http://lists.freedesktop.org/archives/systemd-devel/2015-January/027451.html -* 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 - -* Set NoNewPrivileges= on all of our own services, where that makes sense - * Rework systemctl's GetAll property parsing to use the generic bus_map_all_properties() API -* rework journald sigbus stuff to use mutex - -* import-dkr: support tarsum checksum verification, if it becomes reality one day... - -* import-dkr: convert json bits to nspawn configuration - -* core/cgroup: support net_cls modules, and support automatically allocating class ids, then add support for making firewall changes depending on it, to implement a per-service firewall - -* introduce systemd-nspawn-ephemeral@.service, and hook it into "machinectl start" with a new --ephemeral switch - -* "machinectl status" should also show internal logs of the container in question - -* "machinectl list-images" should show os-release data, as well as machine-info data (including deployment level) +* implement a per-service firewall based on net_cls * Port various tools to make use of verbs.[ch], where applicable -* "machinectl history" - -* "machinectl diff" - -* "machinectl commit" that takes a writable snapshot of a tree, invokes a shell in it, and marks it read-only after use - -* systemd-nspawn -x should support ephemeral instances of gpt images - * hostnamectl: show root image uuid * sysfs set api in libudev is not const @@ -235,15 +117,6 @@ Features: ensure deterministic behaviour if two unit files conflict (like DMs do, for example) -* resolved should optionally register additional per-interface LLMNR - names, so that for the container case we can establish the same name - (maybe "host") for referencing the server, everywhere. - -* systemd-journal-upload (or a new, related tool): allow pushing out - journal messages onto the network in BSD syslog protocol, - continuously. Default to some link-local IP mcast group, to make this - useful as a one-stop debugging tool. - * synchronize console access with BSD locks: http://lists.freedesktop.org/archives/systemd-devel/2014-October/024582.html @@ -263,12 +136,8 @@ Features: * firstboot: make it useful to be run immediately after yum --installroot to set up a machine. (most specifically, make --copy-root-password work even if /etc/passwd already exists -* timesyncd + resolved: add ugly bus calls to set NTP and DNS servers per-interface, for usage by NM - * add infrastructure to allocate dynamic/transient users and UID ranges, for use in user-namespaced containers, per-seat gdm login screens and gdm guest sessions -* machined: add an API so that libvirt-lxc can inform us about network interfaces being removed or added to an existing machine - * maybe add support for specifier expansion in user.conf, specifically DefaultEnvironment= * introduce systemd-timesync-wait.service or so to sync on an NTP fix? @@ -277,8 +146,6 @@ Features: * consider showing the unit names during boot up in the status output, not just the unit descriptions -* dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from? - * maybe allow timer units with an empty Units= setting, so that they can be used for resuming the system but nothing else. @@ -286,14 +153,8 @@ Features: * maybe provide an API to allow migration of foreign PIDs into existing scopes. -* maybe support a new very "soft" reboot mode, that simply kills all processes, disassembles everything, flushes /run and sysvipc, and then reexecs systemd again - -* man: document that corrupted journal files is nothing to act on - * man: maybe use the word "inspect" rather than "introspect"? -* "machinectl list" should probably show columns for OS version and IP addresses - * systemctl: if some operation fails, show log output? * systemctl edit: @@ -301,10 +162,10 @@ Features: - use equvalent of cat() to insert existing config as a comment, prepended with #. Upon editor exit, lines with one # are removed, lines with two # are left with one #, etc. -* refcounting in sd-resolve is borked - * exponential backoff in timesyncd and resolved when we cannot reach a server +* timesyncd + resolved: add ugly bus calls to set NTP and DNS servers per-interface, for usage by NM + * extract_many_words() should probably be used by a lot of code that currently uses FOREACH_WORD and friends. For example, most conf parsing callbacks should use it. @@ -317,41 +178,23 @@ Features: * add systemd.abort_on_kill or some other such flag to send SIGABRT instead of SIGKILL (throughout the codebase, not only PID1) -* networkd: - - add LLDP client side support - - the DHCP lease data (such as NTP/DNS) is still made available when - a carrier is lost on a link. It should be removed instantly. - - expose in the API the following bits: - - option 15, domain name and/or option 119, search list - - option 12, host name and/or option 81, fqdn - - option 123, 144, geolocation - - option 252, configure http proxy (PAC/wpad) - - provide a way to define a per-network interface default metric value - for all routes to it. possibly a second default for DHCP routes. - - allow Name= to be specified repeatedly in the [Match] section. Maybe also - support Name=foo*|bar*|baz ? - - duplicate address check for static IPs (like ARPCHECK in network-scripts) - - allow DUID/IAID to be customized, see issue #394. - - support configuration option for TSO (tcp segmentation offload) - - networkd: whenever uplink info changes, make DHCP server send out FORCERENEW - * resolved: - put networkd events and rtnl events at a higher priority, so that we always process them before we process client requests - DNSSEC - add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)? - - DNS - - search paths - mDNS/DNS-SD + - mDNS RR resolving + - service registration + - service/domain/types browsing - avahi compat - DNS-SD service registration from socket units - - edns0 - - dname: Not necessary for plain DNS as synthesized cname is handed out instead if we do not - announce dname support. However, for DNSSEC it is necessary as the synthesized cname - will not be signed. - - cname on PTR (?) + - resolved should optionally register additional per-interface LLMNR + names, so that for the container case we can establish the same name + (maybe "host") for referencing the server, everywhere. + - add API so NM can push DNS server info into resolved -* Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely +* refcounting in sd-resolve is borked * Add a new verb "systemctl top" @@ -363,8 +206,6 @@ Features: * generator that automatically discovers btrfs subvolumes, identifies their purpose based on some xattr on them. -* timer units: actually add extra delays to timer units with high AccuracySec values, don't start them already when we are awake... - * a way for container managers to turn off getty starting via $container_headless= or so... * figure out a nice way how we can let the admin know what child/sibling unit causes cgroup membership for a specific unit @@ -376,14 +217,8 @@ Features: * Run most system services with cgroupfs read-only and procfs with a more secure mode (doesn't work, since the hidepid= option is per-pid-namespace, not per-mount) -* sd-event: generate a failure of a default event loop is executed out-of-thread - * add bus api to query unit file's X fields. -* consider adding RuntimeDirectoryUser= + RuntimeDirectoryGroup= - -* sd-event: define more intervals where we will shift wakeup intervals around in, 1h, 6h, 24h, ... - * gpt-auto-generator: - Support LUKS for root devices - Define new partition type for encrypted swap? Support probed LUKS for encrypted swap? @@ -434,8 +269,6 @@ Features: * when we detect low battery and no AC on boot, show pretty splash and refuse boot -* machined, localed: when we try to kill an empty cgroup, generate an ESRCH error over the bus - * libsystemd-journal, libsystemd-login, libudev: add calls to easily attach these objects to sd-event event loops * be more careful what we export on the bus as (usec_t) 0 and (usec_t) -1 @@ -493,6 +326,9 @@ Features: * sd-event - allow multiple signal handlers per signal? - document chaining of signal handler for SIGCHLD and child handlers + - define more intervals where we will shift wakeup intervals around in, 1h, 6h, 24h, ... + - generate a failure of a default event loop is executed out-of-thread + - maybe add support for inotify events * in the final killing spree, detect processes from the root directory, and complain loudly if they have argv[0][0] == '@' set. @@ -537,14 +373,10 @@ Features: * systemd-inhibit: make taking delay locks useful: support sending SIGINT or SIGTERM on PrepareForSleep() -* journal-or-kmsg is currently broken? See reverted commit 4a01181e460686d8b4a543b1dfa7f77c9e3c5ab8. - * remove any syslog support from log.c -- we probably cannot do this before split-off udev is gone for good * shutdown logging: store to EFI var, and store to USB stick? -* write UI tool that pops up emergency messages from the journal as notification - * think about window-manager-run-as-user-service problem: exit 0 → activate shutdown.target; exit != 0 → restart service * merge unit_kill_common() and unit_kill_context() @@ -587,6 +419,12 @@ Features: probably reduce the capability set it retains substantially. (we need CAP_SYS_ADMIN for drmSetMaster(), so maybe not worth it) - expose orientation sensors and tablet mode through logind + - maybe allow configuration of the StopTimeout for session scopes + - rename session scope so that it includes the UID. THat way + the session scope can be arranged freely in slices and we don't have + make assumptions about their slice anymore. + - follow PropertiesChanged state more closely, to deal with quick logouts and + relogins * exec: when deinitializating a tty device fix the perms and group, too, not only when initializing. Set access mode/gid to 0620/tty. @@ -641,6 +479,32 @@ Features: lazily. Encode just enough information in the file name, so that we do not have to open it to know that it is not interesting for us, for the most common operations. + - journal-or-kmsg is currently broken? See reverted + commit 4a01181e460686d8b4a543b1dfa7f77c9e3c5ab8. + - man: document that corrupted journal files is nothing to act on + - systemd-journal-upload (or a new, related tool): allow pushing out + journal messages onto the network in BSD syslog protocol, + continuously. Default to some link-local IP mcast group, to make this + useful as a one-stop debugging tool. + - rework journald sigbus stuff to use mutex + - 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. + - journalctl --verify: don't show files that are currently being + written to as FAIL, but instead show that their are being written to. + - add journalctl -H that talks via ssh to a remote peer and passes through + binary logs data + - change journalctl -M to acquire fd to journal directory via machined, and + then operate on that via openat() instead of absolute paths + - add a version of --merge which also merges /var/log/journal/remote + - log accumulated resource usage after each service invocation + - journalctl: -m should access container journals directly by enumerating + them via machined, and also watch containers coming and going. + Benefit: nspawn --ephemeral would start working nicely with the journal. + - assign MESSAGE_ID to log messages about failed services * document: - document that deps in [Unit] sections ignore Alias= fields in @@ -685,8 +549,6 @@ Features: * add libsystemd-password or so to query passwords during boot using the password agent logic -* If we show an error about a unit (such as not showing up) and it has no Description string, then show a description string generated form the reverse of unit_name_mangle(). - * clean up date formatting and parsing so that all absolute/relative timestamps we format can also be parsed * on shutdown: move utmp, wall, audit logic all into PID 1 (or logind?), get rid of systemd-update-utmp-runlevel @@ -699,7 +561,62 @@ Features: * currently x-systemd.timeout is lost in the initrd, since crypttab is copied into dracut, but fstab is not * nspawn: - - refuses to boot containers without /etc/machine-id (OK?), and with empty /etc/machine-id (not OK). + - to allow "linking" of nspawn containers, extend --network-bridge= so + that it can dynamically create bridge interfaces that are refcounted + by the containers on them. For each group of containers to link together + - refuses to boot containers without /etc/machine-id (OK?), and with empty + /etc/machine-id (not OK). + - nspawn -x should support ephemeral instances of gpt images + - emulate /dev/kmsg using CUSE and turn off the syslog syscall + with seccomp. That should provide us with a useful log buffer that + systemd can log to during early boot, and disconnect container logs + from the kernel's logs. + - as soon as networkd has a bus interface, hook up --network-interface=, + --network-bridge= with networkd, to trigger netdev creation should an + interface be missing + - don't copy /etc/resolv.conf from host into container unless we are in + shared-network mode + - a nice way to boot up without machine id set, so that it is set at boot + automatically for supporting --ephemeral. Maybe hash the host machine id + together with the machine name to generate the machine id for the container + - fix logic always print a final newline on output. + https://github.com/systemd/systemd/pull/272#issuecomment-113153176 + - should optionally support receiving WATCHDOG=1 messages from its payload + PID 1... + - should send out sd_notify("WATCHDOG=1") messages + - optionally automatically add FORWARD rules to iptables whenever nspawn is + running, remove them when shut down. + - add a logic for cleaning up read-only, hidden container images in + /var/lib/machines that are not ancestors of any non-hidden containers + - Improve error message when --bind= is used on a non-existing source + directory + - maybe make copying of /etc/resolv.conf optional, and skip it if --read-only + is used + +* machined: + - "machinectl list" should probably show columns for OS version and IP + addresses + - add an API so that libvirt-lxc can inform us about network interfaces being + removed or added to an existing machine + - "machinectl migrate" or similar to copy a container from or to a + difference host, via ssh + - man: document how update dkr images works with machinectl + http://lists.freedesktop.org/archives/systemd-devel/2015-February/028630.html + - introduce systemd-nspawn-ephemeral@.service, and hook it into + "machinectl start" with a new --ephemeral switch + - "machinectl status" should also show internal logs of the container in + question + - "machinectl list-images" should show os-release data, as well as + machine-info data (including deployment level) + - "machinectl history" + - "machinectl diff" + - "machinectl commit" that takes a writable snapshot of a tree, invokes a + shell in it, and marks it read-only after use + +* importd: + - dkr: support tarsum checksum verification, if it becomes reality one day... + - dkr: convert json bits to nspawn configuration + - generate a nice warning if mkfs.btrfs is missing * cryptsetup: - cryptsetup-generator: allow specification of passwords in crypttab itself @@ -710,40 +627,16 @@ Features: * hw watchdog: optionally try to use the preset watchdog timeout instead of always overriding it https://bugs.freedesktop.org/show_bug.cgi?id=54712 -* after deserializing sockets in socket.c we should reapply sockopts and things - -* make timer units go away after they elapsed - -* move PID 1 segfaults to /var/lib/systemd/coredump? - * create /sbin/init symlinks from the build system -* allow writing multiple conditions in unit files on one line - * MountFlags=shared acts as MountFlags=slave right now. -* drop PID 1 reloading, only do reexecing (difficult: Reload() - currently is properly synchronous, Reexec() is weird, because we - cannot delay the response properly until we are back, so instead of - being properly synchronous we just keep open the fd and close it - when done. That means clients do not get a successful method reply, - but much rather a disconnect on success. - * properly handle loop back mounts via fstab, especially regards to fsck/passno * initialize the hostname from the fs label of /, if /etc/hostname does not exist? * rename "userspace" to "core-os" -* load-fragment: when loading a unit file via a chain of symlinks - verify that it is not masked via any of the names traversed. - -* introduce Type=pid-file - -* when breaking cycles drop sysv services first, then services from /run, then from /etc, then from /usr - -* ExecOnFailure=/usr/bin/foo - * udev: - move to LGPL - kill scsi_id @@ -752,13 +645,17 @@ Features: * when a service has the same env var set twice we actually store it twice and return that in systemctl show -p... We should only show the last setting -* introduce mix of BindTo and Requisite - * There's currently no way to cancel fsck (used to be possible via C-c or c on the console) * add option to sockets to avoid activation. Instead just drop packets/connections, see http://cyberelk.net/tim/2012/02/15/portreserve-systemd-solution/ -* save coredump in Windows/Mozilla minidump format +* coredump: + - save coredump in Windows/Mozilla minidump format + - move PID 1 segfaults to /var/lib/systemd/coredump? + - make the handler check /proc/$PID/rlimits for RLIMIT_CORE, + and supress coredump if turned off. Then change RLIMIT_CORE to + infinity by default for all services. This then allows per-service + control of coredumping. * support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting) @@ -767,31 +664,16 @@ Features: * be able to specify a forced restart of service A where service B depends on, in case B needs to be auto-respawned? -* when a bus name of a service disappears from the bus make sure to queue further activation requests - * tmpfiles: - apply "x" on "D" too (see patch from William Douglas) - replace F with f+. - instead of ignoring unknown fields, reject them. - -* for services: do not set $HOME in services unless requested - -* hide PAM options in fragment parser when compile time disabled - -* when we automatically restart a service, ensure we restart its rdeps, too. - -* allow Type=simple with PIDFile= - https://bugzilla.redhat.com/show_bug.cgi?id=723942 - -* move PAM code into its own binary - -* implement Register= switch in .socket units to enable registration - in Avahi, RPC and other socket registration services. + - creating new directories/subvolumes/fifos/device nodes + should not follow symlinks. None of the other adjustment or creation + calls follow symlinks. * make sure systemd-ask-password-wall does not shutdown systemd-ask-password-console too early -* add ReloadSignal= for configuring a reload signal to use - * verify that the AF_UNIX sockets of a service in the fs still exist when we start a service in order to avoid confusion when a user assumes starting a service is enough to make it accessible @@ -801,8 +683,6 @@ Features: * and a dbus call to generate target from current state -* GC unreferenced jobs (such as .device jobs) - * write blog stories about: - hwdb: what belongs into it, lsusb - enabling dbus services @@ -823,20 +703,58 @@ Features: - instantiated apache, dovecot and so on - hooking a script into various stages of shutdown/rearly booot -* allow port=0 in .socket units - -* recreate systemd's D-Bus private socket file on SIGUSR2 - -* Support --test based on current system state - * investigate whether the gnome pty helper should be moved into systemd, to provide cgroup support. -* maybe introduce ExecRestartPre= - * dot output for --test showing the 'initial transaction' * fingerprint.target, wireless.target, gps.target, netdevice.target +* pid1: + - .timer units should optionally support CLOCK_BOOTTIME in addition to CLOCK_MONOTONIC + - When logging about multiple units (stopping BoundTo units, conflicts, etc.), + log both units as UNIT=, so that journalctl -u triggers on both. + - generate better errors when people try to set transient properties + that are not supported... + http://lists.freedesktop.org/archives/systemd-devel/2015-February/028076.html + - maybe introduce WantsMountsFor=? Usecase: + http://lists.freedesktop.org/archives/systemd-devel/2015-January/027729.html + - recreate systemd's D-Bus private socket file on SIGUSR2 + - GC unreferenced jobs (such as .device jobs) + - move PAM code into its own binary + - when we automatically restart a service, ensure we restart its rdeps, too. + - for services: do not set $HOME in services unless requested + - hide PAM options in fragment parser when compile time disabled + - Support --test based on current system state + - If we show an error about a unit (such as not showing up) and it has no Description string, then show a description string generated form the reverse of unit_name_mangle(). + - after deserializing sockets in socket.c we should reapply sockopts and things + - drop PID 1 reloading, only do reexecing (difficult: Reload() + currently is properly synchronous, Reexec() is weird, because we + cannot delay the response properly until we are back, so instead of + being properly synchronous we just keep open the fd and close it + when done. That means clients do not get a successful method reply, + but much rather a disconnect on success. + - when breaking cycles drop sysv services first, then services from /run, then from /etc, then from /usr + - when a bus name of a service disappears from the bus make sure to queue further activation requests + +* unit files: + - allow port=0 in .socket units + - maybe introduce ExecRestartPre= + - add ReloadSignal= for configuring a reload signal to use + - implement Register= switch in .socket units to enable registration + in Avahi, RPC and other socket registration services. + - allow Type=simple with PIDFile= + https://bugzilla.redhat.com/show_bug.cgi?id=723942 + - allow writing multiple conditions in unit files on one line + - load-fragment: when loading a unit file via a chain of symlinks + verify that it is not masked via any of the names traversed. + - introduce Type=pid-file + - ExecOnFailure=/usr/bin/foo + - introduce mix of BindTo and Requisite + - add a concept of RemainAfterExit= to scope units + - Set NoNewPrivileges= on all of our own services, where that makes sense + - Allow multiple ExecStart= for all Type= settings, so that we can cover rescue.service nicely + - consider adding RuntimeDirectoryUser= + RuntimeDirectoryGroup= + * systemd-python: - figure out a simple way to wait for journal events in a way that works with ^C @@ -868,6 +786,23 @@ Features: - add more attribute support for SIT tunnel - work with non-Ethernet devices - add support for more bond options + - dhcp: do we allow configuring dhcp routes on interfaces that are not the one we got the dhcp info from? + - add LLDP client side support + - the DHCP lease data (such as NTP/DNS) is still made available when + a carrier is lost on a link. It should be removed instantly. + - expose in the API the following bits: + - option 15, domain name and/or option 119, search list + - option 12, host name and/or option 81, fqdn + - option 123, 144, geolocation + - option 252, configure http proxy (PAC/wpad) + - provide a way to define a per-network interface default metric value + for all routes to it. possibly a second default for DHCP routes. + - allow Name= to be specified repeatedly in the [Match] section. Maybe also + support Name=foo*|bar*|baz ? + - duplicate address check for static IPs (like ARPCHECK in network-scripts) + - allow DUID/IAID to be customized, see issue #394. + - support configuration option for TSO (tcp segmentation offload) + - whenever uplink info changes, make DHCP server send out FORCERENEW * networkd-wait-online: - make operstates to wait for configurable? diff --git a/configure.ac b/configure.ac index c96b9fb1d9..ec30ff12ae 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_PREREQ([2.64]) AC_INIT([systemd], - [227], + [228], [http://github.com/systemd/systemd/issues], [systemd], [http://www.freedesktop.org/wiki/Software/systemd]) diff --git a/man/.gitignore b/man/.gitignore index bf5eeab938..d928e5a83f 100644 --- a/man/.gitignore +++ b/man/.gitignore @@ -1,4 +1,5 @@ /systemd.directives.xml /systemd.index.xml /*.[13578] +/*.html /custom-entities.ent diff --git a/man/custom-html.xsl b/man/custom-html.xsl index 84c23014e4..e89d73e7f1 100644 --- a/man/custom-html.xsl +++ b/man/custom-html.xsl @@ -37,7 +37,8 @@ <xsl:template match="citerefentry[not(@project)]"> <a> <xsl:attribute name="href"> - <xsl:value-of select="refentrytitle"/><xsl:text>.html</xsl:text> + <xsl:value-of select="refentrytitle"/><xsl:text>.html#</xsl:text> + <xsl:value-of select="refentrytitle/@target"/> </xsl:attribute> <xsl:call-template name="inline.charseq"/> </a> diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 43d1ffbd3c..94376656d5 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.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"> @@ -277,7 +277,18 @@ limit relative to the amount of physical RAM. Defaults to 10%. Note that this size is a safety limit only. As each runtime directory is a tmpfs file system, it will only consume as much - memory as is needed. </para></listitem> + memory as is needed.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>UserTasksMax=</varname></term> + + <listitem><para>Sets the maximum number of OS tasks each user + may run concurrently. This controls the + <varname>TasksMax=</varname> setting of the per-user slice + unit, see + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details. Defaults to 4096.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 811e33f4fa..4680b6a4e5 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -1,4 +1,4 @@ -<?xml version='1.0'?> <!--*-nxml-*--> +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> @@ -77,10 +77,11 @@ 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 - servers listed in <filename>/etc/resolv.conf</filename> are - used, if any are configured there. This setting defaults to - the empty list.</para></listitem> + For compatibility reasons, if this setting is not specified, + the DNS servers listed in + <filename>/etc/resolv.conf</filename> are used instead, if + that file exists and any servers are configured in it. This + setting defaults to the empty list.</para></listitem> </varlistentry> <varlistentry> @@ -98,6 +99,16 @@ </varlistentry> <varlistentry> + <term><varname>Domains=</varname></term> + <listitem><para>A space-separated list of search domains. For + compatibility reasons, if this setting is not specified, the + search domains listed in <filename>/etc/resolv.conf</filename> + are used instead, if that file exists and any domains are + configured in it. This setting defaults to the empty + list.</para></listitem> + </varlistentry> + + <varlistentry> <term><varname>LLMNR=</varname></term> <listitem><para>Takes a boolean argument or <literal>resolve</literal>. Controls Link-Local Multicast Name diff --git a/man/sd-daemon.xml b/man/sd-daemon.xml index b7ba363656..b06d99f346 100644 --- a/man/sd-daemon.xml +++ b/man/sd-daemon.xml @@ -71,10 +71,10 @@ <refsect1> <title>Description</title> - <para><filename>sd-daemon.h</filename> provide APIs for new-style + <para><filename>sd-daemon.h</filename> provides APIs for new-style daemons, as implemented by the <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> - init system.</para> + service manager.</para> <para>See <citerefentry><refentrytitle>sd_listen_fds</refentrytitle><manvolnum>3</manvolnum></citerefentry>, diff --git a/man/sd-event.xml b/man/sd-event.xml new file mode 100644 index 0000000000..47989f4421 --- /dev/null +++ b/man/sd-event.xml @@ -0,0 +1,187 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd-event" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd-event</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd-event</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd-event</refname> + <refpurpose>A generic event loop implementation</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + </funcsynopsis> + + <cmdsynopsis> + <command>pkg-config --cflags --libs libsystemd</command> + </cmdsynopsis> + + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><filename>sd-event.h</filename> provides a generic event + loop implementation, based on Linux <citerefentry + project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry>. + </para> + + <para>See + <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_get_event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry> + for more information about the functions available.</para> + + <para>The event loop design is targeted on running a separate + instance of the event loop in each thread; it has no concept of + distributing events from a single event loop instance onto + multiple worker threads. Dispatching events is strictly ordered + and subject to configurable priorities. In each event loop + iteration a single event source is dispatched. Each time an event + source is dispatched the kernel is polled for new events, before + the next event source is dispatched. The event loop is designed to + honour priorities and provide fairness within each priority. It is + not designed to provide optimal throughput, as this contradicts + these goals due the limitations of the underlying <citerefentry + project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry> + primitives.</para> + + <para>The event loop implementation provides the following features:</para> + + <orderedlist> + <listitem><para>I/O event sources, based on <citerefentry + project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry>'s + file descriptor watching, including edge triggered events (<constant>EPOLLET</constant>). See <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + <listitem><para>Timer event sources, based on <citerefentry + project='man-pages'><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>, + supporting the <constant>CLOCK_MONOTONIC</constant>, + <constant>CLOCK_REALTIME</constant>, + <constant>CLOCK_BOOTIME</constant> clocks, as well as the + <constant>CLOCK_REALTIME_ALARM</constant> and + <constant>CLOCK_BOOTTIME_ALARM</constant> clocks that can resume + the system from suspend. When creating timer events a required + accuracy parameter may be specified which allows coalescing of + timer events to minimize power consumption. See <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + <listitem><para>UNIX process signal events, based on + <citerefentry + project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>, + including full support for real-time signals, and queued parameters. See <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + <listitem><para>Child process state change events, based on + <citerefentry project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry>. See <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + <listitem><para>Static event sources, of three types: defer, + post and exit, for invoking calls in each event loop, after + other event sources or at event loop termination. See + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + <listitem><para>Event sources may be assigned a 64bit priority + value, that controls the order in which event sources are + dispatched if multiple are pending simultanously. See + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + <listitem><para>The event loop may automatically send watchdog + notification messages to the service manager. See + <citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + <listitem><para>The event loop may be integrated into foreign + event loops, such as the GLib one. See + <citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry> + for an example.</para></listitem> + </orderedlist> + + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_get_event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml index 77bec4e706..d4b180cf03 100644 --- a/man/sd_event_add_child.xml +++ b/man/sd_event_add_child.xml @@ -21,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_add_child"> +<refentry id="sd_event_add_child" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_add_child</title> @@ -45,13 +45,23 @@ <refnamediv> <refname>sd_event_add_child</refname> <refname>sd_event_source_get_child_pid</refname> + <refname>sd_event_child_handler_t</refname> - <refpurpose>Add a child state change event source to an event loop</refpurpose> + <refpurpose>Add a child process state change event source to an event loop</refpurpose> </refnamediv> <refsynopsisdiv> <funcsynopsis> - <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>typedef</token> struct sd_event_source sd_event_source;</funcsynopsisinfo> + + <funcprototype> + <funcdef>typedef int (*<function>sd_event_child_handler_t</function>)</funcdef> + <paramdef>sd_event_source *<parameter>s</parameter></paramdef> + <paramdef>const siginfo_t *<parameter>si</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> <funcprototype> <funcdef>int <function>sd_event_add_child</function></funcdef> @@ -64,13 +74,6 @@ </funcprototype> <funcprototype> - <funcdef>typedef int (*<function>sd_event_child_handler_t</function>)</funcdef> - <paramdef>sd_event_source *<parameter>s</parameter></paramdef> - <paramdef>const siginfo_t *<parameter>si</parameter></paramdef> - <paramdef>void *<parameter>userdata</parameter></paramdef> - </funcprototype> - - <funcprototype> <funcdef>int <function>sd_event_source_get_child_pid</function></funcdef> <paramdef>sd_event_source *<parameter>source</parameter></paramdef> <paramdef>pid_t *<parameter>pid</parameter></paramdef> @@ -83,42 +86,75 @@ <title>Description</title> <para><function>sd_event_add_child()</function> adds a new child - state change event source 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 - <parameter>pid</parameter> parameter specifies the process to - watch. The <parameter>handler</parameter> must reference a - function to call when the process changes state. The handler - function will be passed the <parameter>userdata</parameter> - pointer, which may be chosen freely by the caller. The handler - also receives a pointer to a <structname>const - siginfo_t</structname> structure containing the information about - the event. The <parameter>options</parameter> parameter determines - which state changes will be watched for. It must contain an OR-ed - mask of <constant>WEXITED</constant> (watch for the child + process state change event source to an event loop. The event loop + object is specified in the <parameter>event</parameter> parameter, + the event source object is returned in the + <parameter>source</parameter> parameter. The + <parameter>pid</parameter> parameter specifies the PID of the + process to watch. The <parameter>handler</parameter> must + reference a function to call when the process changes state. The + handler function will be passed the + <parameter>userdata</parameter> pointer, which may be chosen + freely by the caller. The handler also receives a pointer to a + <structname>siginfo_t</structname> structure containing + information about the child process event. The + <parameter>options</parameter> parameter determines which state + changes will be watched for. It must contain an OR-ed mask of + <constant>WEXITED</constant> (watch for the child process terminating), <constant>WSTOPPED</constant> (watch for the child - being stopped by a signal), and <constant>WCONTINUED</constant> - (watch for the child being resumed by a signal). See - <citerefentry><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry> + process being stopped by a signal), and + <constant>WCONTINUED</constant> (watch for the child process being + resumed by a signal). See <citerefentry + project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry> for further information.</para> <para>Only a single handler may be installed for a specific - child. The handler is enabled - for a single event (<constant>SD_EVENT_ONESHOT</constant>), - but this may be - changed with + child process. The handler is enabled for a single event + (<constant>SD_EVENT_ONESHOT</constant>), but this may be changed + with <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If the handler function returns a negative error code, it will be - disabled after the invocation, even if - <constant>SD_EVENT_ON</constant> mode is set. + disabled after the invocation, even if the + <constant>SD_EVENT_ON</constant> mode was requested before. </para> + <para>To destroy an event source object use + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even when there's still a + reference to it kept, consider setting the event source to + <constant>SD_EVENT_OFF</constant> with + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>If the the second parameter of + <function>sd_event_add_child()</function> is passed as NULL no + reference to the event source object is returned. In this case the + event source is considered "floating", and will be destroyed + implicitly when the event loop itself is destroyed.</para> + + <para>Note that the <parameter>handler</parameter> function is + invoked at a time where the child process is not reaped yet (and + thus still is exposed as a zombie process by the kernel). However, + the child will be reaped automatically after the function + returns. Child processes for which no child process state change + event sources are installed will not be reaped by the event loop + implementation.</para> + + <para>If both a child process state change event source and a + <constant>SIGCHLD</constant> signal event source is installed in + the same event loop, the configured event source priorities decide + which event source is dispatched first. If the signal handler is + processed first, it should leave the child processes for which + child process state change event sources are installed unreaped.</para> + <para><function>sd_event_source_get_child_pid()</function> - retrieves the configured <parameter>pid</parameter> of a child - state change event source created previously with + retrieves the configured PID of a child process state change event + source created previously with <function>sd_event_add_child()</function>. It takes the event source object as the <parameter>source</parameter> parameter and a - pointer to <type>pid_t</type> to return the result in. + pointer to a <type>pid_t</type> variable to return the process ID + in. </para> </refsect1> @@ -158,7 +194,7 @@ <term><constant>-EBUSY</constant></term> <listitem><para>A handler is already installed for this - child.</para></listitem> + child process.</para></listitem> </varlistentry> @@ -176,19 +212,17 @@ </varlistentry> - </variablelist> - </refsect1> + <varlistentry> + <term><constant>-EDOM</constant></term> - <refsect1> - <title>Notes</title> + <listitem><para>The passed event source is not a child process event source.</para></listitem> + </varlistentry> - <para><function>sd_event_add_child()</function> and the other 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> - file.</para> + </variablelist> </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> + <refsect1> <title>See Also</title> @@ -196,10 +230,16 @@ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>waitid</refentrytitle><manvolnum>2</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml index 826f2fd224..6a13ede76e 100644 --- a/man/sd_event_add_defer.xml +++ b/man/sd_event_add_defer.xml @@ -21,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_add_defer"> +<refentry id="sd_event_add_defer" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_add_defer</title> @@ -46,13 +46,22 @@ <refname>sd_event_add_defer</refname> <refname>sd_event_add_post</refname> <refname>sd_event_add_exit</refname> + <refname>sd_event_handler_t</refname> <refpurpose>Add static event sources to an event loop</refpurpose> </refnamediv> <refsynopsisdiv> <funcsynopsis> - <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>typedef</token> struct sd_event_source sd_event_source;</funcsynopsisinfo> + + <funcprototype> + <funcdef>typedef int (*<function>sd_event_handler_t</function>)</funcdef> + <paramdef>sd_event_source *<parameter>s</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> <funcprototype> <funcdef>int <function>sd_event_add_defer</function></funcdef> @@ -78,49 +87,67 @@ <paramdef>void *<parameter>userdata</parameter></paramdef> </funcprototype> - <funcprototype> - <funcdef>typedef int (*<function>sd_event_handler_t</function>)</funcdef> - <paramdef>sd_event_source *<parameter>s</parameter></paramdef> - <paramdef>void *<parameter>userdata</parameter></paramdef> - </funcprototype> - </funcsynopsis> </refsynopsisdiv> <refsect1> <title>Description</title> - <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 - enabled statically and will "fire" when the event loop is run and - the conditions described below are met. The handler function will - be passed the <parameter>userdata</parameter> pointer, which may - be chosen freely by the caller.</para> + <para>These three functions add new static event sources to an + event loop. The event loop object is specified in the + <parameter>event</parameter> parameter, the event source object is + returned in the <parameter>source</parameter> parameter. The event + sources are enabled statically and will "fire" when the event loop + is run and the conditions described below are met. The handler + function will be passed the <parameter>userdata</parameter> + pointer, which may be chosen freely by the caller.</para> <para><function>sd_event_add_defer()</function> adds a new event - source that will "fire" the next time the event loop is run. By - default, the handler will be called once - (<constant>SD_EVENT_ONESHOT</constant>).</para> + source that will be dispatched instantly, before the event loop + goes to sleep again and waits for new events. By default, the + handler will be called once + (<constant>SD_EVENT_ONESHOT</constant>). Note that if the event + source is set to <constant>SD_EVENT_ON</constant> the event loop + will never go to sleep again, but continously call the handler, + possibly interleaved with other event sources.</para> <para><function>sd_event_add_post()</function> adds a new event - source that will "fire" if any event handlers are invoked whenever - the event loop is run. By default, the source is enabled - permanently (<constant>SD_EVENT_ON</constant>).</para> + source that is run before the event loop will sleep and wait + for new events, but only after at least one other non-post event + source was dispatched. By default, the source is enabled + permanently (<constant>SD_EVENT_ON</constant>). Note that this + event source type will still allow the event loop to go to sleep + again, even if set to <constant>SD_EVENT_ON</constant>, as long as + no other event source is ever triggered.</para> <para><function>sd_event_add_exit()</function> adds a new event - source that will "fire" when the event loop is terminated - with <function>sd_event_exit()</function>.</para> + source that will be dispatched when the event loop is terminated + with <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> <para>The <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> function may be used to enable the event source permanently (<constant>SD_EVENT_ON</constant>) or to make it fire just once - (<constant>SD_EVENT_ONESHOT</constant>). If the handler function - returns a negative error code, it will be disabled after the - invocation, even if <constant>SD_EVENT_ON</constant> mode is - set.</para> + (<constant>SD_EVENT_ONESHOT</constant>).</para> + + <para>If the handler function returns a negative error code, it + will be disabled after the invocation, even if the + <constant>SD_EVENT_ON</constant> mode was requested before.</para> + + <para>To destroy an event source object use + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even when there's still a + reference to it kept, consider setting the event source to + <constant>SD_EVENT_OFF</constant> with + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>If the second parameter of these functions is passed as + NULL no reference to the event source object is returned. In this + case the event source is considered "floating", and will be + destroyed implicitly when the event loop itself is + destroyed.</para> </refsect1> <refsect1> @@ -164,15 +191,7 @@ </variablelist> </refsect1> - <refsect1> - <title>Notes</title> - - <para>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> - file.</para> - </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> <refsect1> <title>See Also</title> @@ -181,10 +200,16 @@ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_event_add_io.xml b/man/sd_event_add_io.xml new file mode 100644 index 0000000000..4cc0428e29 --- /dev/null +++ b/man/sd_event_add_io.xml @@ -0,0 +1,300 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_add_io" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_add_io</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_add_io</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_add_io</refname> + <refname>sd_event_source_get_io_events</refname> + <refname>sd_event_source_set_io_events</refname> + <refname>sd_event_source_get_io_revents</refname> + <refname>sd_event_source_get_io_fd</refname> + <refname>sd_event_source_set_io_fd</refname> + <refname>sd_event_source</refname> + <refname>sd_event_io_handler_t</refname> + + <refpurpose>Add an I/O event source to an event loop</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>typedef</token> struct sd_event_source sd_event_source;</funcsynopsisinfo> + + <funcprototype> + <funcdef>typedef int (*<function>sd_event_io_handler_t</function>)</funcdef> + <paramdef>sd_event_source *<parameter>s</parameter></paramdef> + <paramdef>int <parameter>fd</parameter></paramdef> + <paramdef>uint32_t <parameter>revents</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_add_io</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + <paramdef>sd_event_source **<parameter>source</parameter></paramdef> + <paramdef>int <parameter>fd</parameter></paramdef> + <paramdef>uint32_t <parameter>events</parameter></paramdef> + <paramdef>sd_event_io_handler_t <parameter>handler</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_get_io_events</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>uint32_t *<parameter>events</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_set_io_events</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>uint32_t <parameter>events</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_get_io_revents</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>uint32_t *<parameter>revents</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_get_io_fd</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_set_io_fd</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>int <parameter>fd</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_add_io()</function> adds a new I/O event + source to an event loop. The event loop object is specified in the + <parameter>event</parameter> parameter, the event source object is + returned in the <parameter>source</parameter> parameter. The + <parameter>fd</parameter> parameter takes the UNIX file descriptor + to watch, which may refer to a socket, a FIFO, a message queue, a + serial connection, a character device or any other file descriptor + compatible with Linux <citerefentry + project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry>. The + <parameter>events</parameter> parameter takes a bit mask of I/O + events to watch the file descriptor for, a combination of the + following event flags: <constant>EPOLLIN</constant>, + <constant>EPOLLOUT</constant>, <constant>EPOLLRDHUP</constant>, + <constant>EPOLLPRI</constant> and <constant>EPOLLET</constant>, + see <citerefentry + project='man-pages'><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> + for details. The <parameter>handler</parameter> shall reference a + function to call when the I/O event source is triggered. The + handler function will be passed the + <parameter>userdata</parameter> pointer, which may be chosen + freely by the caller. The handler will also be passed the file + descriptor the event was seen on as well as the actual event flags + seen. It's generally a subset of the events watched, however may + additionally have <constant>EPOLLERR</constant> and + <constant>EPOLLHUP</constant> set.</para> + + <para>By default, the I/O event source will stay enabled + continously (<constant>SD_EVENT_ON</constant>), but this may be + changed with + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>. + If the handler function returns a negative error code, it will be + disabled after the invocation, even if the + <constant>SD_EVENT_ON</constant> mode was requested before. Note + that an I/O event source set to <constant>SD_EVENT_ON</constant> will + fire continously unless data is read or written to the file + descriptor in order to reset the mask of events seen. + </para> + + <para>Setting the I/O event mask to watch for to 0 does not mean + that the event source won't be triggered anymore, as + <constant>EPOLLHUP</constant> and <constant>EPOLLERR</constant> + may be triggered even with a zero event mask. To temporarily + disable an I/O event source use + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + with <constant>SD_EVENT_OFF</constant> instead.</para> + + <para>To destroy an event source object use + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even when there's still a + reference to it kept, consider setting the event source to + <constant>SD_EVENT_OFF</constant> with + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>If the the second parameter of + <function>sd_event_add_io()</function> is passed as NULL no + reference to the event source object is returned. In this case the + event source is considered "floating", and will be destroyed + implicitly when the event loop itself is destroyed.</para> + + <para>It is recommended to use + <function>sd_event_add_io()</function> only in conjunction with + file descriptors that have <constant>O_NONBLOCK</constant> set, to + ensure that all I/O operations from invoked handlers are properly + asynchronous and non-blocking. Using file descriptors without + <constant>O_NONBLOCK</constant> might result in unexpected + starving of other event sources. See <citerefentry + project='man-pages'><refentrytitle>fcntl</refentrytitle><manvolnum>2</manvolnum></citerefentry> + for details on enabling <constant>O_NONBLOCK</constant> mode.</para> + + <para><function>sd_event_source_get_io_events()</function> retrieves + the configured I/O event mask to watch of an I/O event source created + previously with <function>sd_event_add_io()</function>. It takes + the event source object and a pointer to a variable to store the + event mask in.</para> + + <para><function>sd_event_source_set_io_events()</function> changes the + configured I/O event mask to watch of an I/O event source created previously + with <function>sd_event_add_io()</function>. It takes the event + source object and the new event mask to set.</para> + + <para><function>sd_event_source_get_io_revents()</function> + retrieves the I/O event mask of currently seen but undispatched + events from an I/O event source created previously with + <function>sd_event_add_io()</function>. It takes the event source + object and a pointer to a variable to store the event mask + in. When called from a handler function on the handler's event + source object this will return the same mask as passed to the + handler's <parameter>revents</parameter> parameter. This call is + primarily useful to check for undispatched events of an event + source from the handler of an unrelated (possibly higher priority) + event source. Note the relation between + <function>sd_event_source_get_pending()</function> and + <function>sd_event_source_get_io_revents()</function>: both + functions will report non-zero results when there's an event + pending for the event source, but the former applies to all event + source types, the latter only to I/O event sources.</para> + + <para><function>sd_event_source_get_io_fd()</function> retrieves + the UNIX file descriptor of an I/O event source created previously + with <function>sd_event_add_io()</function>. It takes the event + source object and returns the positive file descriptor in the return + value, or a negative error number on error (see below).</para> + + <para><function>sd_event_source_set_io_fd()</function> + changes the UNIX file descriptor of an I/O event source created + previously with <function>sd_event_add_io()</function>. It takes + the event source object and the new file descriptor to set.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, these functions return 0 or a positive + integer. On failure, they return a negative errno-style error + code. </para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + <varlistentry> + <term><constant>-ENOMEM</constant></term> + + <listitem><para>Not enough memory to allocate an object.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para>An invalid argument has been passed.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-ESTALE</constant></term> + + <listitem><para>The event loop is already terminated.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop has been created in a different process.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-EDOM</constant></term> + + <listitem><para>The passed event source is not an I/O event source.</para></listitem> + </varlistentry> + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_get_pending</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>epoll_ctl</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml index 0923fe0ae7..b5312735d2 100644 --- a/man/sd_event_add_signal.xml +++ b/man/sd_event_add_signal.xml @@ -21,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_add_signal"> +<refentry id="sd_event_add_signal" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_add_signal</title> @@ -45,13 +45,24 @@ <refnamediv> <refname>sd_event_add_signal</refname> <refname>sd_event_source_get_signal</refname> + <refname>sd_event_signal_handler_t</refname> - <refpurpose>Add a signal event source to an event loop</refpurpose> + <refpurpose>Add a UNIX process signal event source to an event + loop</refpurpose> </refnamediv> <refsynopsisdiv> <funcsynopsis> - <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>typedef</token> struct sd_event_source sd_event_source;</funcsynopsisinfo> + + <funcprototype> + <funcdef>typedef int (*<function>sd_event_signal_handler_t</function>)</funcdef> + <paramdef>sd_event_source *<parameter>s</parameter></paramdef> + <paramdef>const struct signalfd_siginfo *<parameter>si</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> <funcprototype> <funcdef>int <function>sd_event_add_signal</function></funcdef> @@ -63,13 +74,6 @@ </funcprototype> <funcprototype> - <funcdef>typedef int (*<function>sd_event_signal_handler_t</function>)</funcdef> - <paramdef>sd_event_source *<parameter>s</parameter></paramdef> - <paramdef>const struct signalfd_siginfo *<parameter>si</parameter></paramdef> - <paramdef>void *<parameter>userdata</parameter></paramdef> - </funcprototype> - - <funcprototype> <funcdef>int <function>sd_event_source_get_signal</function></funcdef> <paramdef>sd_event_source *<parameter>source</parameter></paramdef> </funcprototype> @@ -80,41 +84,61 @@ <refsect1> <title>Description</title> - <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>, and the event source is returned in - the <parameter>source</parameter> parameter. The - <parameter>signal</parameter> parameter specifies the signal to be handled - (see - <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>). - The <parameter>handler</parameter> must reference a function to - call when the signal is delivered or be <constant>NULL</constant>. - The handler function will be passed the - <parameter>userdata</parameter> pointer, which may be chosen + <para><function>sd_event_add_signal()</function> adds a new UNIX + process signal event source to an event loop. The event loop + object is specified in the <parameter>event</parameter> parameter, + and the event source object is returned in the + <parameter>source</parameter> parameter. The + <parameter>signal</parameter> parameter specifies the numeric + signal to be handled (see <citerefentry + project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>). + The <parameter>handler</parameter> parameter must reference a + function to call when the signal is received or be + <constant>NULL</constant>. The handler function will be passed + the <parameter>userdata</parameter> pointer, which may be chosen freely by the caller. The handler also receives a pointer to a - <structname>const struct signalfd_siginfo</structname> containing - the information about the received signal. See - <citerefentry project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry> + <structname>signalfd_siginfo</structname> structure containing + information about the received signal. See <citerefentry + project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry> for further information.</para> <para>Only a single handler may be installed for a specific - signal. The signal will be unblocked, and must be - blocked when the function is called. If the handler is not - specified (<parameter>handler</parameter> is + signal. The signal will be unblocked by this call, and must be + blocked before this function is called in all threads (using + <citerefentry + project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry>). If + the handler is not specified (<parameter>handler</parameter> is <constant>NULL</constant>), a default handler which causes the - program to exit will be used. By default, the handler is enabled - permanently (<constant>SD_EVENT_ON</constant>), but this may be - changed with + program to exit cleanly will be used.</para> + + <para>By default, the event source is enabled permanently + (<constant>SD_EVENT_ON</constant>), but this may be changed with <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If the handler function returns a negative error code, it will be - disabled after the invocation, even if - <constant>SD_EVENT_ON</constant> mode is set. + disabled after the invocation, even if the + <constant>SD_EVENT_ON</constant> mode was requested before. </para> + <para>To destroy an event source object use + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even when there's still a + reference to it kept, consider setting the event source to + <constant>SD_EVENT_OFF</constant> with + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>If the the second parameter of + <function>sd_event_add_signal()</function> is passed as NULL no + reference to the event source object is returned. In this case the + event source is considered "floating", and will be destroyed + implicitly when the event loop itself is destroyed.</para> + <para><function>sd_event_source_get_signal()</function> retrieves - the configured signal number of a signal event source created - previously with <function>sd_event_add_signal()</function>. It - takes the event source object as the <parameter>source</parameter> + the configured UNIX process signal number of a signal event source + created previously with + <function>sd_event_add_signal()</function>. It takes the event + source object as the <parameter>source</parameter> parameter.</para> </refsect1> @@ -168,19 +192,17 @@ </varlistentry> - </variablelist> - </refsect1> + <varlistentry> + <term><constant>-EDOM</constant></term> - <refsect1> - <title>Notes</title> + <listitem><para>The passed event source is not a signal event source.</para></listitem> + </varlistentry> - <para><function>sd_event_add_signal()</function> and the other 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> - file.</para> + </variablelist> </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> + <refsect1> <title>See Also</title> @@ -188,10 +210,16 @@ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>signalfd</refentrytitle><manvolnum>2</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml index c5f7aee19d..df38f52fc9 100644 --- a/man/sd_event_add_time.xml +++ b/man/sd_event_add_time.xml @@ -21,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_add_time"> +<refentry id="sd_event_add_time" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_add_time</title> @@ -49,13 +49,23 @@ <refname>sd_event_source_get_time_accuracy</refname> <refname>sd_event_source_set_time_accuracy</refname> <refname>sd_event_source_get_time_clock</refname> + <refname>sd_event_time_handler_t</refname> <refpurpose>Add a timer event source to an event loop</refpurpose> </refnamediv> <refsynopsisdiv> <funcsynopsis> - <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>typedef</token> struct sd_event_source sd_event_source;</funcsynopsisinfo> + + <funcprototype> + <funcdef>typedef int (*<function>sd_event_time_handler_t</function>)</funcdef> + <paramdef>sd_event_source *<parameter>s</parameter></paramdef> + <paramdef>uint64_t <parameter>usec</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> <funcprototype> <funcdef>int <function>sd_event_add_time</function></funcdef> @@ -69,34 +79,27 @@ </funcprototype> <funcprototype> - <funcdef>typedef int (*<function>sd_event_time_handler_t</function>)</funcdef> - <paramdef>sd_event_source *<parameter>s</parameter></paramdef> - <paramdef>uint64_t <parameter>usec</parameter></paramdef> - <paramdef>void *<parameter>userdata</parameter></paramdef> - </funcprototype> - - <funcprototype> <funcdef>int <function>sd_event_source_get_time</function></funcdef> <paramdef>sd_event_source *<parameter>source</parameter></paramdef> - <paramdef>usec_t *<parameter>usec</parameter></paramdef> + <paramdef>uint64_t *<parameter>usec</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>int <function>sd_event_source_set_time</function></funcdef> <paramdef>sd_event_source *<parameter>source</parameter></paramdef> - <paramdef>usec_t <parameter>usec</parameter></paramdef> + <paramdef>uint64_t <parameter>usec</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>int <function>sd_event_source_get_time_accuracy</function></funcdef> <paramdef>sd_event_source *<parameter>source</parameter></paramdef> - <paramdef>usec_t *<parameter>usec</parameter></paramdef> + <paramdef>uint64_t *<parameter>usec</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>int <function>sd_event_source_set_time_accuracy</function></funcdef> <paramdef>sd_event_source *<parameter>source</parameter></paramdef> - <paramdef>usec_t <parameter>usec</parameter></paramdef> + <paramdef>uint64_t <parameter>usec</parameter></paramdef> </funcprototype> <funcprototype> @@ -112,73 +115,130 @@ <title>Description</title> <para><function>sd_event_add_time()</function> adds a new timer - event source 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 - <parameter>clock</parameter> parameter takes a clock identifier, - one of <constant>CLOCK_REALTIME</constant>, - <constant>CLOCK_MONOTONIC</constant> and + event source to an event loop. The event loop object is specified + in the <parameter>event</parameter> parameter, the event source + object is returned in the <parameter>source</parameter> + parameter. The <parameter>clock</parameter> parameter takes a + clock identifier, one of <constant>CLOCK_REALTIME</constant>, + <constant>CLOCK_MONOTONIC</constant>, + <constant>CLOCK_BOOTTIME</constant>, + <constant>CLOCK_REALTIME_ALARM</constant> or <constant>CLOCK_BOOTTIME_ALARM</constant>. See <citerefentry><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry> for details regarding the various types of clocks. The <parameter>usec</parameter> parameter takes a time value in - microseconds, relative to the clock's epoch specifying when the - timer shall elapse the earliest. The + microseconds (µs), relative to the clock's epoch, specifying when + the timer shall elapse the earliest. If a time that already lies + in the past is specified (including 0), the timer source is + dispatched immediately in the next event loop iterations. The <parameter>accuracy</parameter> parameter takes an additional - accuracy value in microseconds specifying a time the timer event - may be delayed. Specify 0 for selecting the default accuracy - (250ms). Specify 1 for most accurate timers. Consider specifying - 60000000 or larger (1h) for long-running events that may be + accuracy value in µs specifying a time the timer event may be + delayed. Specify 0 for selecting the default accuracy + (250ms). Specify 1µs for most accurate timers. Consider specifying + 60000000µs or larger (1min) for long-running events that may be delayed substantially. Picking higher accuracy values allows the system to coalesce timer events more aggressively, thus improving - power efficiency. The <parameter>handler</parameter> shall - reference a function to call when the timer elapses. The handler - function will be passed the <parameter>userdata</parameter> - pointer, which may be chosen freely by the caller. The handler is - also passed the configured time it was triggered, however it might - actually have been called at a slightly later time, subject to the - specified accuracy value, the kernel timer slack (see + power efficiency. The <parameter>handler</parameter> parameter + shall reference a function to call when the timer elapses. The + handler function will be passed the + <parameter>userdata</parameter> pointer, which may be chosen + freely by the caller. The handler is also passed the configured + time it was triggered, however it might actually have been called + at a slightly later time, subject to the specified accuracy value, + the kernel timer slack (see <citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry>) - and additional scheduling latencies.</para> + and additional scheduling latencies. To query the actual time the + handler was called use + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> <para>By default, the timer will elapse once (<constant>SD_EVENT_ONESHOT</constant>), but this may be changed with <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>. If the handler function returns a negative error code, it will be - disabled after the invocation, even if - <constant>SD_EVENT_ON</constant> mode is set. + disabled after the invocation, even if the + <constant>SD_EVENT_ON</constant> mode was requested before. Note + that a timer event set to <constant>SD_EVENT_ON</constant> will + fire continously unless its configured time is updated using + <function>sd_event_source_set_time()</function>. </para> + <para>To destroy an event source object use + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even when there's still a + reference to it kept, consider setting the event source to + <constant>SD_EVENT_OFF</constant> with + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>If the the second parameter of + <function>sd_event_add_time()</function> is passed as NULL no + reference to the event source object is returned. In this case the + event source is considered "floating", and will be destroyed + implicitly when the event loop itself is destroyed.</para> + + <para>If the <parameter>handler</parameter> to + <function>sd_event_add_time()</function> is passed as NULL, and + the event source fires, this will be considered a request to exit + the event loop. In this case, the <parameter>userdata</parameter> + parameter, cast to an integer is used for the exit code passed to + <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>Use <constant>CLOCK_BOOTTIME_ALARM</constant> and + <constant>CLOCK_REALTIME_ALARM</constant> to define event sources + that may wake up the system from suspend.</para> + + <para>In order to set up relative timers (that is, relative to the + current time), retrieve the current time via + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + add the desired timespan to sleep to it, and pass the result as + the <parameter>usec</parameter> parameter to + <function>sd_event_add_time()</function>.</para> + + <para>In order to set up repetitive timers (that is, timers that + are triggered in regular intervals), set up the timer normally, + for the first invocation. Each time the event handler is invoked, + update the timer's trigger time with + <citerefentry><refentrytitle>sd_event_source_set_time</refentrytitle><manvolnum>3</manvolnum></citerefentry> for the next timer + iteration, and reenable the timer using + <function>sd_event_source_set_enabled()</function>. To calculate + the next point in time to pass to + <function>sd_event_source_set_time()</function>, either use as + base the <parameter>usec</parameter> parameter passed to the timer + callback, or the timestamp returned by + <function>sd_event_now()</function>. In the former case timer + events will be regular, while in the latter case the scheduling + latency will keep accumulating on the timer.</para> + <para><function>sd_event_source_get_time()</function> retrieves the configured time value of a timer event source created previously with <function>sd_event_add_time()</function>. It takes the event source object and a pointer to a variable to store the - time in microseconds in.</para> + time, relative to the selected clock's epoch, in µs in.</para> <para><function>sd_event_source_set_time()</function> changes the configured time value of a timer event source created previously with <function>sd_event_add_time()</function>. It takes the event source object and a time relative to the selected clock's - epoch, in microseconds.</para> + epoch, in µs.</para> <para><function>sd_event_source_get_time_accuracy()</function> retrieves the configured accuracy value of a timer event source created previously with <function>sd_event_add_time()</function>. It takes the event source object and a pointer to a variable to store - the accuracy in microseconds in.</para> + the accuracy in µs in.</para> <para><function>sd_event_source_set_time_accuracy()</function> changes the configured accuracy of a timer event source created previously with <function>sd_event_add_time()</function>. It takes - the event source object and an accuracy, in microseconds.</para> + the event source object and an accuracy, in µs.</para> <para><function>sd_event_source_get_time_clock()</function> retrieves the configured clock of a timer event source created previously with <function>sd_event_add_time()</function>. It takes the event source object and a pointer to a variable to store the clock identifier in.</para> - </refsect1> <refsect1> @@ -228,19 +288,17 @@ <listitem><para>The selected clock is not supported by the event loop implementation.</para></listitem> </varlistentry> - </variablelist> - </refsect1> - <refsect1> - <title>Notes</title> + <varlistentry> + <term><constant>-EDOM</constant></term> - <para><function>sd_event_add_time()</function> and the other 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> - file.</para> + <listitem><para>The passed event source is not a timer event source.</para></listitem> + </varlistentry> + </variablelist> </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> + <refsect1> <title>See Also</title> @@ -248,11 +306,18 @@ <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_now</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>timerfd_create</refentrytitle><manvolnum>2</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_event_exit.xml b/man/sd_event_exit.xml new file mode 100644 index 0000000000..4f34f3b122 --- /dev/null +++ b/man/sd_event_exit.xml @@ -0,0 +1,163 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_exit" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_exit</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_exit</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_exit</refname> + <refname>sd_event_get_exit_code</refname> + + <refpurpose>Ask the event loop to exit</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_exit</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + <paramdef>int <parameter>code</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_get_exit_code</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + <paramdef>int *<parameter>code</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_exit()</function> requests the event loop + specified in the <parameter>event</parameter> event loop object to + exit. The <parameter>code</parameter> parameter may be any integer + value and is returned as-is by + <citerefentry><refentrytitle>sd_event_loop</refentrytitle><manvolnum>3</manvolnum></citerefentry> + after the last event loop iteration. It may also be be queried + using <function>sd_event_get_exit_code()</function>, see + below. </para> + + <para>When exiting is requested the event loop will stop listening + for and dispatching regular event sources. Instead it will proceed + with executing only event sources registered with + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry> + in the order defined by their priority. After all exit event + sources have been dispatched the event loop is terminated.</para> + + <para>If <function>sd_event_exit()</function> is invoked a second + time while the event loop is still processing exit event sources, + the exit code stored in the event loop object is updated, but + otherwise no further operation is executed.</para> + + <para><function>sd_event_get_exit_code()</function> may be used to + query the exit code passed into + <function>sd_event_exit()</function> earlier.</para> + + <para>While the full positive and negative integer ranges may be used + for the exit code, care should be taken not pick exit codes that + conflict with regular exit codes returned by + <function>sd_event_loop()</function>, if these exit codes shall be + distinguishable.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, <function>sd_event_exit()</function> and + <function>sd_event_get_exit_code()</function> return 0 or a positive + integer. On failure, they return a negative errno-style error + code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para>The event loop object or error code pointer are invalid.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop was created in a different process.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ESTALE</constant></term> + + <listitem><para>The event loop has exited already and all exit handlers are already processed.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ENODATA</constant></term> + + <listitem><para>The event loop has not been requested to exit yet.</para></listitem> + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_get_fd.xml b/man/sd_event_get_fd.xml index ecdbe76ec4..f68752dd0e 100644 --- a/man/sd_event_get_fd.xml +++ b/man/sd_event_get_fd.xml @@ -21,8 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_get_fd" - xmlns:xi="http://www.w3.org/2001/XInclude"> +<refentry id="sd_event_get_fd" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_get_fd</title> @@ -51,11 +50,11 @@ <refsynopsisdiv> <funcsynopsis> - <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> <funcprototype> <funcdef>int <function>sd_event_get_fd</function></funcdef> - <paramdef>sd_bus *<parameter>event</parameter></paramdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> </funcprototype> </funcsynopsis> @@ -65,19 +64,29 @@ <title>Description</title> <para><function>sd_event_get_fd()</function> returns the file - descriptor that the event loop object returned by the + descriptor that an event loop object returned by the <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry> - function uses to wait for events. This file descriptor can be - polled for events. This makes it possible to embed the + function uses to wait for events. This file descriptor may itself + be polled for + <constant>POLLIN</constant>/<constant>EPOLLIN</constant> + events. This makes it possible to embed an <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry> - event loop inside of another event loop.</para> + event loop into another, possibly foreign, event loop.</para> + + <para>The returned file descriptor refers to an <citerefentry + project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry> + object. It is recommended not to alter it by invoking + <citerefentry + project='man-pages'><refentrytitle>epoll_ctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> + on it, in order to avoid interference with the event loop's inner + logic and assumptions.</para> </refsect1> <refsect1> <title>Return Value</title> <para>On success, <function>sd_event_get_fd()</function> returns a - non-negative integer. On failure, it returns a negative + non-negative file descriptor. On failure, it returns a negative errno-style error code.</para> </refsect1> @@ -108,21 +117,13 @@ <title>Examples</title> <example> - <title>Integration in glib event loop</title> + <title>Integration in the GLib event loop</title> <programlisting><xi:include href="glib-event-glue.c" parse="text" /></programlisting> </example> </refsect1> - <refsect1> - <title>Notes</title> - - <para><function>sd_event_get_fd()</function> is 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> - file.</para> - </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> <refsect1> <title>See Also</title> @@ -130,7 +131,9 @@ <para> <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_ref</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>epoll_ctl</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_event_new.xml b/man/sd_event_new.xml index f6c5d39814..3356faa899 100644 --- a/man/sd_event_new.xml +++ b/man/sd_event_new.xml @@ -21,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_new"> +<refentry id="sd_event_new" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_new</title> @@ -47,32 +47,42 @@ <refname>sd_event_default</refname> <refname>sd_event_ref</refname> <refname>sd_event_unref</refname> + <refname>sd_event_get_tid</refname> + <refname>sd_event</refname> <refpurpose>Acquire and release an event loop object</refpurpose> </refnamediv> <refsynopsisdiv> <funcsynopsis> - <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>typedef</token> struct sd_event sd_event;</funcsynopsisinfo> <funcprototype> <funcdef>int <function>sd_event_new</function></funcdef> - <paramdef>sd_bus **<parameter>event</parameter></paramdef> + <paramdef>sd_event **<parameter>event</parameter></paramdef> </funcprototype> <funcprototype> <funcdef>int <function>sd_event_default</function></funcdef> - <paramdef>sd_bus **<parameter>event</parameter></paramdef> + <paramdef>sd_event **<parameter>event</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>sd_event *<function>sd_event_ref</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> </funcprototype> <funcprototype> - <funcdef>sd_bus *<function>sd_event_ref</function></funcdef> - <paramdef>sd_bus *<parameter>event</parameter></paramdef> + <funcdef>sd_event *<function>sd_event_unref</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> </funcprototype> <funcprototype> - <funcdef>sd_bus *<function>sd_event_unref</function></funcdef> - <paramdef>sd_bus *<parameter>event</parameter></paramdef> + <funcdef>int <function>sd_event_get_tid</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + <paramdef>pid_t *<parameter>tid</parameter></paramdef> </funcprototype> </funcsynopsis> @@ -103,6 +113,17 @@ thread. All threads have exactly either zero or one default event loop objects associated, but never more.</para> + <para>After allocating an event loop object, add event sources to + it with + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry> + or + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + and then execute the event loop using + <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + <para><function>sd_event_ref()</function> increases the reference count of the specified event loop object by one.</para> @@ -117,6 +138,19 @@ 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> + + <para>Both <function>sd_event_ref()</function> and + <function>sd_event_unref()</function> execute no operation if the + passed in event loop object is <constant>NULL</constant>.</para> + + <para><function>sd_event_get_tid()</function> retrieves the thread + identifier ("TID") of the thread the specified event loop object + is associated with. This call is only supported for event loops + allocated with <function>sd_event_default()</function>, and + returns the identifier for the thread the event loop is the + default event loop of. See <citerefentry + project='man-pages'><refentrytitle>gettid</refentrytitle><manvolnum>2</manvolnum></citerefentry> + for more information on thread identifiers.</para> </refsect1> <refsect1> @@ -149,19 +183,20 @@ <listitem><para>The maximum number of event loops has been allocated.</para></listitem> </varlistentry> - </variablelist> - </refsect1> - <refsect1> - <title>Notes</title> + <varlistentry> + <term><constant>-ENXIO</constant></term> - <para><function>sd_event_new()</function> and the other 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> - file.</para> + <listitem><para><function>sd_event_get_tid()</function> was + invoked on an event loop object that was not allocated with + <function>sd_event_default()</function>.</para></listitem> + </varlistentry> + + </variablelist> </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> + <refsect1> <title>See Also</title> @@ -174,7 +209,9 @@ <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>gettid</refentrytitle><manvolnum>2</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_event_now.xml b/man/sd_event_now.xml new file mode 100644 index 0000000000..f577e44c0e --- /dev/null +++ b/man/sd_event_now.xml @@ -0,0 +1,141 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_now" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_now</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_now</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_now</refname> + + <refpurpose>Retrieve current event loop iteration timestamp</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_now</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + <paramdef>clockid_t <parameter>clock</parameter></paramdef> + <paramdef>uint64_t *<parameter>usec</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_now()</function> returns the timestamp + the most recent event loop iteration began. This timestamp is + taken right after after returning from the event sleep, and before + dispatching any event sources. The <parameter>event</parameter> + parameter takes the even loop object to retrieve the timestamp + from. The <parameter>clock</parameter> parameter specifies the clock to + retrieve the timestamp for, and is one of + <constant>CLOCK_REALTIME</constant> (or its equivalent + <constant>CLOCK_REALTIME_ALARM</constant>), + <constant>CLOCK_MONOTONIC</constant> or + <constant>CLOCK_BOOTTIME</constant> (or its equivalent + <constant>CLOCK_BOOTTIME_ALARM</constant>), see <citerefentry + project='man-pages'><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry> + for more information on the various clocks. The retrieved + timestamp is stored in the <parameter>usec</parameter> parameter, + in µs since the clock's epoch. If this function is invoked before + the first event loop iteration the current time is returned, as + reported by <function>clock_gettime()</function>. To distinguish + this case from a regular invocation the return value will be + positive non-zero in this case, while it is zero when the returned + timestamp refers to the actual event loop iteration.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>If the first event loop iteration has not run yet + <function>sd_event_now()</function> returns the requested + timestamp in <parameter>usec</parameter> and returns a positive, + non-zero return value. Otherwise, on success it will return the + iteration's timestamp in <parameter>usec</parameter> and 0 as + return value. On failure, the call returns a negative errno-style + error code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para>An invalid parameter was + passed.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop object was created in a + different process.</para></listitem> + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry project='man-pages'><refentrytitle>clock_gettime</refentrytitle><manvolnum>2</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_run.xml b/man/sd_event_run.xml index 06236fcd1a..5b68959165 100644 --- a/man/sd_event_run.xml +++ b/man/sd_event_run.xml @@ -21,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_run"> +<refentry id="sd_event_run" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_run</title> @@ -46,7 +46,7 @@ <refname>sd_event_run</refname> <refname>sd_event_loop</refname> - <refpurpose>Run the libsystemd event loop</refpurpose> + <refpurpose>Run an event loop</refpurpose> </refnamediv> <refsynopsisdiv> @@ -56,7 +56,7 @@ <funcprototype> <funcdef>int <function>sd_event_run</function></funcdef> <paramdef>sd_event *<parameter>event</parameter></paramdef> - <paramdef>uint64_t <parameter>timeout</parameter></paramdef> + <paramdef>uint64_t <parameter>usec</parameter></paramdef> </funcprototype> <funcprototype> @@ -69,47 +69,60 @@ <refsect1> <title>Description</title> - <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. 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> - - <para><function>sd_event_loop</function> runs - <function>sd_event_wait</function> in a loop with a timeout of - infinity. This makes it suitable for the main event loop of a - program.</para> + <para><function>sd_event_run()</function> may be used to run a single + iteration of the event loop specified in the + <parameter>event</parameter> parameter. The function waits until an event to + process is available, and dispatches the registered handler for + it. The <parameter>usec</parameter> parameter specifies the + maximum time (in microseconds) to wait for an event. Use + <constant>(uint64_t) -1</constant> to specify an infinite + timeout.</para> + + <para><function>sd_event_loop()</function> invokes + <function>sd_event_run()</function> in a loop, thus implementing + the actual event loop. The call returns as soon as exiting was + requested using + <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> <para>The event loop object <parameter>event</parameter> is created with - <function>sd_event_new</function>. - Events to wait for and their handlers can be registered with - <function>sd_event_add_time</function>, - <function>sd_event_add_child</function>, - <function>sd_event_add_signal</function>, - <function>sd_event_add_defer</function>, - <function>sd_event_add_exit</function>, + <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>. + Events sources to wait for and their handlers may be registered + with + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry> and - <function>sd_event_add_post</function>. + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>. </para> - <para>For more fine-grained control, - <function>sd_event_prepare</function>, - <function>sd_event_wait</function>, and - <function>sd_event_dispatch</function> may be used. Along with - <function>sd_event_get_fd</function>, those functions make it - possible to integrate the libsystemd loop inside of another event - loop.</para> + <para>For low-level control of event loop execution, use + <citerefentry><refentrytitle>sd_event_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry> + and + <citerefentry><refentrytitle>sd_event_dispatch</refentrytitle><manvolnum>3</manvolnum></citerefentry> + which are wrapped by <function>sd_event_run()</function>. Along + with + <citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + these functions allow integration of an + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry> + event loop into foreign event loop implementations.</para> </refsect1> <refsect1> <title>Return Value</title> - <para>On success, these functions return 0 or a positive integer. - On failure, they return a negative errno-style error code. - <function>sd_event_run</function> returns 0 if the event loop is - finished, and a positive value if it can be continued.</para> + <para>On failure, these functions return a negative errno-style + error code. <function>sd_event_run()</function> returns a + positive, non-zero integer if an event source was dispatched, and + zero when the specified timeout hit before an event source has + seen any event, and hence no event source was + dispatched. <function>sd_event_loop()</function> returns the exit + code specified when invoking + <function>sd_event_exit()</function>.</para> </refsect1> <refsect1> @@ -122,7 +135,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>The <parameter>event</parameter> parameter is - <constant>NULL</constant>.</para></listitem> + invalid or <constant>NULL</constant>.</para></listitem> </varlistentry> <varlistentry> @@ -153,15 +166,7 @@ <para>Other errors are possible, too.</para> </refsect1> - <refsect1> - <title>Notes</title> - - <para><function>sd_event_run()</function> and - <function>sd_event_loop()</function> 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> - file.</para> - </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> <refsect1> <title>See Also</title> @@ -169,13 +174,15 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <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>, + <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_wait</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <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 deleted file mode 100644 index 1471e12e59..0000000000 --- a/man/sd_event_set_name.xml +++ /dev/null @@ -1,151 +0,0 @@ -<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> -<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" -"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> - -<!-- - This file is part of systemd. - - Copyright 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/>. ---> - -<refentry id="sd_event_set_name" - xmlns:xi="http://www.w3.org/2001/XInclude"> - - <refentryinfo> - <title>sd_event_set_name</title> - <productname>systemd</productname> - - <authorgroup> - <author> - <contrib>More text</contrib> - <firstname>Zbigniew</firstname> - <surname>Jędrzejewski-Szmek</surname> - <email>zbyszek@in.waw.pl</email> - </author> - </authorgroup> - </refentryinfo> - - <refmeta> - <refentrytitle>sd_event_set_name</refentrytitle> - <manvolnum>3</manvolnum> - </refmeta> - - <refnamediv> - <refname>sd_event_set_name</refname> - <refname>sd_event_get_name</refname> - - <refpurpose>Set human-readable names for event sources</refpurpose> - </refnamediv> - - <refsynopsisdiv> - <funcsynopsis> - <funcsynopsisinfo>#include <systemd/sd-bus.h></funcsynopsisinfo> - - <funcprototype> - <funcdef>int <function>sd_event_set_name</function></funcdef> - <paramdef>sd_event_source *<parameter>source</parameter></paramdef> - <paramdef>const char *<parameter>name</parameter></paramdef> - </funcprototype> - - <funcprototype> - <funcdef>int <function>sd_event_get_name</function></funcdef> - <paramdef>sd_event_source *<parameter>source</parameter></paramdef> - <paramdef>const char **<parameter>name</parameter></paramdef> - </funcprototype> - - </funcsynopsis> - </refsynopsisdiv> - - <refsect1> - <title>Description</title> - - <para><function>sd_event_set_name()</function> can be used to set - an arbitrary name for the event source - <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. 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 - <parameter>name</parameter> argument is not referenced after the - function returns.</para> - - <para><function>sd_event_set_name()</function> can be used to - query the current name assigned to source - <parameter>source</parameter>. It returns a pointer to the current - name (possibly <constant>NULL</constant>) in - <parameter>name</parameter>.</para> - </refsect1> - - <refsect1> - <title>Return Value</title> - - <para>On success, <function>sd_event_set_name()</function> and - <function>sd_event_get_name()</function> return a - non-negative integer. On failure, they return a negative - errno-style error code.</para> - </refsect1> - - <refsect1> - <title>Errors</title> - - <para>Returned errors may indicate the following problems:</para> - - <variablelist> - <varlistentry> - <term><constant>-EINVAL</constant></term> - - <listitem><para><parameter>source</parameter> is not a valid - pointer to an <structname>sd_event_source</structname> - structure or the <parameter>name</parameter> argument for - <function>sd_event_get_name()</function> is - <constant>NULL</constant>.</para></listitem> - </varlistentry> - - <varlistentry> - <term><constant>-ENOMEM</constant></term> - - <listitem><para>Not enough memory to copy the - name.</para></listitem> - </varlistentry> - </variablelist> - </refsect1> - - <refsect1> - <title>Notes</title> - - <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> - file.</para> - </refsect1> - - <refsect1> - <title>See Also</title> - - <para> - <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry> - </para> - </refsect1> - -</refentry> diff --git a/man/sd_event_set_watchdog.xml b/man/sd_event_set_watchdog.xml new file mode 100644 index 0000000000..cbc5bc0836 --- /dev/null +++ b/man/sd_event_set_watchdog.xml @@ -0,0 +1,177 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_set_watchdog" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_set_watchdog</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_set_watchdog</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_set_watchdog</refname> + <refname>sd_event_get_watchdog</refname> + + <refpurpose>Enable event loop watchdog support</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_set_watchdog</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + <paramdef>int b</paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_get_watchdog</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_set_watchdog()</function> may be used to + enable or disable automatic watchdog notification support in the + event loop object specified in the <parameter>event</parameter> + parameter. Specifically, depending on the <parameter>b</parameter> + boolean argument this will make sure the event loop wakes up in + regular intervals and sends watchdog notification messages to the + service manager, if this was requested by the service + manager. Watchdog support is determined with + <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + and watchdog messages are sent with + <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. See + the <varname>WatchdogSec=</varname> setting in + <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details on how to enable watchdog support for a service and + the protocol used. The wake-up interval is chosen as half the + watchdog timeout declared by the service manager via the + <varname>$WATCHDOG_USEC</varname> environment variable. If the + service manager did not request watchdog notifications, or if the + process was not invoked by the service manager this call with a + true <parameter>b</parameter> parameter executes no + operation. Passing a false <parameter>b</parameter> parameter will + disable the automatic sending of watchdog notification messages if + it was enabled before. Newly allocated event loop objects have + this feature disabled.</para> + + <para>The first watchdog notification message is sent immediately + when <function>set_event_set_watchdog()</function> is invoked with + a true <parameter>b</parameter> parameter.</para> + + <para>The watchdog logic is designed to allow the service manager + to automatically detect services that ceased processing of + incoming events, and thus appear "hung". Watchdog notifications + are sent out only at the beginning of each event loop + iteration. If an event source dispatch function blocks for an + excessively long time and does not return execution to the event + loop quickly, this might hence cause the notification message to + be delayed, and possibly result in abnormal program termination, + as configured in the service unit file.</para> + + <para><function>sd_event_get_watchdog()</function> may be used to + determine whether watchdog support was previously requested by a + call to <function>sd_event_set_watchdog()</function> with a true + <parameter>b</parameter> parameter and successfully + enabled.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, <function>sd_event_set_watchdog()</function> and + <function>sd_event_get_watchdog()</function> return a non-zero + positive integer if the service manager requested watchdog support + and watchdog support was successfully enabled. They return zero if + the service manager did not request watchdog support, or if + watchdog support was explicitly disabled with a false + <parameter>b</parameter> parameter. On failure, they return a + negative errno-style error + code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop has been created in a different process.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para>The passed event loop object was invalid.</para></listitem> + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_get_event.xml b/man/sd_event_source_get_event.xml new file mode 100644 index 0000000000..2fdbd411bd --- /dev/null +++ b/man/sd_event_source_get_event.xml @@ -0,0 +1,100 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_get_event" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_get_event</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_get_event</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_get_event</refname> + + <refpurpose>Retrieve the event loop of an event source</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>sd_event* <function>sd_event_source_get_event</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_get_event()</function> may be used + to retrieve the event loop object the event source object specified + as <parameter>source</parameter> is associated with. The event + loop object is specified when creating an event source object with + calls such as + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry> + or + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, <function>sd_event_source_get_event()</function> + returns the associated event loop object. On failure, it returns + NULL.</para> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_get_pending.xml b/man/sd_event_source_get_pending.xml new file mode 100644 index 0000000000..1c06e81fe0 --- /dev/null +++ b/man/sd_event_source_get_pending.xml @@ -0,0 +1,167 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_get_pending" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_get_pending</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_get_pending</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_get_pending</refname> + + <refpurpose>Determine pending state of event sources</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_source_get_pending</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_get_pending()</function> may be + used to determine whether the event source object specified as + <parameter>source</parameter> has seen events but has not been + dispatched yet (and thus is marked "pending").</para> + + <para>Event source objects initially are not marked pending, when + they are created with calls such as + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + with the exception of those created with + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry> + which are immediately marked pending, and + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry> + for which the "pending" concept is not defined. For details see + the respective manual pages.</para> + + <para>In each event loop iteration one event source of those + marked pending is dispatched, in the order defined by the event + source priority, as set with + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para> + + <para>For I/O event sources, as created with + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + the call + <citerefentry><refentrytitle>sd_event_get_io_revents</refentrytitle><manvolnum>3</manvolnum></citerefentry> + may be used to query the type of event pending in more + detail.</para> + + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, + <function>sd_event_source_get_pending()</function> returns an + integer greater than zero when the event source is marked pending, + and zero when the event source is not marked pending. On failure, + it returns a negative errno-style error code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para><parameter>source</parameter> is not a valid + pointer to an <structname>sd_event_source</structname> + object.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-EDOM</constant></term> + + <listitem><para><parameter>source</parameter> refers to an + event source object created with + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ENOMEM</constant></term> + + <listitem><para>Not enough memory.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ESTALE</constant></term> + + <listitem><para>The event loop is already terminated.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop has been created in a different process.</para></listitem> + + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_set_description.xml b/man/sd_event_source_set_description.xml new file mode 100644 index 0000000000..b9488a622f --- /dev/null +++ b/man/sd_event_source_set_description.xml @@ -0,0 +1,170 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_set_description" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_set_description</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>More text</contrib> + <firstname>Zbigniew</firstname> + <surname>Jędrzejewski-Szmek</surname> + <email>zbyszek@in.waw.pl</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_set_description</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_set_description</refname> + <refname>sd_event_source_get_description</refname> + + <refpurpose>Set or retrieve descriptive names of event sources</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_source_set_description</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>const char *<parameter>description</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_get_description</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>const char **<parameter>description</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_set_description()</function> may + be used to set an arbitrary descriptive name for the event source + object specified as <parameter>source</parameter>. This name will + be used in debugging messages generated by + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry> + for this event source, and may be queried using + <function>sd_event_source_get_description()</function> for + debugging purposes. The <parameter>description</parameter> parameter shall + point to a <constant>NUL</constant>-terminated string or be + <constant>NULL</constant>. In the latter case, the descriptive + name will be unset. The string is copied internally, hence the + <parameter>description</parameter> argument is not referenced + after the function returns.</para> + + <para><function>sd_event_source_get_description()</function> may + be used to query the current descriptive name assigned to the + event source object <parameter>source</parameter>. It returns a + pointer to the current name in <parameter>description</parameter>, + stored in memory internal to the event source. The memory is + invalidated when the event source is destroyed or the descriptive + name is changed.</para> + + <para>Event source objects generally have no description set when + they are created, except for UNIX signal event sources created + with + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + whose descriptive name is initialized to the signal's C constant + name (e.g. <literal>SIGINT</literal> or + <literal>SIGTERM</literal>).</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, <function>sd_event_source_set_description()</function> and + <function>sd_event_source_get_description()</function> return a + non-negative integer. On failure, they return a negative + errno-style error code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para><parameter>source</parameter> is not a valid + pointer to an <structname>sd_event_source</structname> + object or the <parameter>description</parameter> argument for + <function>sd_event_source_get_description()</function> is + <constant>NULL</constant>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ENOMEM</constant></term> + + <listitem><para>Not enough memory to copy the + name.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop has been created in a different process.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-ENXIO</constant></term> + + <listitem><para>No name was set for the event + source.</para></listitem> + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_set_enabled.xml b/man/sd_event_source_set_enabled.xml new file mode 100644 index 0000000000..74c02e87bb --- /dev/null +++ b/man/sd_event_source_set_enabled.xml @@ -0,0 +1,179 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_set_enabled" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_set_enabled</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_set_enabled</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_set_enabled</refname> + <refname>sd_event_source_get_enabled</refname> + <refname>SD_EVENT_ON</refname> + <refname>SD_EVENT_OFF</refname> + <refname>SD_EVENT_ONESHOT</refname> + + <refpurpose>Enable or disable event sources</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>enum</token> { + <constant>SD_EVENT_OFF</constant> = 0, + <constant>SD_EVENT_ON</constant> = 1, + <constant>SD_EVENT_ONESHOT</constant> = -1, +};</funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_source_set_enabled</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>int <parameter>enabled</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_get_enabled</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>int *<parameter>enabled</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_set_enabled()</function> may be + used to enable or disable the event source object specified as + <parameter>source</parameter>. The <parameter>enabled</parameter> + parameter takes one of <constant>SD_EVENT_ON</constant> (to + enable), <constant>SD_EVENT_OFF</constant> (to disable) or + <constant>SD_EVENT_ONESHOT</constant>. If invoked with + <constant>SD_EVENT_ONESHOT</constant> the event source will be + enabled but automatically reset to + <constant>SD_EVENT_OFF</constant> after the event source was + dispatched once.</para> + + <para>Event sources that are disabled will not result in event + loop wakeups and will not be dispatched, until they are enabled + again.</para> + + <para><function>sd_event_source_get_enabled()</function> may be + used to query whether the event source object + <parameter>source</parameter> is currently enabled or not. It + returns the enablement state in + <parameter>enabled</parameter>.</para> + + <para>Event source objects are enabled when they are first created + with calls such as + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>. However, + depending on the event source type they are enabled continously + (<constant>SD_EVENT_ON</constant>) or only for a single invocation + of the event source handler + (<constant>SD_EVENT_ONESHOT</constant>). For details see the + respective manual pages.</para> + + <para>As event source objects stay active and may be dispatched as + long as there is at least one reference to them, in many cases it + is a good idea to combine a call to + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry> + with a prior call to + <function>sd_event_source_set_enabled()</function> with + <constant>SD_EVENT_OFF</constant>, to ensure the event source is + not dispatched again until all other remaining references are dropped.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, <function>sd_event_source_set_enabled()</function> and + <function>sd_event_source_get_enabled()</function> return a + non-negative integer. On failure, they return a negative + errno-style error code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para><parameter>source</parameter> is not a valid + pointer to an <structname>sd_event_source</structname> + object.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ENOMEM</constant></term> + + <listitem><para>Not enough memory.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop has been created in a different process.</para></listitem> + + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_set_prepare.xml b/man/sd_event_source_set_prepare.xml new file mode 100644 index 0000000000..7066a55306 --- /dev/null +++ b/man/sd_event_source_set_prepare.xml @@ -0,0 +1,171 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_set_prepare" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_set_prepare</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_set_prepare</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_set_prepare</refname> + + <refpurpose>Set a preparation callback for event sources</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_source_set_prepare</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>sd_event_handler_t <parameter>callback</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>typedef int (*<function>sd_event_handler_t</function>)</funcdef> + <paramdef>sd_event_source *<parameter>s</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_set_prepare()</function> may be + used to set a prepartion callback for the event source object + specified as <parameter>source</parameter>. The callback function + specified as <parameter>callback</parameter> will be invoked + immediately before the event loop goes to sleep to wait for + incoming events. It is invoked with the user data pointer passed + when the event source was created. The callback function may be + used to reconfigure the precise events to wait for. If the + <parameter>callback</parameter> parameter is passed as NULL the + callback function is reset. </para> + + <para>Event source objects have no preparation callback associated + when they are first created with calls such as + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Preparation + callback functions are supported for all event source types with + the exception of those created with + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Preparation + callback functions are dispatched in the order indicated by the + event source's priority field, as set with + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Preparation + callbacks of disabled event sources (see + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>) + are not invoked.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, + <function>sd_event_source_set_prepare()</function> returns a + non-negative integer. On failure, it returns a negative + errno-style error code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para><parameter>source</parameter> is not a valid + pointer to an <structname>sd_event_source</structname> + object.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ESTALE</constant></term> + + <listitem><para>The event loop is already terminated.</para></listitem> + + </varlistentry> + <varlistentry> + <term><constant>-ENOMEM</constant></term> + + <listitem><para>Not enough memory.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop has been created in a different process.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-EDOM</constant></term> + + <listitem><para>The specified event source has been created + with + <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem> + + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_priority</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_set_priority.xml b/man/sd_event_source_set_priority.xml new file mode 100644 index 0000000000..cc0f5a0103 --- /dev/null +++ b/man/sd_event_source_set_priority.xml @@ -0,0 +1,189 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_set_priority" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_set_priority</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_set_priority</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_set_priority</refname> + <refname>sd_event_source_get_priority</refname> + <refname>SD_EVENT_PRIORITY_IMPORTANT</refname> + <refname>SD_EVENT_PRIORITY_NORMAL</refname> + <refname>SD_EVENT_PRIORITY_IDLE</refname> + + <refpurpose>Set or retrieve the priority of event sources</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcsynopsisinfo><token>enum</token> { + <constant>SD_EVENT_SOURCE_IMPORTANT</constant> = -100, + <constant>SD_EVENT_SOURCE_NORMAL</constant> = 0, + <constant>SD_EVENT_SOURCE_IDLE</constant> = 100, +};</funcsynopsisinfo> + + <funcprototype> + <funcdef>int <function>sd_event_source_set_priority</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>int64_t <parameter>priority</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>int <function>sd_event_source_get_priority</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>int64_t *<parameter>priority</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_set_priority()</function> may be + used to set the priority for the event source object specified as + <parameter>source</parameter>. The priority is specified as an + arbitrary signed 64bit integer. The priority is initialized to + <constant>SD_EVENT_PRIORITY_NORMAL</constant> (0) when the event + source is allocated with a call such as + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry> + or + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + and may be changed with this call. If multiple event sources have seen events at the same time, they are dispatched in the order indicated by the + event sources' priorities. Event sources with smaller priority + values are dispatched first. As well-known points of reference, + the constants <constant>SD_EVENT_PRIORITY_IMPORTANT</constant> + (-100), <constant>SD_EVENT_PRIORITY_NORMAL</constant> (0) and + <constant>SD_EVENT_PRIORITY_IDLE</constant> (100) may be used to + indicate event sources that shall be dispatched early, normally or + late. It is recommended to specify priorities based on these + definitions, and relative to them -- however, the full 64bit + signed integer range is available for ordering event + sources.</para> + + <para>Priorities define the order in which event sources that have + seen events are dispatched. Care should be taken to ensure that + high-priority event sources (those with negative priority values + assigned) do not cause starvation of low-priority event sources + (those with positive priority values assigned).</para> + + <para>The order in which event sources with the same priority are + dispatched is undefined, but the event loop generally tries to + dispatch them in the order it learnt about events on them. As the + backing kernel primitives do not provide accurate information + about the order in which events occured this is not necessarily + reliable. However, it is guaranteed that if events are seen on + multiple same-priority event sources at the same time, each one is + not dispatched again until all others have been dispatched + once. This behaviour guarantees that within each priority + particular event sources do not starve or dominate the event + loop.</para> + + <para><function>sd_event_source_get_priority()</function> may be + used to query the current priority assigned to the event source + object <parameter>source</parameter>.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, + <function>sd_event_source_set_priority()</function> and + <function>sd_event_source_get_priority()</function> return a + non-negative integer. On failure, they return a negative + errno-style error code.</para> + </refsect1> + + <refsect1> + <title>Errors</title> + + <para>Returned errors may indicate the following problems:</para> + + <variablelist> + <varlistentry> + <term><constant>-EINVAL</constant></term> + + <listitem><para><parameter>source</parameter> is not a valid + pointer to an <structname>sd_event_source</structname> + object.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ENOMEM</constant></term> + + <listitem><para>Not enough memory.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>-ESTALE</constant></term> + + <listitem><para>The event loop is already terminated.</para></listitem> + + </varlistentry> + + <varlistentry> + <term><constant>-ECHILD</constant></term> + + <listitem><para>The event loop has been created in a different process.</para></listitem> + + </varlistentry> + + </variablelist> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_set_userdata.xml b/man/sd_event_source_set_userdata.xml new file mode 100644 index 0000000000..533d491b13 --- /dev/null +++ b/man/sd_event_source_set_userdata.xml @@ -0,0 +1,119 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_set_userdata" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_set_userdata</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_set_userdata</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_set_userdata</refname> + <refname>sd_event_source_get_userdata</refname> + + <refpurpose>Set or retrieve user data pointer of event sources</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>void* <function>sd_event_source_set_userdata</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + <paramdef>void *<parameter>userdata</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>void* <function>sd_event_source_get_userdata</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_set_userdata()</function> may be + used to set an arbitrary user data pointer for the event source + object specified as <parameter>source</parameter>. The user data + pointer is usually specified when creating an event source object + with calls such as + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry> + or + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + and may be updated with this call. The user data pointer is also + passed to all handler callback functions associated with the event + source. The <parameter>userdata</parameter> parameter specifies + the new user data pointer to set, the function returns the + previous user data pointer. Note that <constant>NULL</constant> is + a valid user data pointer.</para> + + <para><function>sd_event_source_get_userdata()</function> may be + used to query the current user data pointer assigned to the event + source object <parameter>source</parameter>.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para>On success, + <function>sd_event_source_set_userdata()</function> and + <function>sd_event_source_get_userdata()</function> return the + previously set user data pointer. On failure, they return + NULL.</para> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_description</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_source_unref.xml b/man/sd_event_source_unref.xml new file mode 100644 index 0000000000..579ec47e8e --- /dev/null +++ b/man/sd_event_source_unref.xml @@ -0,0 +1,125 @@ +<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" +"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> + +<!-- + This file is part of systemd. + + Copyright 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/>. +--> + +<refentry id="sd_event_source_unref" xmlns:xi="http://www.w3.org/2001/XInclude"> + + <refentryinfo> + <title>sd_event_source_unref</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>sd_event_source_unref</refentrytitle> + <manvolnum>3</manvolnum> + </refmeta> + + <refnamediv> + <refname>sd_event_source_unref</refname> + <refname>sd_event_source_ref</refname> + + <refpurpose>Increase or decrease event source reference counters</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + + <funcprototype> + <funcdef>sd_event_source* <function>sd_event_source_unref</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + </funcprototype> + + <funcprototype> + <funcdef>sd_event_source* <function>sd_event_source_ref</function></funcdef> + <paramdef>sd_event_source *<parameter>source</parameter></paramdef> + </funcprototype> + + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><function>sd_event_source_unref()</function> may be used to + decrement by one the reference counter of the event source object + specified as <parameter>source</parameter>. The reference counter + is initially set to one, when the event source is created with calls + such as + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry> + or + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>. When + the reference counter reaches zero it is removed from its event loop + object and destroyed.</para> + + <para><function>sd_event_source_ref()</function> may be used + to increase by one the reference counter of the event source object + specified as <parameter>source</parameter>.</para> + + <para>Both functions execute no operation if the passed event + source object is <constant>NULL</constant>.</para> + + <para>Note that event source objects stay alive and may be + dispatched as long as they have a reference counter greater than + zero. In order to drop a reference of an event source and make + sure the associated event source handler function is not called + anymore it is recommended to combine a call of + <function>sd_event_source_unref()</function> with a prior call to + <function>sd_event_source_set_enabled()</function> with + <constant>SD_EVENT_OFF</constant>.</para> + </refsect1> + + <refsect1> + <title>Return Value</title> + + <para><function>sd_event_source_unref()</function> always returns + <constant>NULL</constant>. + <function>sd_event_source_ref()</function> always returns the + event source object passed in.</para> + </refsect1> + + <xi:include href="libsystemd-pkgconfig.xml" /> + + <refsect1> + <title>See Also</title> + + <para> + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_child</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml index 7ca50aedf9..1eefa80700 100644 --- a/man/sd_event_wait.xml +++ b/man/sd_event_wait.xml @@ -21,7 +21,7 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. --> -<refentry id="sd_event_wait"> +<refentry id="sd_event_wait" xmlns:xi="http://www.w3.org/2001/XInclude"> <refentryinfo> <title>sd_event_wait</title> @@ -46,14 +46,32 @@ <refname>sd_event_wait</refname> <refname>sd_event_prepare</refname> <refname>sd_event_dispatch</refname> - - <refpurpose>Run parts of the libsystemd event loop</refpurpose> + <refname>sd_event_get_state</refname> + <refname>SD_EVENT_INITIAL</refname> + <refname>SD_EVENT_PREPARING</refname> + <refname>SD_EVENT_ARMED</refname> + <refname>SD_EVENT_PENDING</refname> + <refname>SD_EVENT_RUNNING</refname> + <refname>SD_EVENT_EXITING</refname> + <refname>SD_EVENT_FINISHED</refname> + + <refpurpose>Low-level event loop operations</refpurpose> </refnamediv> <refsynopsisdiv> <funcsynopsis> <funcsynopsisinfo>#include <systemd/sd-event.h></funcsynopsisinfo> + <funcsynopsisinfo><token>enum</token> { + <constant>SD_EVENT_INITIAL</constant>, + <constant>SD_EVENT_PREPARING</constant>, + <constant>SD_EVENT_ARMED</constant>, + <constant>SD_EVENT_PENDING</constant>, + <constant>SD_EVENT_RUNNING</constant>, + <constant>SD_EVENT_EXITING</constant>, + <constant>SD_EVENT_FINISHED</constant>, +};</funcsynopsisinfo> + <funcprototype> <funcdef>int <function>sd_event_prepare</function></funcdef> <paramdef>sd_event *<parameter>event</parameter></paramdef> @@ -62,7 +80,7 @@ <funcprototype> <funcdef>int <function>sd_event_wait</function></funcdef> <paramdef>sd_event *<parameter>event</parameter></paramdef> - <paramdef>uint64_t <parameter>timeout</parameter></paramdef> + <paramdef>uint64_t <parameter>usec</parameter></paramdef> </funcprototype> <funcprototype> @@ -70,66 +88,184 @@ <paramdef>sd_event *<parameter>event</parameter></paramdef> </funcprototype> + <funcprototype> + <funcdef>int <function>sd_event_get_state</function></funcdef> + <paramdef>sd_event *<parameter>event</parameter></paramdef> + </funcprototype> + </funcsynopsis> </refsynopsisdiv> <refsect1> <title>Description</title> - <para>Functions described here form parts of an event loop.</para> - - <para><function>sd_event_prepare</function> checks for pending + <para>The low-level <function>sd_event_prepare()</function>, + <function>sd_event_wait()</function> and + <function>sd_event_dispatch()</function> functions may be used to + execute specific phases of an event loop. See + <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry> + and + <citerefentry><refentrytitle>sd_event_loop</refentrytitle><manvolnum>3</manvolnum></citerefentry> + for higher-level functions that execute individual but complete + iterations of an event loop or run it continously.</para> + + <para><function>sd_event_prepare()</function> checks for pending events and arms necessary timers. If any events are ready to be - processed, it returns a positive value, and the events should be - processed with <function>sd_event_dispatch</function>. - <function>sd_event_dispatch</function> runs a handler for one of - the events from the sources with the highest priority. On success, - <function>sd_event_dispatch</function> returns either 0, which - means that the loop is finished, or a positive value, which means - that the loop is again in the initial state and - <function>sd_event_prepare</function> should be called again. - </para> + processed ("pending"), it returns a positive, non-zero value, and the caller + should process these events with + <function>sd_event_dispatch()</function>.</para> + + <para><function>sd_event_dispatch()</function> dispatches the + highest priority event source that has a pending event. On + success, <function>sd_event_dispatch()</function> returns either + zero, which indicates that no further event sources may be + dispatched and exiting of the event loop was requested via + <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>; + or a positive non-zero value, which means that an event source was + dispatched and the loop returned to its initial state, and the + caller should initiate the next event loop iteration by invoking + <function>sd_event_prepare()</function> again.</para> + + <para>In case <function>sd_event_prepare()</function> returned + zero, <function>sd_event_wait()</function> should be called to + wait for further events or a timeout. If any events are ready to + be processed, it returns a positive, non-zero value, and the + events should be dispatched with + <function>sd_event_dispatch()</function>. Otherwise, the event + loop returned to its initial state and the next event loop + iteration should be initiated by invoking + <function>sd_event_prepare()</function> again.</para> + + <para><function>sd_event_get_state()</function> may be used to + determine the state the event loop is currently in. It returns one + of the states described below.</para> + + <para>All four functions take, as the first argument, the event + loop object <parameter>event</parameter> that has been created + with <function>sd_event_new()</function>. The timeout for + <function>sd_event_wait()</function> is specified in + <parameter>usec</parameter> in milliseconds. <constant>(uint64_t) + -1</constant> may be used to specify an infinite timeout.</para> +</refsect1> + + <refsect1> + <title>State Machine</title> + + <para>The event loop knows the following states, that may be + queried with <function>sd_event_get_state()</function>.</para> - <para>In case <function>sd_event_prepare</function> returned 0, - <function>sd_event_wait</function> should be called to wait for - events or a timeout. If any events are ready to be processed, it - returns a positive value, and the events should be processed with - <function>sd_event_dispatch</function>. Otherwise, the loop is - back in the initial state and <function>sd_event_prepare</function> - should be called again.</para> + <variablelist> + <varlistentry> + <term><constant>SD_EVENT_INITIAL</constant></term> + + <listitem><para>The initial state the event loop is in, + before each event loop iteration. Use + <function>sd_event_prepare()</function> to transition the + event loop into the <constant>SD_EVENT_ARMED</constant> or + <constant>SD_EVENT_PENDING</constant> states.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>SD_EVENT_PREPARING</constant></term> + + <listitem><para>An event source is currently being prepared, + i.e. the preparation handler is currently being excuted, as + set with + <citerefentry><refentrytitle>sd_event_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This + state is only seen in the event source preparation handler + that is invoked from the + <function>sd_event_prepare()</function> call and is + immediately followed by <constant>SD_EVENT_ARMED</constant> or + <constant>SD_EVENT_PENDING</constant>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>SD_EVENT_ARMED</constant></term> + + <listitem><para><function>sd_event_prepare()</function> has + been called and no event sources were ready to be + dispatched. Use <function>sd_event_wait()</function> to wait + for new events, and transition into + <constant>SD_EVENT_PENDING</constant> or back into + <constant>SD_EVENT_INITIAL</constant>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>SD_EVENT_PENDING</constant></term> + + <listitem><para><function>sd_event_prepare()</function> or + <function>sd_event_wait()</function> have been called and + there were event sources with events pending. Use + <function>sd_event_dispatch()</function> to dispatch the + highest priority event source and transition back to + <constant>SD_EVENT_INITIAL</constant>, or + <constant>SD_EVENT_FINISHED</constant>.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>SD_EVENT_RUNNING</constant></term> + + <listitem><para>A regular event source is currently being + dispatched. This state is only seen in the event source + handler that is invoked from the + <function>sd_event_dispatch()</function> call, and is + immediately followed by <constant>SD_EVENT_INITIAL</constant> + or <constant>SD_EVENT_FINISHED</constant> as soon the event + source handler returns. Note that during dispatching of exit + event sources the <constant>SD_EVENT_EXITING</constant> state + is seen instead.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>SD_EVENT_EXITING</constant></term> + + <listitem><para>Similar to + <constant>SD_EVENT_RUNNING</constant> but is the state in + effect while dispatching exit event sources. It is followed by + <constant>SD_EVENT_INITIAL</constant> or + <constant>SD_EVENT_FINISHED</constant> as soon as the event + handler returns.</para></listitem> + </varlistentry> + + <varlistentry> + <term><constant>SD_EVENT_FINISHED</constant></term> + + <listitem><para>The event loop has exited. All exit event + sources have run. If the event loop is in this state it serves + no purpose anymore, and should be freed.</para></listitem> + </varlistentry> + + </variablelist> + + <para>A simplified flow chart of the states and the calls to + transition between them is shown below. Note that + <constant>SD_EVENT_PREPARING</constant>, + <constant>SD_EVENT_RUNNING</constant> and + <constant>SD_EVENT_EXITING</constant> are not shown here.</para> <programlisting> - ┌──────────┐ - │ initial ├──←←←←←←←←←←←←←←←←←←←─┐ - └───┬──────┘ ↑ - │ ↑ - sd_event_prepare ┌─────────┐ ↑ - ├ 0 →→→→→→→──┤ armed │ ↑ - 1 └───┬─────┘ ↑ - ↓ │ ↑ - ↓ sd_event_wait ↑ - ├───←←←←←←←─── 1 ┴─ 0 →→→→→→→─┘ - ┌───┴──────┐ ↑ - │ pending │ ↑ - └───┬──────┘ ↑ - │ ↑ - sd_event_dispatch ↑ - ↓ ↑ - ├ 1 ──────────→→→→→→→─────────┘ - 0 - ↓ - ┌───┴──────┐ - │ finished │ - └──────────┘ + INITIAL -<---<---<---<---<---<---<---<---<---<---<---<---\ + | | + | ^ + | | + v ret == 0 | + sd_event_prepare() >--->--->--->--->- ARMED | + | | ^ + | ret > 0 | | + | | | + v v ret == 0 | + PENDING <---<---<---<---<---< sd_event_wait() >--->--->--+ + | ret > 0 ^ + | | + | | + v | + sd_event_dispatch() >--->--->--->--->--->--->--->--->--->--->/ + | ret > 0 + | ret == 0 + | + v + FINISHED </programlisting> - - <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. - <constant>(uint64_t) -1</constant> may be used to specify an - infinite timeout.</para> </refsect1> <refsect1> @@ -137,13 +273,15 @@ <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 - events are ready to be processed and 0 means that no events are - 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 these functions, a - negative return value means the loop must be aborted.</para> + of <function>sd_event_prepare()</function> and + <function>sd_event_wait()</function>, a positive, non-zero return + code indicates that events are ready to be processed and zero + indicates that no events are ready. In case of + <function>sd_event_dispatch()</function>, a positive, non-zero + return code indicates that the event loop returned to its initial + state and zero indicates the event loop has + exited. <function>sd_event_get_state()</function> returns a + positive or zero state on success.</para> </refsect1> <refsect1> @@ -156,7 +294,7 @@ <term><constant>-EINVAL</constant></term> <listitem><para>The <parameter>event</parameter> parameter is - <constant>NULL</constant>.</para></listitem> + invalid or <constant>NULL</constant>.</para></listitem> </varlistentry> <varlistentry> @@ -185,14 +323,7 @@ <para>Other errors are possible, too.</para> </refsect1> - <refsect1> - <title>Notes</title> - - <para>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> - file.</para> - </refsect1> + <xi:include href="libsystemd-pkgconfig.xml" /> <refsect1> <title>See Also</title> @@ -200,13 +331,15 @@ <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>, <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>. + <citerefentry><refentrytitle>sd_event_add_post</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_run</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_get_fd</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_source_set_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_watchdog_enabled.xml b/man/sd_watchdog_enabled.xml index 144ab1db61..6e27528a71 100644 --- a/man/sd_watchdog_enabled.xml +++ b/man/sd_watchdog_enabled.xml @@ -98,6 +98,11 @@ <varname>WatchdogSec=</varname> in service files. See <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details.</para> + + <para>Use + <citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry> + to enable automatic watchdog support in + <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>-based event loops.</para> </refsect1> <refsect1> @@ -168,7 +173,8 @@ <citerefentry><refentrytitle>sd-daemon</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_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>, + <citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/systemctl.xml b/man/systemctl.xml index 755a74f987..1fb056874c 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -888,6 +888,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service <para>Example: <command>systemctl set-property foobar.service CPUShares=777</command></para> + <para>If the specified unit appears to be inactive, the + changes will be only stored on disk as described + previously hence they will be effective when the unit will + be started.</para> + <para>Note that this command allows changing multiple properties at the same time, which is preferable over setting them individually. Like unit file configuration diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml index f1054b03bb..2810638bc2 100644 --- a/man/systemd-journald.service.xml +++ b/man/systemd-journald.service.xml @@ -106,13 +106,6 @@ <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 - <constant>AF_UNIX</constant>/<constant>SOCK_DGRAM</constant> - socket <filename>/run/systemd/journal/syslog</filename>, if it - exists, which may be used by Unix syslog daemons to process the - data further.</para> - <para>See <citerefentry><refentrytitle>journald.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> for information about the configuration of this service.</para> diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index 54ce992b85..edc6df914a 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.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"> @@ -317,7 +317,20 @@ <varname>MemoryAccounting=</varname> and <varname>TasksAccounting=</varname>. See <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> - for details on the per-unit settings.</para></listitem> + for details on the per-unit + settings. <varname>DefaulTasksAccounting=</varname> defaults + to on, the other three settings to off.</para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>DefaultTasksMax=</varname></term> + + <listitem><para>Configure the default value for the per-unit + <varname>TasksMax=</varname> setting. See + <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry> + for details. This setting applies to all unit types that + support resource control settings, with the exception of slice + units. Defaults to 512.</para></listitem> </varlistentry> <varlistentry> @@ -341,13 +354,26 @@ <listitem><para>These settings control various default 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. 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 + for details. The resource limit is possible to specify in two formats, + <option>value</option> to set soft and hard limits to the same value, + or <option>soft:hard</option> to set both limits individually (e.g. DefaultLimitAS=4G:16G). + Use the string <varname>infinity</varname> to + 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). For the limits referring to time values, + the usual time units ms, s, min, h and so on may be used (see + <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry> + for details). Note that if no time unit is specified for + <varname>DefaultLimitCPU=</varname> the default unit of seconds is + implied, while for <varname>DefaultLimitRTTIME=</varname> the default + unit of microseconds is implied. Also, note that the effective + granularity of the limits might influence their + enforcement. For example, time limits specified for + <varname>DefaultLimitCPU=</varname> will be rounded up implicitly to + multiples of 1s. 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> </varlistentry> </variablelist> diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 6dda6c5e69..5f98ef163c 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -630,7 +630,10 @@ <listitem><para>These settings set both soft and hard limits of various resources for executed processes. See <citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry> - for details. Use the string <varname>infinity</varname> to + for details. The resource limit is possible to specify in two formats, + <option>value</option> to set soft and hard limits to the same value, + or <option>soft:hard</option> to set both limits individually (e.g. LimitAS=4G:16G). + Use the string <varname>infinity</varname> to 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 @@ -1381,6 +1384,7 @@ <varlistentry> <term><varname>$LISTEN_FDS</varname></term> <term><varname>$LISTEN_PID</varname></term> + <term><varname>$LISTEN_FDNAMES</varname></term> <listitem><para>Information about file descriptors passed to a service for socket activation. See @@ -1389,6 +1393,24 @@ </varlistentry> <varlistentry> + <term><varname>$NOTIFY_SOCKET</varname></term> + + <listitem><para>The socket + <function>sd_notify()</function> talks to. See + <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>. + </para></listitem> + </varlistentry> + + <varlistentry> + <term><varname>$WATCHDOG_PID</varname></term> + <term><varname>$WATCHDOG_USEC</varname></term> + + <listitem><para>Information about watchdog keep-alive notifications. See + <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>. + </para></listitem> + </varlistentry> + + <varlistentry> <term><varname>$TERM</varname></term> <listitem><para>Terminal type, set only for units connected to @@ -1402,8 +1424,8 @@ <para>Additional variables may be configured by the following means: for processes spawned in specific units, use the - <varname>Environment=</varname> and - <varname>EnvironmentFile=</varname> options above; to specify + <varname>Environment=</varname>, <varname>EnvironmentFile=</varname> + and <varname>PassEnvironment=</varname> options above; to specify variables globally, use <varname>DefaultEnvironment=</varname> (see <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index a724d88584..4a8d265fed 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -88,7 +88,8 @@ configured in a unit file <filename>home-lennart.mount</filename>. For details about the escaping logic used to convert a file system path to a unit name, see - <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> + <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. + Note that mount units cannot be templated.</para> <para>Optionally, a mount unit may be accompanied by an automount unit, to allow on-demand or parallelized mounting. See diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 0497f60546..b1106c759d 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -241,7 +241,10 @@ see <ulink url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para> - <para>Implies <literal>TasksAccounting=true</literal>.</para> + <para>Implies <literal>TasksAccounting=true</literal>. The + system default for this setting may be controlled with + <varname>DefaultTasksMax=</varname> in + <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para> </listitem> </varlistentry> diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 20a71afe59..b998a1f81f 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -506,7 +506,8 @@ larger than the configured time, then the service is placed in a failed state and it will be terminated with <constant>SIGABRT</constant>. By setting - <varname>Restart=</varname> to <option>on-failure</option> or + <varname>Restart=</varname> to <option>on-failure</option>, + <option>on-watchdog</option>, <option>on-abnormal</option> or <option>always</option>, the service will be automatically restarted. The time configured here will be passed to the executed service process in the @@ -521,7 +522,9 @@ check whether the service manager expects watchdog keep-alive notifications. See <citerefentry><refentrytitle>sd_watchdog_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry> - for details. + for details. + <citerefentry><refentrytitle>sd_event_set_watchdog</refentrytitle><manvolnum>3</manvolnum></citerefentry> + may be used to enable automatic watchdog notification support. </para></listitem> </varlistentry> @@ -678,8 +681,10 @@ <constant>SIGPIPE</constant>. Exit status definitions can either be numeric exit codes or termination signal names, separated by spaces. For example: - <programlisting>SuccessExitStatus=1 2 8 - SIGKILL</programlisting> ensures that exit codes 1, 2, 8 and + + <programlisting>SuccessExitStatus=1 2 8 SIGKILL</programlisting> + + ensures that exit codes 1, 2, 8 and the termination signal <constant>SIGKILL</constant> are considered clean service terminations. </para> @@ -711,14 +716,16 @@ signal names, and are separated by spaces. Defaults to the empty list, so that, by default, no exit status is excluded from the configured restart logic. For example: - <programlisting>RestartPreventExitStatus=1 6 - SIGABRT</programlisting> ensures that exit codes 1 and 6 and - the termination signal <constant>SIGABRT</constant> will not - result in automatic service restarting. This option may appear - more than once, in which case the list of restart-preventing - statuses is merged. If the empty string is assigned to this - option, the list is reset and all prior assignments of this - option will have no effect.</para></listitem> + + <programlisting>RestartPreventExitStatus=1 6 SIGABRT</programlisting> + + ensures that exit codes 1 and 6 and the termination signal + <constant>SIGABRT</constant> will not result in automatic + service restarting. This option may appear more than once, in + which case the list of restart-preventing statuses is + merged. If the empty string is assigned to this option, the + list is reset and all prior assignments of this option will + have no effect.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index beac053bf0..43841c2399 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -311,6 +311,15 @@ </varlistentry> <varlistentry> + <term><varname>SocketProtocol=</varname></term> + <listitem><para>Takes a one of <option>udplite</option> + or <option>sctp</option>. Specifies a socket protocol + (<constant>IPPROTO_UDPLITE</constant>) UDP-Lite + (<constant>IPPROTO_SCTP</constant>) SCTP socket respectively. </para> + </listitem> + </varlistentry> + + <varlistentry> <term><varname>BindIPv6Only=</varname></term> <listitem><para>Takes a one of <option>default</option>, <option>both</option> or <option>ipv6-only</option>. Controls diff --git a/man/systemd.time.xml b/man/systemd.time.xml index 135eb35f1b..ffcac82263 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -82,8 +82,8 @@ <listitem><para>hours, hour, hr, h</para></listitem> <listitem><para>days, day, d</para></listitem> <listitem><para>weeks, week, w</para></listitem> - <listitem><para>months, month</para></listitem> - <listitem><para>years, year, y</para></listitem> + <listitem><para>months, month, M (defined as 30.44 days)</para></listitem> + <listitem><para>years, year, y (define as 365.25 days)</para></listitem> </itemizedlist> <para>If no time unit is specified, generally seconds are assumed, @@ -229,6 +229,10 @@ the value and all values plus multiples of the repetition value are matched.</para> + <para>The seconds component may contain decimal fractions both in + the value and the repetition. All fractions are rounded to 6 + decimal places.</para> + <para>Either time or date specification may be omitted, in which case the current day and 00:00:00 is implied, respectively. If the second component is not specified, <literal>:00</literal> is @@ -276,6 +280,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 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 +05:40:23.4200004/3.1700005 → 05:40:23.420000/3.170001 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 diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 8cf6c4683b..cfa13015b0 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -190,13 +190,12 @@ <varname>OnUnitInactiveSec=</varname> and ending the time configured with <varname>AccuracySec=</varname> later. Within this time window, the expiry time will be placed at a - host-specific, randomized but stable position that is + host-specific, randomized, but stable position that is synchronized between all local timer units. This is done in - order to distribute the wake-up time in networked - installations, as well as optimizing power consumption to - suppress unnecessary CPU wake-ups. To get best accuracy, set - this option to 1us. Note that the timer is still subject to - the timer slack configured via + order to optimize power consumption to suppress unnecessary + CPU wake-ups. To get best accuracy, set this option to + 1us. Note that the timer is still subject to the timer slack + configured via <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>'s <varname>TimerSlackNSec=</varname> setting. See <citerefentry><refentrytitle>prctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> @@ -204,6 +203,38 @@ this value as high as possible and as low as necessary.</para></listitem> </varlistentry> + + <varlistentry> + <term><varname>RandomizedDelaySec=</varname></term> + + <listitem><para>Delay the timer by a randomly selected, evenly + distributed amount of time between 0 and the specified time + value. Defaults to 0, indicating that no randomized delay + shall be applied. Each timer unit will determine this delay + randomly each time it is started, and the delay will simply be + added on top of the next determined elapsing time. This is + useful to stretch dispatching of similarly configured timer + events over a certain amount time, to avoid that they all fire + at the same time, possibly resulting in resource + congestion. Note the relation to + <varname>AccuracySec=</varname> above: the latter allows the + service manager to coalesce timer events within a specified + time range in order to minimize wakeups, the former does the + opposite: it stretches timer events over a time range, to make + it unlikely that they fire simultaneously. If + <varname>RandomizedDelaySec=</varname> and + <varname>AccuracySec=</varname> are used in conjunction, first + the randomized delay is added, and then the result is + possibly further shifted to coalesce it with other timer + events happening on the system. As mentioned above + <varname>AccuracySec=</varname> defaults to 1min and + <varname>RandomizedDelaySec=</varname> to 0, thus encouraging + coalescing of timer events. In order to optimally stretch + timer events over a certain range of time, make sure to set + <varname>RandomizedDelaySec=</varname> to a higher value, and + <varname>AccuracySec=1us</varname>.</para></listitem> + </varlistentry> + <varlistentry> <term><varname>Unit=</varname></term> @@ -243,6 +274,24 @@ again after any work that is to be done is finished. Defaults to <varname>false</varname>.</para></listitem> </varlistentry> + + <varlistentry> + <term><varname>RemainAfterElapse=</varname></term> + + <listitem><para>Takes a boolean argument. If true, an elapsed + timer will stay loaded, and its state remains queriable. If + false, an elapsed timer unit that cannot elapse anymore is + unloaded. Turning this off is particularly useful for + transient timer units that shall disappear after they first + elapse. Note that this setting has an effect on repeatedly + starting the a timer unit that only elapses once: if + <varname>RemainAfterElapse=</varname> is on, it will not be + started again, and is guaranteed to elapse only once. However, + if <varname>RemainAfterLeapse=</varname> is off, it might be + started again if it is already elapsed, and thus be triggered + multiple times. Defaults to + <varname>yes</varname>.</para></listitem> + </varlistentry> </variablelist> </refsect1> diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 3f6128cb5b..5bf1f2956b 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -169,13 +169,15 @@ <varlistentry> <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>. 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> + exist yet, the file system supports subvolumes (btrfs), and + the system itself is installed into a subvolume + (specifically: the root directory <filename>/</filename> is + itself a subvolume). 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> @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2014-04-29 09:17+0300\n" "Last-Translator: Dimitris Spingos (Δημήτρης Σπίγγος) <dmtrs32@gmail.com>\n" "Language-Team: team@lists.gnome.gr\n" @@ -451,6 +451,15 @@ msgid "" "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 "" @@ -461,20 +470,68 @@ msgid "Authentication is required to log into a local container." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 -msgid "Manage local virtual machines and containers" +msgid "Log into the local host" msgstr "" #: ../src/machine/org.freedesktop.machine1.policy.in.h:4 #, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +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 +#, fuzzy +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 +#, fuzzy msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "Απαιτείται πιστοποίηση για να ορίσετε πληροφορίες τοπικής μηχανής." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../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:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 #, fuzzy msgid "" "Authentication is required to manage local virtual machine and container " @@ -520,3 +577,38 @@ msgid "" msgstr "" "Απαιτείται πιστοποίηση για να ελέγξετε αν ο συγχρονισμός ώρας δικτύου θα " "ενεργοποιηθεί." + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-04-24 13:26+0200\n" "Last-Translator: Álex Puchades <alex94puchades@gmail.com>\n" "Language-Team: Español; Castellano <gnome-es-list@gnome.org>\n" @@ -446,6 +446,15 @@ msgstr "" "Se requiere autenticación para indicar al firmware que arranque la interfaz " "de configuración." +#: ../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 "Se requiere autenticación para establecer el nombre de equipo local." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Conectarse a un contenedor local" @@ -455,21 +464,70 @@ msgid "Authentication is required to log into a local container." msgstr "Se requiere autenticación para conectarse a un contenedor local." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Conectarse a un contenedor local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Conectarse a un contenedor local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Se requiere autenticación para establecer el nombre de equipo local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Conectarse a un contenedor local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Se requiere autenticación para establecer el nombre de equipo local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "Administrar máquinas virtuales y contenedores locales" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "" "Se requiere autenticación para administrar las máquinas virtuales y los " "contenedores locales." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "Administrar imágenes de máquina virtual y de contenedor locales" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -517,6 +575,41 @@ msgstr "" "Se requiere autenticación para activar/desactivar la sincronización de hora " "por red." +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Se requiere autenticación para recargar el estado de systemd." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Se requiere autenticación para establecer el nombre de equipo local." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + #~ msgid "Press Ctrl+C to cancel all filesystem checks in progress" #~ msgstr "" #~ "Presione Ctrl+C para cancelar todas las comprobaciones del sistema de " @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-01-02 22:58+0100\n" "Last-Translator: Gabor Kelemen <kelemeng at ubuntu dot com>\n" "Language-Team: Hungarian <openscope at googlegroups dot com>\n" @@ -439,6 +439,15 @@ msgid "" "interface." msgstr "Hitelesítés szükséges a helyi gépnév beállításához." +#: ../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 "Hitelesítés szükséges a helyi gépnév beállításához." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Bejelentkezés helyi konténerbe" @@ -449,20 +458,69 @@ msgid "Authentication is required to log into a local container." msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Bejelentkezés helyi konténerbe" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Bejelentkezés helyi konténerbe" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Hitelesítés szükséges a helyi gépnév beállításához." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Bejelentkezés helyi konténerbe" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Hitelesítés szükséges a helyi gépnév beállításához." + +#: ../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:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 #, fuzzy msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "Hitelesítés szükséges a helyi gép információinak beállításához." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../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:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 #, fuzzy msgid "" "Authentication is required to manage local virtual machine and container " @@ -506,3 +564,38 @@ msgid "" "Authentication is required to control whether network time synchronization " "shall be enabled." msgstr "Hitelesítés szükséges a hálózati időszinkronizáció engedélyezéséhez." + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Hitelesítés szükséges a rendszeridő beállításához." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Hitelesítés szükséges a rendszeridő beállításához." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Hitelesítés szükséges a systemd állapotának újratöltéséhez." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Hitelesítés szükséges a rendszeridő beállításához." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Hitelesítés szükséges a helyi gépnév beállításához." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Hitelesítés szükséges a rendszeridő beállításához." @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" -"PO-Revision-Date: 2015-06-10 23:10+0100\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" +"PO-Revision-Date: 2015-11-22 16:54+0100\n" "Last-Translator: Daniele Medri <dmedri@gmail.com>\n" "Language-Team: Italian\n" "Language: it\n" @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.7.6\n" +"X-Generator: Poedit 1.8.5\n" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 msgid "Send passphrase back to system" @@ -443,6 +443,14 @@ msgstr "" "Autenticazione richiesta per indicare al firmware di avviare l'interfaccia " "di configurazione." +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "Configura un messaggio per gli utenti" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +msgid "Authentication is required to set a wall message" +msgstr "Autenticazione richiesta per configurare un messaggio per gli utenti" + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Accedi in un container locale" @@ -452,20 +460,62 @@ msgid "Authentication is required to log into a local container." msgstr "Autenticazione richiesta per accedere in un container locale." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +msgid "Log into the local host" +msgstr "Accedi in un host locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +msgid "Authentication is required to log into the local host." +msgstr "Autenticazione richiesta per accedere in un host locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +msgid "Acquire a shell in a local container" +msgstr "Apri una shell in un container locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Autenticazione richiesta per aprire una shell in un container locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "Apri una shell in un host locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Autenticazione richiesta per aprire una shell in un host locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Apri un pseudo TTY in un container locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" +"Autenticazione richiesta per aprire un pseudo TTY in un container locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Apri un pseudo TTY in un host locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Autenticazione richiesta per aprire un pseudo TTY in un host locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "Gestisci le virtual machine e i container locali" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "" "Autenticazione richiesta per gestire le virtual machine e i container locali." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "Gestisci le immagini locali delle virtual machine e dei container" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -514,3 +564,32 @@ msgid "" msgstr "" "Autenticazione richiesta per verificare se la sincronizzazione dell'orario " "in rete possa essere attivata." + +#: ../src/core/dbus-unit.c:428 +msgid "Authentication is required to start '$(unit)'." +msgstr "Autenticazione richiesta per avviare '$(unit)'." + +#: ../src/core/dbus-unit.c:429 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Autenticazione richiesta per fermare '$(unit)'." + +#: ../src/core/dbus-unit.c:430 +msgid "Authentication is required to reload '$(unit)'." +msgstr "Autenticazione richiesta per ricaricare '$(unit)'." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Autenticazione richiesta per riavviare '$(unit)'." + +#: ../src/core/dbus-unit.c:535 +msgid "Authentication is required to kill '$(unit)'." +msgstr "Autenticazione richiesta per terminare '$(unit)'." + +#: ../src/core/dbus-unit.c:565 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" +"Autenticazione richiesta per riconfigurare lo stato \"fallito\" di '$(unit)'." + +#: ../src/core/dbus-unit.c:597 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Autenticazione richiesta per configurare le proprietà di '$(unit)'." diff --git a/po/pt_BR.po b/po/pt_BR.po index 1dd5900e2f..2a11371f97 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-01-10 12:23-0300\n" "Last-Translator: Rafael Ferreira <rafael.f.f1@gmail.com>\n" "Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n" @@ -441,6 +441,15 @@ msgid "" "interface." msgstr "É necessária autenticação para definir nome de máquina local." +#: ../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 "É necessária autenticação para definir nome de máquina local." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Conectar a um contêiner local" @@ -451,20 +460,69 @@ msgid "Authentication is required to log into a local container." msgstr "É necessária autenticação para se conectar a um contêiner local." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Conectar a um contêiner local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Conectar a um contêiner local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "É necessária autenticação para definir nome de máquina local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Conectar a um contêiner local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "É necessária autenticação para definir nome de máquina local." + +#: ../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:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 #, fuzzy msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "É necessária autenticação para definir informações de máquina local." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../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:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 #, fuzzy msgid "" "Authentication is required to manage local virtual machine and container " @@ -510,3 +568,38 @@ msgid "" msgstr "" "É necessária autenticação para controlar se deve ser habilitada, ou não, a " "sincronização de horário através de rede." + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "É necessária autenticação para recarregar o estado do sistema." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "É necessária autenticação para definir nome de máquina local." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-03-22 21:53+0300\n" "Last-Translator: Sergey Ptashnick <0comffdiz@inbox.ru>\n" "Language: ru\n" @@ -465,6 +465,15 @@ msgid "" "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 "Зайти в локальный контейнер" @@ -474,21 +483,70 @@ msgid "Authentication is required to log into a local container." msgstr "Чтобы зайти в локальный контейнер, необходимо пройти аутентификацию." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Зайти в локальный контейнер" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Чтобы зайти в локальный контейнер, необходимо пройти аутентификацию." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Зайти в локальный контейнер" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Чтобы настроить имя компьютера, необходимо пройти аутентификацию." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Зайти в локальный контейнер" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +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 +#, fuzzy +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:4 +#: ../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:5 +#: ../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:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -536,6 +594,43 @@ msgstr "" "Чтобы включить или выключить синхронизацию времени по сети, необходимо " "пройти аутентификацию." +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Чтобы настроить системное время, необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Чтобы настроить системное время, необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "" +"Чтобы заставить systemd перечитать конфигурацию, необходимо пройти " +"аутентификацию." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Чтобы настроить системное время, необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Чтобы зайти в локальный контейнер, необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Чтобы настроить имя компьютера, необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Чтобы настроить системное время, необходимо пройти аутентификацию." + #~ msgid "Press Ctrl+C to cancel all filesystem checks in progress" #~ msgstr "" #~ "Чтобы прервать все запущенные проверки файловых систем, нажмите Ctrl+C" @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-03-14 11:09+0100\n" "Last-Translator: Sebastian Rasmussen <sebras@gmail.com>\n" "Language-Team: Swedish\n" @@ -418,6 +418,15 @@ msgid "" "interface." msgstr "Autentisering krävs för att ange lokalt värdnamn." +#: ../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 "Autentisering krävs för att ange lokalt värdnamn." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Logga till en lokal behållare" @@ -427,20 +436,69 @@ msgid "Authentication is required to log into a local container." msgstr "Autentisering krävs för att logga till en lokal behållare" #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Autentisering krävs för att ange lokalt värdnamn." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../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 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Autentisering krävs för att ange lokalt värdnamn." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "Hantera lokala virtuella maskiner och behållare" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "" "Autentisering krävs för att hantera lokala virtuella maskiner och behållare." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "Hantera lokala virtuella maskin- och behållaravbildningar" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -490,6 +548,41 @@ msgstr "" "Autentisering krävs för att kontrollera huruvida synkronisering av " "nätverkstid ska vara aktiverat." +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Autentisering krävs för att läsa om tillståndet för systemd." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Autentisering krävs för att ange lokalt värdnamn." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + #~ msgid "Press Ctrl+C to cancel all filesystem checks in progress" #~ msgstr "Tryck Ctrl+C för att avbryta alla pågående filsystemskontroller." @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2014-07-16 19:13+0300\n" "Last-Translator: Daniel Korostil <ted.korostiled@gmail.com>\n" "Language-Team: linux.org.ua\n" @@ -421,6 +421,15 @@ msgid "" "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 "" @@ -431,20 +440,68 @@ msgid "Authentication is required to log into a local container." msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 -msgid "Manage local virtual machines and containers" +msgid "Log into the local host" msgstr "" #: ../src/machine/org.freedesktop.machine1.policy.in.h:4 #, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +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 +#, fuzzy +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 +#, fuzzy msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "Засвідчення потрібно, щоб вказати локальну інформацію про машини." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../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:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 #, fuzzy msgid "" "Authentication is required to manage local virtual machine and container " @@ -488,3 +545,38 @@ msgid "" msgstr "" "Засвідчення потрібно, щоб контролювати, чи синхронізування часу через мережу " "запущено." + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Засвідчення потрібно, щоб вказати системний час." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Засвідчення потрібно, щоб вказати системний час." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Засвідчення потрібно, щоб вказати системний час." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Засвідчення потрібно, щоб вказати системний час." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Засвідчення потрібно, щоб вказати системний час." diff --git a/po/zh_TW.po b/po/zh_TW.po index fb276a1577..5a214a3c48 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-06-11 12:44+0800\n" "Last-Translator: Jeff Huang <s8321414@gmail.com>\n" "Language-Team: chinese-l10n <chinese-l10n@googlegroups.com>\n" @@ -373,6 +373,15 @@ msgid "" "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 "登入到本機容器" @@ -382,19 +391,68 @@ msgid "Authentication is required to log into a local container." msgstr "登入到本機容器需要驗證。" #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "登入到本機容器" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "登入到本機容器需要驗證。" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "登入到本機容器" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +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 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "設定主機名稱需要驗證。" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "登入到本機容器" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +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 +#, fuzzy +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:4 +#: ../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:5 +#: ../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:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -435,3 +493,38 @@ msgid "" "Authentication is required to control whether network time synchronization " "shall be enabled." msgstr "控制網路時間同步是否啟用需要驗證。" + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "設定系統時間需要驗證。" + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "設定系統時間需要驗證。" + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "重新載入 systemd 狀態需要驗證。" + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "設定系統時間需要驗證。" + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "登入到本機容器需要驗證。" + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "設定主機名稱需要驗證。" + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "設定系統時間需要驗證。" diff --git a/shell-completion/bash/loginctl b/shell-completion/bash/loginctl index 7a083d2875..776eca4e62 100644 --- a/shell-completion/bash/loginctl +++ b/shell-completion/bash/loginctl @@ -41,7 +41,8 @@ _loginctl () { if __contains_word "$prev" ${OPTS[ARG]}; then case $prev in --signal|-s) - comps=$(compgen -A signal) + _signals + return ;; --kill-who) comps='all leader' diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl index 140465d316..61c5402786 100644 --- a/shell-completion/bash/machinectl +++ b/shell-completion/bash/machinectl @@ -57,7 +57,8 @@ _machinectl() { if __contains_word "$prev" ${OPTS[ARG]}; then case $prev in --signal|-s) - comps=$(compgen -A signal) + _signals + return ;; --kill-who) comps='all leader' diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index d80d8f02a8..6ffab33e45 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -115,7 +115,8 @@ _systemctl () { if __contains_word "$prev" ${OPTS[ARG]}; then case $prev in --signal|-s) - comps=$(compgen -A signal) + _signals + return ;; --type|-t) comps=$(__systemctl $mode -t help) diff --git a/shell-completion/bash/systemd-nspawn b/shell-completion/bash/systemd-nspawn index f9b740380c..429e712eb3 100644 --- a/shell-completion/bash/systemd-nspawn +++ b/shell-completion/bash/systemd-nspawn @@ -57,7 +57,7 @@ _systemd_nspawn() { [ARG]='-D --directory -u --user --uuid --capability --drop-capability --link-journal --bind --bind-ro -M --machine -S --slice --setenv -Z --selinux-context -L --selinux-apifs-context --register --network-interface --network-bridge --personality -i --image --tmpfs --volatile - --network-macvlan' + --network-macvlan --kill-signal' ) _init_completion || return @@ -132,6 +132,10 @@ _systemd_nspawn() { compopt -o nospace comps=$( compgen -A file -- "$cur" ) ;; + --kill-signal) + _signals + return + ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 diff --git a/src/basic/af-list.c b/src/basic/af-list.c index f396115a34..07dfff6ad4 100644 --- a/src/basic/af-list.c +++ b/src/basic/af-list.c @@ -19,16 +19,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <string.h> +#include <sys/socket.h> -#include "util.h" #include "af-list.h" +#include "util.h" static const struct af_name* lookup_af(register const char *str, register unsigned int len); -#include "af-to-name.h" #include "af-from-name.h" +#include "af-to-name.h" const char *af_to_name(int id) { diff --git a/src/basic/arphrd-list.c b/src/basic/arphrd-list.c index 284043cd90..03d8ad7403 100644 --- a/src/basic/arphrd-list.c +++ b/src/basic/arphrd-list.c @@ -22,13 +22,13 @@ #include <net/if_arp.h> #include <string.h> -#include "util.h" #include "arphrd-list.h" +#include "util.h" static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len); -#include "arphrd-to-name.h" #include "arphrd-from-name.h" +#include "arphrd-to-name.h" const char *arphrd_to_name(int id) { diff --git a/src/basic/async.c b/src/basic/async.c index c3135f0efe..cfc5d224e1 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -68,7 +68,7 @@ int asynchronous_sync(void) { } static void *close_thread(void *p) { - assert_se(close_nointr(PTR_TO_INT(p)) != -EBADF); + assert_se(close_nointr(PTR_TO_FD(p)) != -EBADF); return NULL; } @@ -84,7 +84,7 @@ int asynchronous_close(int fd) { if (fd >= 0) { PROTECT_ERRNO; - r = asynchronous_job(close_thread, INT_TO_PTR(fd)); + r = asynchronous_job(close_thread, FD_TO_PTR(fd)); if (r < 0) assert_se(close_nointr(fd) != -EBADF); } diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h index 6de331c73e..026d3cd9b1 100644 --- a/src/basic/audit-util.h +++ b/src/basic/audit-util.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdint.h> #include <stdbool.h> +#include <stdint.h> #include <sys/types.h> #define AUDIT_SESSION_INVALID ((uint32_t) -1) diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h index 2874bc99f7..9ce7b42d00 100644 --- a/src/basic/bitmap.h +++ b/src/basic/bitmap.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "macro.h" #include "hashmap.h" +#include "macro.h" typedef struct Bitmap Bitmap; diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 290fabdeff..be40dc5702 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -105,7 +105,7 @@ int btrfs_is_filesystem(int fd) { return F_TYPE_EQUAL(sfs.f_type, BTRFS_SUPER_MAGIC); } -int btrfs_is_subvol(int fd) { +int btrfs_is_subvol_fd(int fd) { struct stat st; assert(fd >= 0); @@ -121,6 +121,18 @@ int btrfs_is_subvol(int fd) { return btrfs_is_filesystem(fd); } +int btrfs_is_subvol(const char *path) { + _cleanup_close_ int fd = -1; + + assert(path); + + fd = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (fd < 0) + return -errno; + + return btrfs_is_subvol_fd(fd); +} + int btrfs_subvol_make(const char *path) { struct btrfs_ioctl_vol_args args = {}; _cleanup_close_ int fd = -1; @@ -1423,12 +1435,16 @@ static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_sub return n_old_qgroups; r = btrfs_subvol_get_parent(fd, old_subvol_id, &old_parent_id); - if (r < 0) + if (r == -ENXIO) + /* We have no parent, hence nothing to copy. */ + n_old_parent_qgroups = 0; + else 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; + else { + 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; @@ -1682,7 +1698,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag assert(old_fd >= 0); assert(new_path); - r = btrfs_is_subvol(old_fd); + r = btrfs_is_subvol_fd(old_fd); if (r < 0) return r; if (r == 0) { @@ -1868,7 +1884,7 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed */ if (subvol_id == 0) { - r = btrfs_is_subvol(fd); + r = btrfs_is_subvol_fd(fd); if (r < 0) return r; if (!r) @@ -1885,14 +1901,19 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed if (n > 0) /* already parent qgroups set up, let's bail */ return 0; + qgroups = mfree(qgroups); + r = btrfs_subvol_get_parent(fd, subvol_id, &parent_subvol); - if (r < 0) + if (r == -ENXIO) + /* No parent, hence no qgroup memberships */ + n = 0; + else if (r < 0) return r; - - qgroups = mfree(qgroups); - n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups); - if (n < 0) - return n; + else { + n = btrfs_qgroup_find_parents(fd, parent_subvol, &qgroups); + if (n < 0) + return n; + } if (insert_intermediary_qgroup) { uint64_t lowest = 256, new_qgroupid; diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index fc9efd72d5..8c11ce35d2 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -56,7 +56,9 @@ typedef enum BtrfsRemoveFlags { } BtrfsRemoveFlags; int btrfs_is_filesystem(int fd); -int btrfs_is_subvol(int fd); + +int btrfs_is_subvol_fd(int fd); +int btrfs_is_subvol(const char *path); 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); diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 7151fc3d0c..8f60561ede 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -23,9 +23,10 @@ #include <string.h> #include "alloc-util.h" -#include "string-util.h" #include "calendarspec.h" #include "fileio.h" +#include "parse-util.h" +#include "string-util.h" #define BITS_WEEKDAYS 127 @@ -49,7 +50,7 @@ void calendar_spec_free(CalendarSpec *c) { free_chain(c->day); free_chain(c->hour); free_chain(c->minute); - free_chain(c->second); + free_chain(c->microsecond); free(c); } @@ -135,7 +136,7 @@ int calendar_spec_normalize(CalendarSpec *c) { sort_chain(&c->day); sort_chain(&c->hour); sort_chain(&c->minute); - sort_chain(&c->second); + sort_chain(&c->microsecond); return 0; } @@ -177,7 +178,7 @@ _pure_ bool calendar_spec_valid(CalendarSpec *c) { if (!chain_valid(c->minute, 0, 59)) return false; - if (!chain_valid(c->second, 0, 59)) + if (!chain_valid(c->microsecond, 0, 60*USEC_PER_SEC-1)) return false; return true; @@ -232,7 +233,7 @@ static void format_weekdays(FILE *f, const CalendarSpec *c) { } } -static void format_chain(FILE *f, int space, const CalendarComponent *c) { +static void format_chain(FILE *f, int space, const CalendarComponent *c, bool usec) { assert(f); if (!c) { @@ -241,14 +242,25 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c) { } assert(c->value >= 0); - fprintf(f, "%0*i", space, c->value); - - if (c->repeat > 0) - fprintf(f, "/%i", c->repeat); + if (!usec) + fprintf(f, "%0*i", space, c->value); + else if (c->value % USEC_PER_SEC == 0) + fprintf(f, "%0*i", space, (int) (c->value / USEC_PER_SEC)); + else + fprintf(f, "%0*i.%06i", space, (int) (c->value / USEC_PER_SEC), (int) (c->value % USEC_PER_SEC)); + + if (c->repeat > 0) { + if (!usec) + fprintf(f, "/%i", c->repeat); + else if (c->repeat % USEC_PER_SEC == 0) + fprintf(f, "/%i", (int) (c->repeat / USEC_PER_SEC)); + else + fprintf(f, "/%i.%06i", (int) (c->repeat / USEC_PER_SEC), (int) (c->repeat % USEC_PER_SEC)); + } if (c->next) { fputc(',', f); - format_chain(f, space, c->next); + format_chain(f, space, c->next, usec); } } @@ -270,17 +282,17 @@ int calendar_spec_to_string(const CalendarSpec *c, char **p) { fputc(' ', f); } - format_chain(f, 4, c->year); + format_chain(f, 4, c->year, false); fputc('-', f); - format_chain(f, 2, c->month); + format_chain(f, 2, c->month, false); fputc('-', f); - format_chain(f, 2, c->day); + format_chain(f, 2, c->day, false); fputc(' ', f); - format_chain(f, 2, c->hour); + format_chain(f, 2, c->hour, false); fputc(':', f); - format_chain(f, 2, c->minute); + format_chain(f, 2, c->minute, false); fputc(':', f); - format_chain(f, 2, c->second); + format_chain(f, 2, c->microsecond, true); if (c->utc) fputs(" UTC", f); @@ -391,35 +403,70 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { } } -static int prepend_component(const char **p, CalendarComponent **c) { - unsigned long value, repeat = 0; - char *e = NULL, *ee = NULL; - CalendarComponent *cc; - - assert(p); - assert(c); +static int parse_component_decimal(const char **p, bool usec, unsigned long *res) { + unsigned long value; + const char *e = NULL; + char *ee = NULL; + int r; errno = 0; - value = strtoul(*p, &e, 10); + value = strtoul(*p, &ee, 10); if (errno > 0) return -errno; - if (e == *p) + if (ee == *p) return -EINVAL; if ((unsigned long) (int) value != value) return -ERANGE; + e = ee; - if (*e == '/') { - repeat = strtoul(e+1, &ee, 10); - if (errno > 0) - return -errno; - if (ee == e+1) - return -EINVAL; - if ((unsigned long) (int) repeat != repeat) - return -ERANGE; - if (repeat <= 0) + if (usec) { + if (value * USEC_PER_SEC / USEC_PER_SEC != value) return -ERANGE; - e = ee; + value *= USEC_PER_SEC; + if (*e == '.') { + unsigned add; + + e++; + r = parse_fractional_part_u(&e, 6, &add); + if (r < 0) + return r; + + if (add + value < value) + return -ERANGE; + value += add; + } + } + + *p = e; + *res = value; + + return 0; +} + +static int prepend_component(const char **p, bool usec, CalendarComponent **c) { + unsigned long value, repeat = 0; + CalendarComponent *cc; + int r; + const char *e; + + assert(p); + assert(c); + + e = *p; + + r = parse_component_decimal(&e, usec, &value); + if (r < 0) + return r; + + if (*e == '/') { + e++; + r = parse_component_decimal(&e, usec, &repeat); + if (r < 0) + return r; + + if (repeat == 0) + return -ERANGE; } if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':') @@ -438,13 +485,31 @@ static int prepend_component(const char **p, CalendarComponent **c) { if (*e ==',') { *p += 1; - return prepend_component(p, c); + return prepend_component(p, usec, c); } return 0; } -static int parse_chain(const char **p, CalendarComponent **c) { +static int const_chain(int value, CalendarComponent **c) { + CalendarComponent *cc = NULL; + + assert(c); + + cc = new0(CalendarComponent, 1); + if (!cc) + return -ENOMEM; + + cc->value = value; + cc->repeat = 0; + cc->next = *c; + + *c = cc; + + return 0; +} + +static int parse_chain(const char **p, bool usec, CalendarComponent **c) { const char *t; CalendarComponent *cc = NULL; int r; @@ -455,12 +520,19 @@ static int parse_chain(const char **p, CalendarComponent **c) { t = *p; if (t[0] == '*') { + if (usec) { + r = const_chain(0, c); + if (r < 0) + return r; + (*c)->repeat = USEC_PER_SEC; + } else + *c = NULL; + *p = t + 1; - *c = NULL; return 0; } - r = prepend_component(&t, &cc); + r = prepend_component(&t, usec, &cc); if (r < 0) { free_chain(cc); return r; @@ -471,24 +543,6 @@ static int parse_chain(const char **p, CalendarComponent **c) { return 0; } -static int const_chain(int value, CalendarComponent **c) { - CalendarComponent *cc = NULL; - - assert(c); - - cc = new0(CalendarComponent, 1); - if (!cc) - return -ENOMEM; - - cc->value = value; - cc->repeat = 0; - cc->next = *c; - - *c = cc; - - return 0; -} - static int parse_date(const char **p, CalendarSpec *c) { const char *t; int r; @@ -503,7 +557,7 @@ static int parse_date(const char **p, CalendarSpec *c) { if (*t == 0) return 0; - r = parse_chain(&t, &first); + r = parse_chain(&t, false, &first); if (r < 0) return r; @@ -519,7 +573,7 @@ static int parse_date(const char **p, CalendarSpec *c) { } t++; - r = parse_chain(&t, &second); + r = parse_chain(&t, false, &second); if (r < 0) { free_chain(first); return r; @@ -540,7 +594,7 @@ static int parse_date(const char **p, CalendarSpec *c) { } t++; - r = parse_chain(&t, &third); + r = parse_chain(&t, false, &third); if (r < 0) { free_chain(first); free_chain(second); @@ -582,7 +636,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) { goto finish; } - r = parse_chain(&t, &h); + r = parse_chain(&t, false, &h); if (r < 0) goto fail; @@ -592,7 +646,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) { } t++; - r = parse_chain(&t, &m); + r = parse_chain(&t, false, &m); if (r < 0) goto fail; @@ -610,7 +664,7 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) { } t++; - r = parse_chain(&t, &s); + r = parse_chain(&t, true, &s); if (r < 0) goto fail; @@ -639,7 +693,8 @@ finish: *p = t; c->hour = h; c->minute = m; - c->second = s; + c->microsecond = s; + return 0; fail: @@ -671,7 +726,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { } if (strcaseeq(p, "minutely")) { - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -679,7 +734,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->minute); if (r < 0) goto fail; - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -690,7 +745,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->minute); if (r < 0) goto fail; - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -704,7 +759,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->minute); if (r < 0) goto fail; - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -724,7 +779,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->minute); if (r < 0) goto fail; - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -738,7 +793,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->minute); if (r < 0) goto fail; - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -765,7 +820,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->minute); if (r < 0) goto fail; - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -789,7 +844,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { r = const_chain(0, &c->minute); if (r < 0) goto fail; - r = const_chain(0, &c->second); + r = const_chain(0, &c->microsecond); if (r < 0) goto fail; @@ -906,14 +961,16 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { return (weekdays_bits & (1 << k)); } -static int find_next(const CalendarSpec *spec, struct tm *tm) { +static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { struct tm c; + int tm_usec; int r; assert(spec); assert(tm); c = *tm; + tm_usec = *usec; for (;;) { /* Normalize the current date */ @@ -927,7 +984,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { if (r > 0) { c.tm_mon = 0; c.tm_mday = 1; - c.tm_hour = c.tm_min = c.tm_sec = 0; + c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; } if (r < 0 || tm_out_of_bounds(&c, spec->utc)) return r; @@ -938,29 +995,29 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { if (r > 0) { c.tm_mday = 1; - c.tm_hour = c.tm_min = c.tm_sec = 0; + c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; } if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_year ++; c.tm_mon = 0; c.tm_mday = 1; - c.tm_hour = c.tm_min = c.tm_sec = 0; + c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; } r = find_matching_component(spec->day, &c.tm_mday); if (r > 0) - c.tm_hour = c.tm_min = c.tm_sec = 0; + c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_mon ++; c.tm_mday = 1; - c.tm_hour = c.tm_min = c.tm_sec = 0; + c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; } if (!matches_weekday(spec->weekdays_bits, &c, spec->utc)) { c.tm_mday++; - c.tm_hour = c.tm_min = c.tm_sec = 0; + c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; } @@ -969,7 +1026,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { c.tm_min = c.tm_sec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_mday ++; - c.tm_hour = c.tm_min = c.tm_sec = 0; + c.tm_hour = c.tm_min = c.tm_sec = tm_usec = 0; continue; } @@ -978,19 +1035,23 @@ static int find_next(const CalendarSpec *spec, struct tm *tm) { c.tm_sec = 0; if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_hour ++; - c.tm_min = c.tm_sec = 0; + c.tm_min = c.tm_sec = tm_usec = 0; continue; } - r = find_matching_component(spec->second, &c.tm_sec); + c.tm_sec = c.tm_sec * USEC_PER_SEC + tm_usec; + r = find_matching_component(spec->microsecond, &c.tm_sec); + tm_usec = c.tm_sec % USEC_PER_SEC; + c.tm_sec /= USEC_PER_SEC; + if (r < 0 || tm_out_of_bounds(&c, spec->utc)) { c.tm_min ++; - c.tm_sec = 0; + c.tm_sec = tm_usec = 0; continue; } - *tm = c; + *usec = tm_usec; return 0; } } @@ -999,14 +1060,17 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) struct tm tm; time_t t; int r; + usec_t tm_usec; assert(spec); assert(next); - t = (time_t) (usec / USEC_PER_SEC) + 1; + usec++; + t = (time_t) (usec / USEC_PER_SEC); assert_se(localtime_or_gmtime_r(&t, &tm, spec->utc)); + tm_usec = usec % USEC_PER_SEC; - r = find_next(spec, &tm); + r = find_next(spec, &tm, &tm_usec); if (r < 0) return r; @@ -1014,6 +1078,6 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) if (t == (time_t) -1) return -EINVAL; - *next = (usec_t) t * USEC_PER_SEC; + *next = (usec_t) t * USEC_PER_SEC + tm_usec; return 0; } diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h index 56dc02f391..75b699682a 100644 --- a/src/basic/calendarspec.h +++ b/src/basic/calendarspec.h @@ -25,6 +25,7 @@ * time, a la cron */ #include <stdbool.h> + #include "util.h" typedef struct CalendarComponent { @@ -44,7 +45,7 @@ typedef struct CalendarSpec { CalendarComponent *hour; CalendarComponent *minute; - CalendarComponent *second; + CalendarComponent *microsecond; } CalendarSpec; void calendar_spec_free(CalendarSpec *c); diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index 4d391510bc..f0974900cd 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -28,8 +28,8 @@ static const struct capability_name* lookup_capability(register const char *str, register unsigned int len); -#include "cap-to-name.h" #include "cap-from-name.h" +#include "cap-to-name.h" const char *capability_to_name(int id) { diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 01359fa7cb..a80ee60bd3 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -21,12 +21,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> -#include <stdio.h> #include <dirent.h> +#include <stdio.h> +#include <sys/types.h> -#include "set.h" #include "def.h" +#include "set.h" /* An enum of well known cgroup controllers */ typedef enum CGroupController { diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c index 34d1331486..22869e4136 100644 --- a/src/basic/errno-list.c +++ b/src/basic/errno-list.c @@ -21,14 +21,14 @@ #include <string.h> -#include "util.h" #include "errno-list.h" +#include "util.h" static const struct errno_name* lookup_errno(register const char *str, register unsigned int len); -#include "errno-to-name.h" #include "errno-from-name.h" +#include "errno-to-name.h" const char *errno_to_name(int id) { diff --git a/src/basic/escape.c b/src/basic/escape.c index 4815161b09..42a84c9317 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -89,20 +89,20 @@ size_t cescape_char(char c, char *buf) { return buf - buf_old; } -char *cescape(const char *s) { - char *r, *t; +char *cescape_length(const char *s, size_t n) { const char *f; + char *r, *t; - assert(s); + assert(s || n == 0); /* Does C style string escaping. May be reversed with * cunescape(). */ - r = new(char, strlen(s)*4 + 1); + r = new(char, n*4 + 1); if (!r) return NULL; - for (f = s, t = r; *f; f++) + for (f = s, t = r; f < s + n; f++) t += cescape_char(*f, t); *t = 0; @@ -110,6 +110,12 @@ char *cescape(const char *s) { return r; } +char *cescape(const char *s) { + assert(s); + + return cescape_length(s, strlen(s)); +} + int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { int r = 1; diff --git a/src/basic/escape.h b/src/basic/escape.h index 85ba909081..52ebf11c4a 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <inttypes.h> +#include <sys/types.h> /* What characters are special in the shell? */ /* must be escaped outside and inside double-quotes */ @@ -35,6 +35,7 @@ typedef enum UnescapeFlags { } UnescapeFlags; char *cescape(const char *s); +char *cescape_length(const char *s, size_t n); size_t cescape_char(char c, char *buf); int cunescape(const char *s, UnescapeFlags flags, char **ret); diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index fcff753ada..4c83731540 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -19,12 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <signal.h> +#include <stdlib.h> #include "exit-status.h" -#include "set.h" #include "macro.h" +#include "set.h" const char* exit_status_to_string(ExitStatus status, ExitStatusLevel level) { diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 1ca10f0383..5ce1592eeb 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -21,13 +21,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <dirent.h> #include <stdbool.h> +#include <stdio.h> #include <sys/socket.h> #include "macro.h" +/* Make sure we can distinguish fd 0 and NULL */ +#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) +#define PTR_TO_FD(p) (PTR_TO_INT(p)-1) + int close_nointr(int fd); int safe_close(int fd); void safe_close_pair(int p[]); diff --git a/src/basic/fdset.c b/src/basic/fdset.c index 42b0b2b98f..e5452f3bb0 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <errno.h> #include <dirent.h> +#include <errno.h> #include <fcntl.h> #include "sd-daemon.h" @@ -36,10 +36,6 @@ #define MAKE_SET(s) ((Set*) s) #define MAKE_FDSET(s) ((FDSet*) s) -/* Make sure we can distinguish fd 0 and NULL */ -#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) -#define PTR_TO_FD(p) (PTR_TO_INT(p)-1) - FDSet *fdset_new(void) { return MAKE_FDSET(set_new(NULL)); } diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c index f596f1d11f..0405822ce0 100644 --- a/src/basic/fileio-label.c +++ b/src/basic/fileio-label.c @@ -20,9 +20,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "selinux-util.h" #include "fileio-label.h" +#include "selinux-util.h" +#include "util.h" int write_string_file_atomic_label(const char *fn, const char *line) { int r; diff --git a/src/basic/fileio-label.h b/src/basic/fileio-label.h index 25fa351be2..9feb3cccb5 100644 --- a/src/basic/fileio-label.h +++ b/src/basic/fileio-label.h @@ -23,6 +23,7 @@ ***/ #include <stdio.h> + #include "fileio.h" int write_string_file_atomic_label(const char *fn, const char *line); diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 902c7e295b..5fbb7bc4c3 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -22,10 +22,10 @@ ***/ #include <fcntl.h> +#include <limits.h> #include <sys/inotify.h> #include <sys/types.h> #include <unistd.h> -#include <limits.h> #include "time-util.h" diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h index e70818fdd7..b03aa43160 100644 --- a/src/basic/gunicode.h +++ b/src/basic/gunicode.h @@ -6,8 +6,8 @@ #pragma once -#include <stdint.h> #include <stdbool.h> +#include <stdint.h> #include <stdlib.h> char *utf8_prev_char (const char *p); diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 4109a08c6c..6e501ef6ff 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -380,7 +380,7 @@ static unsigned base_bucket_hash(HashmapBase *h, const void *p) { h->hash_ops->hash(p, &state); - siphash24_finalize((uint8_t*)&hash, &state); + hash = siphash24_finalize(&state); return (unsigned) (hash % n_buckets(h)); } diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index ea0528c6fc..c57a3cbd60 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -72,7 +72,7 @@ static bool hostname_valid_char(char c) { * allow_trailing_dot is true and at least two components are present * in the name. Note that due to the restricted charset and length * this call is substantially more conservative than - * dns_domain_is_valid(). + * dns_name_is_valid(). */ bool hostname_is_valid(const char *s, bool allow_trailing_dot) { unsigned n_dots = 0; diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index f4e24121e7..b75c39aac7 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -44,7 +44,7 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) { assert(u); if (family == AF_INET) - return (be32toh(u->in.s_addr) & 0xFFFF0000) == (169U << 24 | 254U << 16); + return (be32toh(u->in.s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); if (family == AF_INET6) return IN6_IS_ADDR_LINKLOCAL(&u->in6); @@ -52,6 +52,19 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) { return -EAFNOSUPPORT; } +int in_addr_is_localhost(int family, const union in_addr_union *u) { + assert(u); + + if (family == AF_INET) + /* All of 127.x.x.x is localhost. */ + return (be32toh(u->in.s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24; + + if (family == AF_INET6) + return IN6_IS_ADDR_LOOPBACK(&u->in6); + + return -EAFNOSUPPORT; +} + int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) { assert(a); assert(b); diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 51af08868c..58f55b3418 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -33,6 +33,7 @@ union in_addr_union { int in_addr_is_null(int family, const union in_addr_union *u); int in_addr_is_link_local(int family, const union in_addr_union *u); +int in_addr_is_localhost(int family, const union in_addr_union *u); int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b); int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); diff --git a/src/basic/ioprio.h b/src/basic/ioprio.h index e5c71d0043..d8bb6eb497 100644 --- a/src/basic/ioprio.h +++ b/src/basic/ioprio.h @@ -4,8 +4,8 @@ /* This is minimal version of Linux' linux/ioprio.h header file, which * is licensed GPL2 */ -#include <unistd.h> #include <sys/syscall.h> +#include <unistd.h> /* * Gives us 8 prio classes with 13-bits of data for each class diff --git a/src/basic/json.c b/src/basic/json.c index 716705e5ff..9d5dedb934 100644 --- a/src/basic/json.c +++ b/src/basic/json.c @@ -23,9 +23,9 @@ #include <sys/types.h> #include "alloc-util.h" +#include "hexdecoct.h" #include "json.h" #include "macro.h" -#include "hexdecoct.h" #include "string-util.h" #include "utf8.h" diff --git a/src/basic/json.h b/src/basic/json.h index e0b4d810b5..8a7d79cb17 100644 --- a/src/basic/json.h +++ b/src/basic/json.h @@ -22,6 +22,7 @@ ***/ #include <stdbool.h> + #include "util.h" enum { diff --git a/src/basic/label.c b/src/basic/label.c index 82f10b21bd..f33502f90f 100644 --- a/src/basic/label.c +++ b/src/basic/label.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "label.h" #include "selinux-util.h" #include "smack-util.h" #include "util.h" -#include "label.h" int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { int r, q; diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index 87c3aef7af..0bdbae480b 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -19,12 +19,12 @@ 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 <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/file.h> #include "alloc-util.h" diff --git a/src/basic/login-util.c b/src/basic/login-util.c index 832f477bd2..41cef14e73 100644 --- a/src/basic/login-util.c +++ b/src/basic/login-util.c @@ -20,8 +20,8 @@ ***/ #include "def.h" -#include "string-util.h" #include "login-util.h" +#include "string-util.h" bool session_id_valid(const char *id) { diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 2cb404ea81..3e4de008a4 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <inttypes.h> +#include <sys/types.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/mempool.c b/src/basic/mempool.c index d5d98d8829..9ee6e6a76d 100644 --- a/src/basic/mempool.c +++ b/src/basic/mempool.c @@ -20,8 +20,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "mempool.h" #include "macro.h" +#include "mempool.h" #include "util.h" struct pool { diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index 76bbc1edda..c241ef6064 100644 --- a/src/basic/mkdir-label.c +++ b/src/basic/mkdir-label.c @@ -20,8 +20,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <stdio.h> +#include <unistd.h> #include "label.h" #include "mkdir.h" diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 0214c4627e..5d7fb9a12d 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <errno.h> +#include <string.h> #include "fs-util.h" #include "mkdir.h" diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h index 6c617ab305..da10e90ff2 100644 --- a/src/basic/ordered-set.h +++ b/src/basic/ordered-set.h @@ -29,6 +29,17 @@ static inline OrderedSet* ordered_set_new(const struct hash_ops *ops) { return (OrderedSet*) ordered_hashmap_new(ops); } +static inline int ordered_set_ensure_allocated(OrderedSet **s, const struct hash_ops *ops) { + if (*s) + return 0; + + *s = ordered_set_new(ops); + if (!*s) + return -ENOMEM; + + return 0; +} + static inline OrderedSet* ordered_set_free(OrderedSet *s) { ordered_hashmap_free((OrderedHashmap*) s); return NULL; diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 151067e916..3ae99d9334 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -490,3 +490,39 @@ int safe_atod(const char *s, double *ret_d) { *ret_d = (double) d; return 0; } + +int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { + size_t i; + unsigned val = 0; + const char *s; + + s = *p; + + /* accept any number of digits, strtoull is limted to 19 */ + for(i=0; i < digits; i++,s++) { + if (*s < '0' || *s > '9') { + if (i == 0) + return -EINVAL; + + /* too few digits, pad with 0 */ + for (; i < digits; i++) + val *= 10; + + break; + } + + val *= 10; + val += *s - '0'; + } + + /* maybe round up */ + if (*s >= '5' && *s <= '9') + val++; + + s += strspn(s, DIGITS); + + *p = s; + *res = val; + + return 0; +} diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 408690d0b3..125de53d7a 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -90,3 +90,5 @@ static inline int safe_atoli(const char *s, long int *ret_u) { #endif int safe_atod(const char *s, double *ret_d); + +int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 72633ebf70..fdc7e1bdef 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -19,12 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> -#include <sys/types.h> #include <alloca.h> +#include <signal.h> +#include <stdbool.h> #include <stdio.h> #include <string.h> -#include <signal.h> +#include <sys/types.h> #include "formats-util.h" #include "macro.h" diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index a821a3d5bb..e8ce5cfd96 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -24,15 +24,15 @@ #include <sys/un.h> #ifdef HAVE_SELINUX -#include <selinux/selinux.h> -#include <selinux/label.h> #include <selinux/context.h> +#include <selinux/label.h> +#include <selinux/selinux.h> #endif #include "alloc-util.h" -#include "strv.h" #include "path-util.h" #include "selinux-util.h" +#include "strv.h" #ifdef HAVE_SELINUX DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon); diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 2afcaec183..d19984c5fe 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> #include <stdbool.h> +#include <sys/socket.h> #include "macro.h" diff --git a/src/basic/set.h b/src/basic/set.h index 4554ef2d49..5fd7de08f9 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -27,7 +27,6 @@ Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); #define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) - static inline Set *set_free(Set *s) { internal_hashmap_free(HASHMAP_BASE(s)); return NULL; diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c index 0108603fe8..c535c89d52 100644 --- a/src/basic/sigbus.c +++ b/src/basic/sigbus.c @@ -23,8 +23,8 @@ #include <sys/mman.h> #include "macro.h" -#include "util.h" #include "sigbus.h" +#include "util.h" #define SIGBUS_QUEUE_MAX 64 diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 3b61961389..10fc56da69 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -17,9 +17,9 @@ coding style) */ -#include "sparse-endian.h" - #include "siphash24.h" +#include "sparse-endian.h" +#include "unaligned.h" #include "util.h" static inline uint64_t rotate_left(uint64_t x, uint8_t b) { @@ -53,37 +53,40 @@ void siphash24_init(struct siphash *state, const uint8_t k[16]) { 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; + k0 = unaligned_read_le64(k); + k1 = unaligned_read_le64(k + 8); + + *state = (struct siphash) { + /* "somepseudorandomlygeneratedbytes" */ + .v0 = 0x736f6d6570736575ULL ^ k0, + .v1 = 0x646f72616e646f6dULL ^ k1, + .v2 = 0x6c7967656e657261ULL ^ k0, + .v3 = 0x7465646279746573ULL ^ k1, + .padding = 0, + .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; + size_t left = state->inlen & 7; + uint64_t m; assert(in); assert(state); - /* update total length */ + /* Update total length */ state->inlen += inlen; - /* if padding exists, fill it out */ + /* If padding exists, fill it out */ if (left > 0) { - for ( ; in < end && left < 8; in ++, left ++ ) - state->padding |= ( ( uint64_t )*in ) << (left * 8); + 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 */ + /* We did not have enough input to fill out the padding completely */ return; #ifdef DEBUG @@ -93,6 +96,7 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { 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 + state->v3 ^= state->padding; sipround(state); sipround(state); @@ -101,10 +105,10 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { state->padding = 0; } - end -= ( state->inlen % sizeof (uint64_t) ); + end -= (state->inlen % sizeof(uint64_t)); - for ( ; in < end; in += 8 ) { - m = le64toh(*(le64_t*) in); + for ( ; in < end; in += 8) { + m = unaligned_read_le64(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); @@ -119,38 +123,41 @@ void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { } left = state->inlen & 7; - - switch(left) - { - case 7: state->padding |= ((uint64_t) in[6]) << 48; - - case 6: state->padding |= ((uint64_t) in[5]) << 40; - - case 5: state->padding |= ((uint64_t) in[4]) << 32; - - case 4: state->padding |= ((uint64_t) in[3]) << 24; - - 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; + switch (left) { + case 7: + state->padding |= ((uint64_t) in[6]) << 48; + case 6: + state->padding |= ((uint64_t) in[5]) << 40; + case 5: + state->padding |= ((uint64_t) in[4]) << 32; + case 4: + state->padding |= ((uint64_t) in[3]) << 24; + 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]); + case 0: + break; } } -void siphash24_finalize(uint8_t out[8], struct siphash *state) { +uint64_t siphash24_finalize(struct siphash *state) { uint64_t b; - b = state->padding | (( ( uint64_t )state->inlen ) << 56); + assert(state); + + b = state->padding | (((uint64_t) state->inlen) << 56); + #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) 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 + state->v3 ^= b; sipround(state); sipround(state); @@ -169,14 +176,17 @@ void siphash24_finalize(uint8_t out[8], struct siphash *state) { sipround(state); sipround(state); - *(le64_t*)out = htole64(state->v0 ^ state->v1 ^ state->v2 ^ state->v3); + return 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]) { +uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) { struct siphash state; + assert(in); + assert(k); + siphash24_init(&state, k); - siphash24_compress(_in, inlen, &state); - siphash24_finalize(out, &state); + siphash24_compress(in, inlen, &state); + + return siphash24_finalize(&state); } diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index 6c5cd98ee8..ba4f7d01b6 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -4,16 +4,16 @@ #include <sys/types.h> struct siphash { - uint64_t v0; - uint64_t v1; - uint64_t v2; - uint64_t v3; - uint64_t padding; - size_t inlen; + 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); +uint64_t siphash24_finalize(struct siphash *state); -void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); +uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index c60f2556af..129ffa811c 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -21,9 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/socket.h> -#include <netinet/in.h> #include <netinet/ether.h> +#include <netinet/in.h> +#include <sys/socket.h> #include <sys/un.h> #include <linux/netlink.h> #include <linux/if_packet.h> diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 909b220a24..fb92464274 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -52,9 +52,8 @@ 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; + * different archs. Let's give its type a name. */ +typedef typeof(((struct statfs*)NULL)->f_type) 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); diff --git a/src/basic/strv.c b/src/basic/strv.c index ba6df716a7..771781f9fc 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -27,8 +27,8 @@ #include "alloc-util.h" #include "escape.h" #include "string-util.h" -#include "util.h" #include "strv.h" +#include "util.h" char *strv_find(char **l, const char *name) { char **i; diff --git a/src/basic/strxcpyx.c b/src/basic/strxcpyx.c index 6542c0abf5..088ba53c29 100644 --- a/src/basic/strxcpyx.c +++ b/src/basic/strxcpyx.c @@ -27,6 +27,7 @@ #include <stdio.h> #include <string.h> + #include "strxcpyx.h" size_t strpcpy(char **dest, size_t size, const char *src) { diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index f2185c1c11..b2c7a297ae 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> #include <stdarg.h> +#include <stdbool.h> #include <stdio.h> #include "macro.h" diff --git a/src/basic/time-util.c b/src/basic/time-util.c index b36fbe4f09..b9da6991da 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -27,6 +27,7 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "parse-util.h" #include "path-util.h" #include "string-util.h" #include "strv.h" @@ -323,15 +324,15 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { const char *suffix; usec_t usec; } table[] = { - { "y", USEC_PER_YEAR }, - { "month", USEC_PER_MONTH }, - { "w", USEC_PER_WEEK }, - { "d", USEC_PER_DAY }, - { "h", USEC_PER_HOUR }, - { "min", USEC_PER_MINUTE }, - { "s", USEC_PER_SEC }, - { "ms", USEC_PER_MSEC }, - { "us", 1 }, + { "y", USEC_PER_YEAR }, + { "month", USEC_PER_MONTH }, + { "w", USEC_PER_WEEK }, + { "d", USEC_PER_DAY }, + { "h", USEC_PER_HOUR }, + { "min", USEC_PER_MINUTE }, + { "s", USEC_PER_SEC }, + { "ms", USEC_PER_MSEC }, + { "us", 1 }, }; unsigned i; @@ -658,29 +659,18 @@ int parse_timestamp(const char *t, usec_t *usec) { parse_usec: { - char *end; - unsigned long long val; - size_t l; + unsigned add; k++; - if (*k < '0' || *k > '9') + r = parse_fractional_part_u(&k, 6, &add); + if (r < 0) return -EINVAL; - /* base 10 instead of base 0, .09 is not base 8 */ - errno = 0; - val = strtoull(k, &end, 10); - if (*end || errno) + if (*k) 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 = add; - x_usec = val; } from_tm: @@ -711,33 +701,34 @@ int parse_time(const char *t, usec_t *usec, usec_t default_unit) { const char *suffix; usec_t usec; } table[] = { - { "seconds", USEC_PER_SEC }, - { "second", USEC_PER_SEC }, - { "sec", USEC_PER_SEC }, - { "s", USEC_PER_SEC }, + { "seconds", USEC_PER_SEC }, + { "second", USEC_PER_SEC }, + { "sec", USEC_PER_SEC }, + { "s", USEC_PER_SEC }, { "minutes", USEC_PER_MINUTE }, - { "minute", USEC_PER_MINUTE }, - { "min", USEC_PER_MINUTE }, - { "months", USEC_PER_MONTH }, - { "month", USEC_PER_MONTH }, - { "msec", USEC_PER_MSEC }, - { "ms", USEC_PER_MSEC }, - { "m", USEC_PER_MINUTE }, - { "hours", USEC_PER_HOUR }, - { "hour", USEC_PER_HOUR }, - { "hr", USEC_PER_HOUR }, - { "h", USEC_PER_HOUR }, - { "days", USEC_PER_DAY }, - { "day", USEC_PER_DAY }, - { "d", USEC_PER_DAY }, - { "weeks", USEC_PER_WEEK }, - { "week", USEC_PER_WEEK }, - { "w", USEC_PER_WEEK }, - { "years", USEC_PER_YEAR }, - { "year", USEC_PER_YEAR }, - { "y", USEC_PER_YEAR }, - { "usec", 1ULL }, - { "us", 1ULL }, + { "minute", USEC_PER_MINUTE }, + { "min", USEC_PER_MINUTE }, + { "months", USEC_PER_MONTH }, + { "month", USEC_PER_MONTH }, + { "M", USEC_PER_MONTH }, + { "msec", USEC_PER_MSEC }, + { "ms", USEC_PER_MSEC }, + { "m", USEC_PER_MINUTE }, + { "hours", USEC_PER_HOUR }, + { "hour", USEC_PER_HOUR }, + { "hr", USEC_PER_HOUR }, + { "h", USEC_PER_HOUR }, + { "days", USEC_PER_DAY }, + { "day", USEC_PER_DAY }, + { "d", USEC_PER_DAY }, + { "weeks", USEC_PER_WEEK }, + { "week", USEC_PER_WEEK }, + { "w", USEC_PER_WEEK }, + { "years", USEC_PER_YEAR }, + { "year", USEC_PER_YEAR }, + { "y", USEC_PER_YEAR }, + { "usec", 1ULL }, + { "us", 1ULL }, }; const char *p, *s; diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h index d6181dd9a9..a8115eaa1f 100644 --- a/src/basic/unaligned.h +++ b/src/basic/unaligned.h @@ -21,8 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <endian.h> #include <stdint.h> +/* BE */ + static inline uint16_t unaligned_read_be16(const void *_u) { const uint8_t *u = _u; @@ -64,3 +67,47 @@ static inline void unaligned_write_be64(void *_u, uint64_t a) { unaligned_write_be32(u, (uint32_t) (a >> 32)); unaligned_write_be32(u + 4, (uint32_t) a); } + +/* LE */ + +static inline uint16_t unaligned_read_le16(const void *_u) { + const uint8_t *u = _u; + + return (((uint16_t) u[1]) << 8) | + ((uint16_t) u[0]); +} + +static inline uint32_t unaligned_read_le32(const void *_u) { + const uint8_t *u = _u; + + return (((uint32_t) unaligned_read_le16(u + 2)) << 16) | + ((uint32_t) unaligned_read_le16(u)); +} + +static inline uint64_t unaligned_read_le64(const void *_u) { + const uint8_t *u = _u; + + return (((uint64_t) unaligned_read_le32(u + 4)) << 32) | + ((uint64_t) unaligned_read_le32(u)); +} + +static inline void unaligned_write_le16(void *_u, uint16_t a) { + uint8_t *u = _u; + + u[0] = (uint8_t) a; + u[1] = (uint8_t) (a >> 8); +} + +static inline void unaligned_write_le32(void *_u, uint32_t a) { + uint8_t *u = _u; + + unaligned_write_le16(u, (uint16_t) a); + unaligned_write_le16(u + 2, (uint16_t) (a >> 16)); +} + +static inline void unaligned_write_le64(void *_u, uint64_t a) { + uint8_t *u = _u; + + unaligned_write_le32(u, (uint32_t) a); + unaligned_write_le32(u + 4, (uint32_t) (a >> 32)); +} diff --git a/src/basic/user-util.c b/src/basic/user-util.c index d6c936db37..397880b0b1 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <pwd.h> #include <grp.h> +#include <pwd.h> #include "alloc-util.h" #include "fd-util.h" diff --git a/src/basic/user-util.h b/src/basic/user-util.h index 11ff6674cf..6106e138be 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <stdbool.h> +#include <sys/types.h> bool uid_is_valid(uid_t uid); diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 7600d99903..b4063a4cec 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -44,10 +44,10 @@ */ #include <errno.h> -#include <stdlib.h> #include <inttypes.h> -#include <string.h> #include <stdbool.h> +#include <stdlib.h> +#include <string.h> #include "alloc-util.h" #include "hexdecoct.h" diff --git a/src/basic/util.c b/src/basic/util.c index 08bdcd28f2..58617b354a 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -73,6 +73,7 @@ #include "build.h" #include "def.h" #include "device-nodes.h" +#include "dirent-util.h" #include "env-util.h" #include "escape.h" #include "exit-status.h" @@ -81,19 +82,20 @@ #include "formats-util.h" #include "gunicode.h" #include "hashmap.h" +#include "hexdecoct.h" #include "hostname-util.h" #include "ioprio.h" #include "log.h" #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 "stat-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -102,8 +104,6 @@ #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); @@ -206,7 +206,7 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) { log_debug("Spawned %s as " PID_FMT ".", path, pid); - r = hashmap_put(pids, UINT_TO_PTR(pid), path); + r = hashmap_put(pids, PID_TO_PTR(pid), path); if (r < 0) return log_oom(); path = NULL; @@ -224,10 +224,10 @@ static int do_execute(char **directories, usec_t timeout, char *argv[]) { _cleanup_free_ char *path = NULL; pid_t pid; - pid = PTR_TO_UINT(hashmap_first_key(pids)); + pid = PTR_TO_PID(hashmap_first_key(pids)); assert(pid > 0); - path = hashmap_remove(pids, UINT_TO_PTR(pid)); + path = hashmap_remove(pids, PID_TO_PTR(pid)); assert(path); wait_for_terminate_and_warn(path, pid, true); diff --git a/src/basic/virt.c b/src/basic/virt.c index d088b7a804..b82680a54b 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -24,6 +24,8 @@ #include <unistd.h> #include "alloc-util.h" +#include "dirent-util.h" +#include "fd-util.h" #include "fileio.h" #include "process-util.h" #include "stat-util.h" @@ -267,13 +269,20 @@ int detect_vm(void) { if (cached_found >= 0) return cached_found; - r = detect_vm_cpuid(); + /* We have to use the correct order here: + * Some virtualization technologies do use KVM hypervisor but are + * expected to be detected as something else. So detect DMI first. + * + * An example is Virtualbox since version 5.0, which uses KVM backend. + * Detection via DMI works corretly, the CPU ID would find KVM + * only. */ + r = detect_vm_dmi(); if (r < 0) return r; if (r != VIRTUALIZATION_NONE) goto finish; - r = detect_vm_dmi(); + r = detect_vm_cpuid(); if (r < 0) return r; if (r != VIRTUALIZATION_NONE) diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 38b79da886..6d35adc0e2 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -18,12 +18,12 @@ #include <efi.h> #include <efilib.h> -#include "util.h" #include "console.h" -#include "graphics.h" -#include "pefile.h" #include "disk.h" +#include "graphics.h" #include "linux.h" +#include "pefile.h" +#include "util.h" #ifndef EFI_OS_INDICATIONS_BOOT_TO_FW_UI #define EFI_OS_INDICATIONS_BOOT_TO_FW_UI 0x0000000000000001ULL diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c index 66aa88f32e..2151d34432 100644 --- a/src/boot/efi/console.c +++ b/src/boot/efi/console.c @@ -18,8 +18,8 @@ #include <efi.h> #include <efilib.h> -#include "util.h" #include "console.h" +#include "util.h" #define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ { 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } } diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c index f732428216..efa91fa7ac 100644 --- a/src/boot/efi/graphics.c +++ b/src/boot/efi/graphics.c @@ -20,8 +20,8 @@ #include <efi.h> #include <efilib.h> -#include "util.h" #include "graphics.h" +#include "util.h" EFI_STATUS graphics_mode(BOOLEAN on) { #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c index 809c69310e..e9d097c132 100644 --- a/src/boot/efi/linux.c +++ b/src/boot/efi/linux.c @@ -17,8 +17,8 @@ #include <efi.h> #include <efilib.h> -#include "util.h" #include "linux.h" +#include "util.h" #define SETUP_MAGIC 0x53726448 /* "HdrS" */ struct SetupHeader { diff --git a/src/boot/efi/pefile.c b/src/boot/efi/pefile.c index e6fedbc929..efb3271ee3 100644 --- a/src/boot/efi/pefile.c +++ b/src/boot/efi/pefile.c @@ -17,8 +17,8 @@ #include <efi.h> #include <efilib.h> -#include "util.h" #include "pefile.h" +#include "util.h" struct DosFileHeader { UINT8 Magic[2]; diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c index 470ea3e2cc..b584b5e6a9 100644 --- a/src/boot/efi/splash.c +++ b/src/boot/efi/splash.c @@ -18,9 +18,9 @@ #include <efi.h> #include <efilib.h> -#include "util.h" #include "graphics.h" #include "splash.h" +#include "util.h" struct bmp_file { CHAR8 signature[2]; diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 0c5ee4e9ff..2cd5c33cb6 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -16,12 +16,12 @@ #include <efi.h> #include <efilib.h> -#include "util.h" -#include "pefile.h" #include "disk.h" #include "graphics.h" -#include "splash.h" #include "linux.h" +#include "pefile.h" +#include "splash.h" +#include "util.h" /* magic string to find in the binary image */ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " VERSION " ####"; diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h index bdb4b00199..8432a2a119 100644 --- a/src/bootchart/bootchart.h +++ b/src/bootchart/bootchart.h @@ -25,6 +25,7 @@ ***/ #include <stdbool.h> + #include "list.h" #define MAXCPUS 16 diff --git a/src/bootchart/store.h b/src/bootchart/store.h index bbb4796efd..4d2e0d439f 100644 --- a/src/bootchart/store.h +++ b/src/bootchart/store.h @@ -25,6 +25,7 @@ ***/ #include <dirent.h> + #include "bootchart.h" double gettime_ns(void); diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c index 05330c0577..2bf473ffc1 100644 --- a/src/bootchart/svg.c +++ b/src/bootchart/svg.c @@ -22,25 +22,25 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fcntl.h> +#include <limits.h> #include <stdio.h> #include <string.h> +#include <sys/utsname.h> #include <time.h> -#include <limits.h> #include <unistd.h> -#include <sys/utsname.h> -#include <fcntl.h> #include "alloc-util.h" #include "architecture.h" -#include "util.h" +#include "bootchart.h" +#include "fd-util.h" #include "fileio.h" +#include "list.h" #include "macro.h" #include "store.h" #include "svg.h" -#include "bootchart.h" -#include "list.h" #include "utf8.h" -#include "fd-util.h" +#include "util.h" #define time_to_graph(t) ((t) * arg_scale_x) #define ps_to_graph(n) ((n) * arg_scale_y) diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c index f0834e9525..debd58ce8b 100644 --- a/src/bus-proxyd/bus-xml-policy.c +++ b/src/bus-proxyd/bus-xml-policy.c @@ -392,11 +392,11 @@ static int file_load(Policy *p, const char *path) { } else { PolicyItem *first; - first = hashmap_get(p->user_items, UINT32_TO_PTR(i->uid)); + first = hashmap_get(p->user_items, UID_TO_PTR(i->uid)); item_append(i, &first); i->uid_valid = true; - r = hashmap_replace(p->user_items, UINT32_TO_PTR(i->uid), first); + r = hashmap_replace(p->user_items, UID_TO_PTR(i->uid), first); if (r < 0) { LIST_REMOVE(items, first, i); return log_oom(); @@ -424,11 +424,11 @@ static int file_load(Policy *p, const char *path) { } else { PolicyItem *first; - first = hashmap_get(p->group_items, UINT32_TO_PTR(i->gid)); + first = hashmap_get(p->group_items, GID_TO_PTR(i->gid)); item_append(i, &first); i->gid_valid = true; - r = hashmap_replace(p->group_items, UINT32_TO_PTR(i->gid), first); + r = hashmap_replace(p->group_items, GID_TO_PTR(i->gid), first); if (r < 0) { LIST_REMOVE(items, first, i); return log_oom(); @@ -787,7 +787,7 @@ static int policy_check(Policy *p, const struct policy_check_filter *filter) { verdict = check_policy_items(p->default_items, filter); if (filter->gid != GID_INVALID) { - items = hashmap_get(p->group_items, UINT32_TO_PTR(filter->gid)); + items = hashmap_get(p->group_items, GID_TO_PTR(filter->gid)); if (items) { v = check_policy_items(items, filter); if (v != DUNNO) @@ -796,7 +796,7 @@ static int policy_check(Policy *p, const struct policy_check_filter *filter) { } if (filter->uid != UID_INVALID) { - items = hashmap_get(p->user_items, UINT32_TO_PTR(filter->uid)); + items = hashmap_get(p->user_items, UID_TO_PTR(filter->uid)); if (items) { v = check_policy_items(items, filter); if (v != DUNNO) @@ -1155,7 +1155,7 @@ static void dump_hashmap_items(Hashmap *h) { void *k; HASHMAP_FOREACH_KEY(i, k, h, j) { - printf("\t%s Item for %u:\n", draw_special_char(DRAW_ARROW), PTR_TO_UINT(k)); + printf("\t%s Item for " UID_FMT ":\n", draw_special_char(DRAW_ARROW), PTR_TO_UID(k)); dump_items(i, "\t\t"); } } diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h index 8f0ab8f17f..8dde0cb868 100644 --- a/src/bus-proxyd/bus-xml-policy.h +++ b/src/bus-proxyd/bus-xml-policy.h @@ -23,8 +23,8 @@ #include <pthread.h> -#include "list.h" #include "hashmap.h" +#include "list.h" typedef enum PolicyItemType { _POLICY_ITEM_TYPE_UNSET = 0, diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h index da3834f8b0..9f68902441 100644 --- a/src/bus-proxyd/driver.h +++ b/src/bus-proxyd/driver.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "bus-xml-policy.h" #include "proxy.h" diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c index 6e47884209..2dc5fe631b 100644 --- a/src/bus-proxyd/stdio-bridge.c +++ b/src/bus-proxyd/stdio-bridge.c @@ -27,8 +27,8 @@ #include <string.h> #include <unistd.h> -#include "sd-daemon.h" #include "sd-bus.h" +#include "sd-daemon.h" #include "alloc-util.h" #include "bus-internal.h" diff --git a/src/core/.gitignore b/src/core/.gitignore index f293bbdc93..465b4fcc20 100644 --- a/src/core/.gitignore +++ b/src/core/.gitignore @@ -1,2 +1,3 @@ /macros.systemd +/triggers.systemd /systemd.pc diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c index 3ae46d8cfb..0a484d89fc 100644 --- a/src/core/audit-fd.c +++ b/src/core/audit-fd.c @@ -21,16 +21,17 @@ #include <errno.h> + #include "audit-fd.h" #ifdef HAVE_AUDIT -#include <stdbool.h> #include <libaudit.h> +#include <stdbool.h> +#include "fd-util.h" #include "log.h" #include "util.h" -#include "fd-util.h" static bool initialized = false; static int audit_fd; diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h index 4a31f4c4be..f6c5f7c5af 100644 --- a/src/core/bus-endpoint.h +++ b/src/core/bus-endpoint.h @@ -24,8 +24,8 @@ typedef struct BusEndpoint BusEndpoint; typedef struct BusEndpointPolicy BusEndpointPolicy; -#include "hashmap.h" #include "bus-policy.h" +#include "hashmap.h" struct BusEndpointPolicy { char *name; diff --git a/src/core/bus-policy.h b/src/core/bus-policy.h index 3b04f5457a..2f61289185 100644 --- a/src/core/bus-policy.h +++ b/src/core/bus-policy.h @@ -21,9 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "kdbus.h" #include "list.h" #include "macro.h" -#include "kdbus.h" typedef struct BusNamePolicy BusNamePolicy; diff --git a/src/core/cgroup.c b/src/core/cgroup.c index bed01fde21..d122175417 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -217,7 +217,7 @@ static int whitelist_device(const char *path, const char *node, const char *acc) r = cg_set_attribute("devices", path, "devices.allow", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set devices.allow on %s: %m", path); return r; @@ -288,7 +288,7 @@ static int whitelist_major(const char *path, const char *name, char type, const r = cg_set_attribute("devices", path, "devices.allow", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set devices.allow on %s: %m", path); } @@ -328,13 +328,13 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT); r = cg_set_attribute("cpu", path, "cpu.shares", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set cpu.shares on %s: %m", path); sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC); r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set cpu.cfs_period_us on %s: %m", path); if (c->cpu_quota_per_sec_usec != USEC_INFINITY) { @@ -343,7 +343,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u } else r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1"); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set cpu.cfs_quota_us on %s: %m", path); } @@ -359,7 +359,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT); r = cg_set_attribute("blkio", path, "blkio.weight", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set blkio.weight on %s: %m", path); /* FIXME: no way to reset this list */ @@ -373,7 +373,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight); r = cg_set_attribute("blkio", path, "blkio.weight_device", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set blkio.weight_device on %s: %m", path); } } @@ -392,7 +392,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth); r = cg_set_attribute("blkio", path, a, buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set %s on %s: %m", a, path); } } @@ -416,7 +416,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u } if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set memory.limit_in_bytes/memory.max on %s: %m", path); } @@ -432,7 +432,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u else r = cg_set_attribute("devices", path, "devices.allow", "a"); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to reset devices.list on %s: %m", path); if (c->device_policy == CGROUP_CLOSED || @@ -494,7 +494,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u r = cg_set_attribute("pids", path, "pids.max", "max"); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set pids.max on %s: %m", path); } @@ -505,7 +505,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u r = cg_set_attribute("net_cls", path, "net_cls.classid", buf); if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r, + log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set net_cls.classid on %s: %m", path); } } diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 457544b49f..1b18d06652 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -112,8 +112,8 @@ struct CGroupContext { bool delegate; }; -#include "unit.h" #include "cgroup-util.h" +#include "unit.h" void cgroup_context_init(CGroupContext *c); void cgroup_context_done(CGroupContext *c); diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c index 45f2c2ffd6..54830a515b 100644 --- a/src/core/dbus-automount.c +++ b/src/core/dbus-automount.c @@ -21,8 +21,8 @@ #include "automount.h" #include "bus-util.h" -#include "string-util.h" #include "dbus-automount.h" +#include "string-util.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 05ac89c3c0..445b237643 100644 --- a/src/core/dbus-busname.c +++ b/src/core/dbus-busname.c @@ -21,9 +21,9 @@ #include "bus-util.h" #include "busname.h" +#include "dbus-busname.h" #include "string-util.h" #include "unit.h" -#include "dbus-busname.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult); diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c index cb156fd37c..97e4a47556 100644 --- a/src/core/dbus-device.c +++ b/src/core/dbus-device.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "device.h" #include "dbus-device.h" +#include "device.h" +#include "unit.h" const sd_bus_vtable bus_device_vtable[] = { SD_BUS_VTABLE_START(0), diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c index 3b8116281c..c633eb1b76 100644 --- a/src/core/dbus-kill.c +++ b/src/core/dbus-kill.c @@ -19,11 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "signal-util.h" #include "bus-util.h" - -#include "kill.h" #include "dbus-kill.h" +#include "kill.h" +#include "signal-util.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode); diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h index 794c402048..1d32fca547 100644 --- a/src/core/dbus-kill.h +++ b/src/core/dbus-kill.h @@ -23,8 +23,8 @@ #include "sd-bus.h" -#include "unit.h" #include "kill.h" +#include "unit.h" extern const sd_bus_vtable bus_kill_vtable[]; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index d3bcc795ae..2562396180 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -630,9 +630,13 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s if (r < 0) return r; - u = manager_get_unit(m, name); - if (!u) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = bus_unit_check_load_state(u, error); + if (r < 0) + return r; return bus_unit_method_set_properties(message, u, error); } @@ -644,6 +648,7 @@ static int transient_unit_from_message( Unit **unit, sd_bus_error *error) { + UnitType t; Unit *u; int r; @@ -651,12 +656,18 @@ static int transient_unit_from_message( assert(message); assert(name); + t = unit_name_to_type(name); + if (t < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name or type."); + + if (!unit_vtable[t]->can_transient) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t)); + r = manager_load_unit(m, name, NULL, error, &u); if (r < 0) return r; - if (u->load_state != UNIT_NOT_FOUND || - set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) + if (!unit_is_pristine(u)) return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); /* OK, the unit failed to load and is unreferenced, now let's @@ -670,6 +681,9 @@ static int transient_unit_from_message( if (r < 0) return r; + /* Now load the missing bits of the unit we just created */ + manager_dispatch_load_queue(m); + *unit = u; return 0; @@ -680,8 +694,6 @@ static int transient_aux_units_from_message( sd_bus_message *message, sd_bus_error *error) { - Unit *u; - char *name = NULL; int r; assert(m); @@ -692,20 +704,17 @@ static int transient_aux_units_from_message( return r; while ((r = sd_bus_message_enter_container(message, 'r', "sa(sv)")) > 0) { + const char *name = NULL; + Unit *u; + r = sd_bus_message_read(message, "s", &name); if (r < 0) return r; r = transient_unit_from_message(m, message, name, &u, error); - if (r < 0 && r != -EEXIST) + if (r < 0) return r; - if (r != -EEXIST) { - r = unit_load(u); - if (r < 0) - return r; - } - r = sd_bus_message_exit_container(message); if (r < 0) return r; @@ -724,7 +733,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata, const char *name, *smode; Manager *m = userdata; JobMode mode; - UnitType t; Unit *u; int r; @@ -739,13 +747,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata, if (r < 0) return r; - t = unit_name_to_type(name); - if (t < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type."); - - if (!unit_vtable[t]->can_transient) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t)); - mode = job_mode_from_string(smode); if (mode < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode); @@ -764,13 +765,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata, if (r < 0) return r; - /* And load this stub fully */ - r = unit_load(u); - if (r < 0) - return r; - - manager_dispatch_load_queue(m); - /* Finally, start it */ return bus_unit_queue_job(message, u, JOB_START, mode, false, error); } @@ -1960,6 +1954,7 @@ const sd_bus_vtable bus_manager_vtable[] = { 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("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), 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), diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index 90a6d37073..bc5751a10d 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -23,10 +23,10 @@ #include "dbus-cgroup.h" #include "dbus-execute.h" #include "dbus-kill.h" +#include "dbus-mount.h" #include "mount.h" #include "string-util.h" #include "unit.h" -#include "dbus-mount.h" static int property_get_what( sd_bus *bus, diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c index 9e32b5fb06..e0544e9161 100644 --- a/src/core/dbus-path.c +++ b/src/core/dbus-path.c @@ -20,10 +20,10 @@ ***/ #include "bus-util.h" +#include "dbus-path.h" #include "path.h" #include "string-util.h" #include "unit.h" -#include "dbus-path.h" static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult); diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h index 33beda47b7..4fb0b25e09 100644 --- a/src/core/dbus-scope.h +++ b/src/core/dbus-scope.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_scope_vtable[]; diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h index aab9f7aa26..a67b64ab5b 100644 --- a/src/core/dbus-service.h +++ b/src/core/dbus-service.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_service_vtable[]; diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c index 09e78d1f33..469e3e1c93 100644 --- a/src/core/dbus-slice.c +++ b/src/core/dbus-slice.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" -#include "slice.h" #include "dbus-cgroup.h" #include "dbus-slice.h" +#include "slice.h" +#include "unit.h" const sd_bus_vtable bus_slice_vtable[] = { SD_BUS_VTABLE_START(0), diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h index eadc3b1a9c..117d11471b 100644 --- a/src/core/dbus-slice.h +++ b/src/core/dbus-slice.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_slice_vtable[]; diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index be5ef261a6..895dd07753 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -150,6 +150,7 @@ const sd_bus_vtable bus_socket_vtable[] = { 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), + SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h index 17164d9871..8dad6ea2e9 100644 --- a/src/core/dbus-socket.h +++ b/src/core/dbus-socket.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_socket_vtable[]; diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c index 603ca95fd9..f2a0f1d172 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -23,10 +23,10 @@ #include "bus-util.h" #include "dbus-cgroup.h" #include "dbus-execute.h" +#include "dbus-swap.h" #include "string-util.h" #include "swap.h" #include "unit.h" -#include "dbus-swap.h" static int property_get_priority( sd_bus *bus, diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h index 9469f68ab8..a414ca7f75 100644 --- a/src/core/dbus-swap.h +++ b/src/core/dbus-swap.h @@ -23,6 +23,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_swap_vtable[]; diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c index 350f5c3ed2..654bcf1a29 100644 --- a/src/core/dbus-target.c +++ b/src/core/dbus-target.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" #include "dbus-target.h" +#include "unit.h" const sd_bus_vtable bus_target_vtable[] = { SD_BUS_VTABLE_START(0), diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index a8a280d961..ec301df6d7 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -180,8 +180,10 @@ const sd_bus_vtable bus_timer_vtable[] = { BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; @@ -282,8 +284,23 @@ static int bus_timer_set_transient_property( return 1; - } else if (streq(name, "WakeSystem")) { + } else if (streq(name, "RandomizedDelayUSec")) { + usec_t u = 0; + + r = sd_bus_message_read(message, "t", &u); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + char time[FORMAT_TIMESPAN_MAX]; + + t->random_usec = u; + unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); + } + + return 1; + } else if (streq(name, "WakeSystem")) { int b; r = sd_bus_message_read(message, "b", &b); @@ -292,11 +309,24 @@ static int bus_timer_set_transient_property( if (mode != UNIT_CHECK) { t->wake_system = b; - unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system)); + unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b)); } return 1; + } else if (streq(name, "RemainAfterElapse")) { + int b; + + r = sd_bus_message_read(message, "b", &b); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + t->remain_after_elapse = b; + unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b)); + } + + return 1; } return 0; diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h index 103172f055..ca35c4b8c1 100644 --- a/src/core/dbus-timer.h +++ b/src/core/dbus-timer.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_timer_vtable[]; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index d9b7382c82..66b465a0b7 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1251,3 +1251,20 @@ int bus_unit_set_properties( return n; } + +int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { + + if (u->load_state == UNIT_LOADED) + return 0; + + /* Give a better description of the unit error when + * possible. Note that in the case of UNIT_MASKED, load_error + * is not set. */ + if (u->load_state == UNIT_MASKED) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit is masked."); + + if (u->load_state == UNIT_NOT_FOUND) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit not found."); + + return sd_bus_error_set_errnof(error, u->load_error, "Unit is not loaded properly: %m."); +} diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index b622e0ae8d..ac9ee2d6b8 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_unit_vtable[]; @@ -37,3 +38,5 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error); int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error); int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error); + +int bus_unit_check_load_state(Unit *u, sd_bus_error *error); diff --git a/src/core/execute.c b/src/core/execute.c index 07979bf8b3..677480cbe1 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2414,8 +2414,8 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { for (i = 0; i < RLIM_NLIMITS; i++) if (c->rlimit[i]) - fprintf(f, "%s%s: "RLIM_FMT"\n", - prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max); + fprintf(f, "%s%s: " RLIM_FMT " " RLIM_FMT "\n", + prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur, c->rlimit[i]->rlim_max); if (c->ioprio_set) { _cleanup_free_ char *class_str = NULL; diff --git a/src/core/execute.h b/src/core/execute.h index 1faff160cb..be5be9f531 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -27,16 +27,16 @@ typedef struct ExecContext ExecContext; typedef struct ExecRuntime ExecRuntime; typedef struct ExecParameters ExecParameters; -#include <sys/capability.h> +#include <sched.h> #include <stdbool.h> #include <stdio.h> -#include <sched.h> +#include <sys/capability.h> -#include "list.h" +#include "bus-endpoint.h" #include "fdset.h" +#include "list.h" #include "missing.h" #include "namespace.h" -#include "bus-endpoint.h" typedef enum ExecUtmpMode { EXEC_UTMP_INIT, @@ -204,8 +204,8 @@ struct ExecContext { BusEndpoint *bus_endpoint; }; -#include "cgroup.h" #include "cgroup-util.h" +#include "cgroup.h" struct ExecParameters { char **argv; diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c index 3645f9c515..d92a9a764f 100644 --- a/src/core/hostname-setup.c +++ b/src/core/hostname-setup.c @@ -25,12 +25,12 @@ #include "alloc-util.h" #include "fileio.h" +#include "hostname-setup.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) { int r; diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c index 9572fa17d9..4f42ae6f31 100644 --- a/src/core/ima-setup.c +++ b/src/core/ima-setup.c @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> +#include <unistd.h> #include "fd-util.h" #include "fileio.h" diff --git a/src/core/job.c b/src/core/job.c index 53e0947215..9654590635 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -500,17 +500,26 @@ static void job_change_type(Job *j, JobType newtype) { } static int job_perform_on_unit(Job **j) { - /* While we execute this operation the job might go away (for - * example: because it finishes immediately or is replaced by a new, - * conflicting job.) To make sure we don't access a freed job later on - * we store the id here, so that we can verify the job is still - * valid. */ - Manager *m = (*j)->manager; - Unit *u = (*j)->unit; - JobType t = (*j)->type; - uint32_t id = (*j)->id; + uint32_t id; + Manager *m; + JobType t; + Unit *u; int r; + /* While we execute this operation the job might go away (for + * example: because it finishes immediately or is replaced by + * a new, conflicting job.) To make sure we don't access a + * freed job later on we store the id here, so that we can + * verify the job is still valid. */ + + assert(j); + assert(*j); + + m = (*j)->manager; + u = (*j)->unit; + t = (*j)->type; + id = (*j)->id; + switch (t) { case JOB_START: r = unit_start(u); @@ -518,6 +527,7 @@ static int job_perform_on_unit(Job **j) { case JOB_RESTART: t = JOB_STOP; + /* fall through */ case JOB_STOP: r = unit_stop(u); break; @@ -617,8 +627,7 @@ int job_run_and_invalidate(Job *j) { } _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) { - const char *format; - const UnitStatusMessageFormats *format_table; + static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = { [JOB_DONE] = "Started %s.", [JOB_TIMEOUT] = "Timed out starting %s.", @@ -644,11 +653,14 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR [JOB_SKIPPED] = "%s is not active.", }; + const UnitStatusMessageFormats *format_table; + const char *format; + assert(u); assert(t >= 0); assert(t < _JOB_TYPE_MAX); - if (t == JOB_START || t == JOB_STOP || t == JOB_RESTART) { + if (IN_SET(t, JOB_START, JOB_STOP, JOB_RESTART)) { format_table = &UNIT_VTABLE(u)->status_message_formats; if (format_table) { format = t == JOB_START ? format_table->finished_start_job[result] : @@ -672,7 +684,6 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR } static void job_print_status_message(Unit *u, JobType t, JobResult result) { - const char *format; static const char* const job_result_status_table[_JOB_RESULT_MAX] = { [JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL, [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL, @@ -683,10 +694,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL, }; + const char *format; + assert(u); assert(t >= 0); assert(t < _JOB_TYPE_MAX); + /* Reload status messages have traditionally not been printed to console. */ + if (t == JOB_RELOAD) + return; + format = job_get_status_message_format(u, t, result); if (!format) return; @@ -699,10 +716,10 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { REENABLE_WARNING; if (t == JOB_START && result == JOB_FAILED) { - _cleanup_free_ char *quoted = shell_maybe_quote(u->id); + _cleanup_free_ char *quoted; - manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, - "See 'systemctl status %s' for details.", strna(quoted)); + quoted = shell_maybe_quote(u->id); + manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted)); } } @@ -740,13 +757,22 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { snprintf(buf, sizeof(buf), format, unit_description(u)); REENABLE_WARNING; - if (t == JOB_START) + switch (t) { + + case JOB_START: mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED; - else if (t == JOB_STOP || t == JOB_RESTART) - mid = SD_MESSAGE_UNIT_STOPPED; - else if (t == JOB_RELOAD) + break; + + case JOB_RELOAD: mid = SD_MESSAGE_UNIT_RELOADED; - else { + break; + + case JOB_STOP: + case JOB_RESTART: + mid = SD_MESSAGE_UNIT_STOPPED; + break; + + default: log_struct(job_result_log_level[result], LOG_UNIT_ID(u), LOG_MESSAGE("%s", buf), @@ -770,10 +796,7 @@ static void job_emit_status_message(Unit *u, JobType t, JobResult result) { return; job_log_status_message(u, t, result); - - /* Reload status messages have traditionally not been printed to console. */ - if (t != JOB_RELOAD) - job_print_status_message(u, t, result); + job_print_status_message(u, t, result); } static void job_fail_dependencies(Unit *u, UnitDependency d) { diff --git a/src/core/job.h b/src/core/job.h index 60d8bd4f3e..118b24e5b7 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -26,6 +26,7 @@ #include "sd-event.h" #include "list.h" +#include "unit-name.h" typedef struct Job Job; typedef struct JobDependency JobDependency; diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index 651f79a1fe..a6ab8cf4b3 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -19,17 +19,17 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <string.h> +#include <unistd.h> #ifdef HAVE_KMOD #include <libkmod.h> #endif -#include "macro.h" -#include "capability-util.h" #include "bus-util.h" +#include "capability-util.h" #include "kmod-setup.h" +#include "macro.h" #ifdef HAVE_KMOD static void systemd_kmod_log( diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index 11566af51b..3fa66f91aa 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -20,13 +20,13 @@ ***/ -#include "unit.h" +#include "conf-parser.h" #include "load-dropin.h" +#include "load-fragment.h" #include "log.h" #include "strv.h" #include "unit-name.h" -#include "conf-parser.h" -#include "load-fragment.h" +#include "unit.h" static int add_dependency_consumer( UnitDependency dependency, diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h index 1e018c4525..93ffcc4a72 100644 --- a/src/core/load-dropin.h +++ b/src/core/load-dropin.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unit.h" #include "dropin.h" +#include "unit.h" /* Read service data supplementary drop-in directories */ diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 4c5376d601..0408b9a829 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -126,7 +126,7 @@ $1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, $1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) $1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context) $1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting) -$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context) +$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max) $1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate) $1.NetClass, config_parse_netclass, 0, offsetof($1, cgroup_context)' )m4_dnl @@ -249,6 +249,7 @@ Socket.ListenNetlink, config_parse_socket_listen, SOCKET_SOCK Socket.ListenSpecial, config_parse_socket_listen, SOCKET_SPECIAL, 0 Socket.ListenMessageQueue, config_parse_socket_listen, SOCKET_MQUEUE, 0 Socket.ListenUSBFunction, config_parse_socket_listen, SOCKET_USB_FUNCTION, 0 +Socket.SocketProtocol, config_parse_socket_protocol, 0, 0 Socket.BindIPv6Only, config_parse_socket_bind, 0, 0, Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog) Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0 @@ -344,7 +345,9 @@ Timer.OnUnitActiveSec, config_parse_timer, 0, Timer.OnUnitInactiveSec, config_parse_timer, 0, 0 Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent) Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system) +Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse) Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec) +Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_usec) Timer.Unit, config_parse_trigger_unit, 0, 0 m4_dnl Path.PathExists, config_parse_path_spec, 0, 0 diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 62cad0a0c0..3c124495b6 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -32,8 +32,8 @@ #include <sys/resource.h> #include <sys/stat.h> -#include "alloc-util.h" #include "af-list.h" +#include "alloc-util.h" #include "bus-error.h" #include "bus-internal.h" #include "bus-util.h" @@ -421,6 +421,37 @@ int config_parse_socket_listen(const char *unit, return 0; } +int config_parse_socket_protocol(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + Socket *s; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + s = SOCKET(data); + + if (streq(rvalue, "udplite")) + s->socket_protocol = IPPROTO_UDPLITE; + else if (streq(rvalue, "sctp")) + s->socket_protocol = IPPROTO_SCTP; + else { + log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue); + return 0; + } + + return 0; +} + int config_parse_socket_bind(const char *unit, const char *filename, unsigned line, @@ -1058,59 +1089,123 @@ int config_parse_bounding_set( return 0; } -int config_parse_limit( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +static int rlim_parse_u64(const char *val, rlim_t *res) { + int r = 0; - struct rlimit **rl = data; - rlim_t v; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - rl += ltype; - - if (streq(rvalue, "infinity")) - v = RLIM_INFINITY; + if (streq(val, "infinity")) + *res = RLIM_INFINITY; else { uint64_t u; /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */ assert_cc(sizeof(rlim_t) == sizeof(uint64_t)); - r = safe_atou64(rvalue, &u); + r = safe_atou64(val, &u); if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) r = -ERANGE; - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); - return 0; - } + if (r == 0) + *res = (rlim_t) u; + } + return r; +} + +static int rlim_parse_size(const char *val, rlim_t *res) { + int r = 0; + + if (streq(val, "infinity")) + *res = RLIM_INFINITY; + else { + uint64_t u; + + r = parse_size(val, 1024, &u); + if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) + r = -ERANGE; + if (r == 0) + *res = (rlim_t) u; + } + return r; +} + +static int rlim_parse_sec(const char *val, rlim_t *res) { + int r = 0; + + if (streq(val, "infinity")) + *res = RLIM_INFINITY; + else { + usec_t t; + + r = parse_sec(val, &t); + if (r < 0) + return r; + if (t == USEC_INFINITY) + *res = RLIM_INFINITY; + else + *res = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); - v = (rlim_t) u; } + return r; +} + +static int rlim_parse_usec(const char *val, rlim_t *res) { + int r = 0; + + if (streq(val, "infinity")) + *res = RLIM_INFINITY; + else { + usec_t t; + + r = parse_time(val, &t, 1); + if (r < 0) + return r; + if (t == USEC_INFINITY) + *res = RLIM_INFINITY; + else + *res = (rlim_t) t; + } + return r; +} + +static int parse_rlimit_range( + const char *unit, + const char *filename, + unsigned line, + const char *value, + struct rlimit **rl, + int (*rlim_parser)(const char *, rlim_t *)) { + + const char *whole_value = value; + rlim_t soft, hard; + _cleanup_free_ char *sword = NULL, *hword = NULL; + int nwords, r; + + assert(value); + + /* <value> or <soft:hard> */ + nwords = extract_many_words(&value, ":", EXTRACT_DONT_COALESCE_SEPARATORS, &sword, &hword, NULL); + r = nwords < 0 ? nwords : nwords == 0 ? -EINVAL : 0; + + if (r == 0) + r = rlim_parser(sword, &soft); + if (r == 0 && nwords == 2) + r = rlim_parser(hword, &hard); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", whole_value); + return 0; + } + if (nwords == 2 && soft > hard) + return log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid resource value ("RLIM_FMT" > "RLIM_FMT"), ignoring: %s", soft, hard, whole_value); if (!*rl) { *rl = new(struct rlimit, 1); if (!*rl) return log_oom(); } - - (*rl)->rlim_cur = (*rl)->rlim_max = v; + (*rl)->rlim_cur = soft; + (*rl)->rlim_max = nwords == 2 ? hard : soft; return 0; } -int config_parse_bytes_limit( +int config_parse_limit( const char *unit, const char *filename, unsigned line, @@ -1123,8 +1218,6 @@ int config_parse_bytes_limit( void *userdata) { struct rlimit **rl = data; - rlim_t bytes; - int r; assert(filename); assert(lvalue); @@ -1132,31 +1225,30 @@ int config_parse_bytes_limit( assert(data); rl += ltype; + return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_u64); +} - if (streq(rvalue, "infinity")) - bytes = RLIM_INFINITY; - else { - uint64_t u; - - r = parse_size(rvalue, 1024, &u); - if (r >= 0 && u >= (uint64_t) RLIM_INFINITY) - r = -ERANGE; - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); - return 0; - } +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) { - bytes = (rlim_t) u; - } + struct rlimit **rl = data; - if (!*rl) { - *rl = new(struct rlimit, 1); - if (!*rl) - return log_oom(); - } + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); - (*rl)->rlim_cur = (*rl)->rlim_max = bytes; - return 0; + rl += ltype; + return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_size); } int config_parse_sec_limit( @@ -1172,8 +1264,6 @@ int config_parse_sec_limit( void *userdata) { struct rlimit **rl = data; - rlim_t seconds; - int r; assert(filename); assert(lvalue); @@ -1181,35 +1271,9 @@ int config_parse_sec_limit( assert(data); rl += ltype; - - if (streq(rvalue, "infinity")) - seconds = RLIM_INFINITY; - else { - usec_t t; - - r = parse_sec(rvalue, &t); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); - return 0; - } - - if (t == USEC_INFINITY) - seconds = RLIM_INFINITY; - else - seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC)); - } - - if (!*rl) { - *rl = new(struct rlimit, 1); - if (!*rl) - return log_oom(); - } - - (*rl)->rlim_cur = (*rl)->rlim_max = seconds; - return 0; + return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_sec); } - int config_parse_usec_limit( const char *unit, const char *filename, @@ -1223,8 +1287,6 @@ int config_parse_usec_limit( void *userdata) { struct rlimit **rl = data; - rlim_t useconds; - int r; assert(filename); assert(lvalue); @@ -1232,33 +1294,10 @@ int config_parse_usec_limit( assert(data); rl += ltype; + return parse_rlimit_range(unit, filename, line, rvalue, rl, rlim_parse_usec); +} - if (streq(rvalue, "infinity")) - useconds = RLIM_INFINITY; - else { - usec_t t; - - r = parse_time(rvalue, &t, 1); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); - return 0; - } - if (t == USEC_INFINITY) - useconds = RLIM_INFINITY; - else - useconds = (rlim_t) t; - } - - if (!*rl) { - *rl = new(struct rlimit, 1); - if (!*rl) - return log_oom(); - } - - (*rl)->rlim_cur = (*rl)->rlim_max = useconds; - return 0; -} #ifdef HAVE_SYSV_COMPAT int config_parse_sysv_priority(const char *unit, @@ -1305,38 +1344,28 @@ int config_parse_exec_mount_flags(const char *unit, void *data, void *userdata) { - ExecContext *c = data; - const char *word, *state; - size_t l; + unsigned long flags = 0; + ExecContext *c = data; assert(filename); assert(lvalue); assert(rvalue); assert(data); - FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) { - _cleanup_free_ char *t; - - t = strndup(word, l); - if (!t) - return log_oom(); - - if (streq(t, "shared")) - flags = MS_SHARED; - else if (streq(t, "slave")) - flags = MS_SLAVE; - else if (streq(t, "private")) - flags = MS_PRIVATE; - else { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring: %s", t, rvalue); - return 0; - } + if (streq(rvalue, "shared")) + flags = MS_SHARED; + else if (streq(rvalue, "slave")) + flags = MS_SLAVE; + else if (streq(rvalue, "private")) + flags = MS_PRIVATE; + else { + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue); + return 0; } - if (!isempty(state)) - log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring."); c->mount_flags = flags; + return 0; } @@ -2991,12 +3020,11 @@ int config_parse_tasks_max( void *data, void *userdata) { - CGroupContext *c = data; - uint64_t u; + uint64_t *tasks_max = data, u; int r; if (isempty(rvalue) || streq(rvalue, "infinity")) { - c->tasks_max = (uint64_t) -1; + *tasks_max = (uint64_t) -1; return 0; } @@ -3006,7 +3034,7 @@ int config_parse_tasks_max( return 0; } - c->tasks_max = u; + *tasks_max = u; return 0; } diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 62300c10f9..a451fc164a 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -38,6 +38,7 @@ int config_parse_unit_path_printf(const char *unit, const char *filename, unsign int config_parse_unit_path_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_documentation(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_socket_listen(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_socket_protocol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_socket_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_exec_nice(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_oom_score_adjust(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index bd632131b9..4c8d920389 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -24,12 +24,12 @@ #include "env-util.h" #include "fileio.h" +#include "locale-setup.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/macros.systemd.in b/src/core/macros.systemd.in index bea6ef1da3..2cace3d3ba 100644 --- a/src/core/macros.systemd.in +++ b/src/core/macros.systemd.in @@ -1,4 +1,4 @@ -# -*- Mode: makefile; indent-tabs-mode: t -*- */ +# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */ # # This file is part of systemd. # @@ -39,17 +39,16 @@ Requires(postun): systemd \ %systemd_post() \ if [ $1 -eq 1 ] ; then \ # Initial installation \ - systemctl preset %{?*} >/dev/null 2>&1 || : \ + systemctl --no-reload preset %{?*} >/dev/null 2>&1 || : \ fi \ %{nil} -%systemd_user_post() %systemd_post --user --global %{?*} +%systemd_user_post() %{expand:%systemd_post \\--user \\--global %%{?*}} %systemd_preun() \ if [ $1 -eq 0 ] ; then \ # Package removal, not upgrade \ - systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \ - systemctl stop %{?*} > /dev/null 2>&1 || : \ + systemctl --no-reload disable --now %{?*} > /dev/null 2>&1 || : \ fi \ %{nil} @@ -60,14 +59,11 @@ if [ $1 -eq 0 ] ; then \ fi \ %{nil} -%systemd_postun() \ -systemctl daemon-reload >/dev/null 2>&1 || : \ -%{nil} +%systemd_postun() %{nil} %systemd_user_postun() %{nil} %systemd_postun_with_restart() \ -systemctl daemon-reload >/dev/null 2>&1 || : \ if [ $1 -ge 1 ] ; then \ # Package upgrade, not uninstall \ systemctl try-restart %{?*} >/dev/null 2>&1 || : \ diff --git a/src/core/main.c b/src/core/main.c index fcfd6d375d..ba1feedb9a 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -37,8 +37,8 @@ #include <valgrind/valgrind.h> #endif -#include "sd-daemon.h" #include "sd-bus.h" +#include "sd-daemon.h" #include "alloc-util.h" #include "architecture.h" @@ -125,7 +125,8 @@ static FILE* arg_serialization = NULL; static bool arg_default_cpu_accounting = false; static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; -static bool arg_default_tasks_accounting = false; +static bool arg_default_tasks_accounting = true; +static uint64_t arg_default_tasks_max = UINT64_C(512); static void pager_open_if_enabled(void) { @@ -657,7 +658,7 @@ static int parse_config_file(void) { { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, - { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] }, + { "Manager", "DefaultLimitCPU", config_parse_sec_limit, 0, &arg_default_rlimit[RLIMIT_CPU] }, { "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] }, @@ -672,11 +673,12 @@ static int parse_config_file(void) { { "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] }, + { "Manager", "DefaultLimitRTTIME", config_parse_usec_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting }, { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting }, { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting }, { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting }, + { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max }, {} }; @@ -712,6 +714,7 @@ static void manager_set_defaults(Manager *m) { m->default_blockio_accounting = arg_default_blockio_accounting; m->default_memory_accounting = arg_default_memory_accounting; m->default_tasks_accounting = arg_default_tasks_accounting; + m->default_tasks_max = arg_default_tasks_max; manager_set_default_rlimits(m, arg_default_rlimit); manager_environment_add(m, NULL, arg_default_environment); diff --git a/src/core/manager.c b/src/core/manager.c index f695b8a66c..edff6758c5 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -577,6 +577,8 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) { m->running_as = running_as; m->exit_code = _MANAGER_EXIT_CODE_INVALID; m->default_timer_accuracy_usec = USEC_PER_MINUTE; + m->default_tasks_accounting = true; + m->default_tasks_max = UINT64_C(512); /* Prepare log fields we can use for structured logging */ m->unit_log_field = unit_log_fields[running_as]; diff --git a/src/core/manager.h b/src/core/manager.h index bc3f02f872..f6903a5c34 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -21,12 +21,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <libmount.h> #include <stdbool.h> #include <stdio.h> -#include <libmount.h> #include "sd-bus.h" #include "sd-event.h" + #include "cgroup-util.h" #include "fdset.h" #include "hashmap.h" @@ -260,6 +261,7 @@ struct Manager { bool default_blockio_accounting; bool default_tasks_accounting; + uint64_t default_tasks_max; usec_t default_timer_accuracy_usec; struct rlimit *rlimit[_RLIMIT_MAX]; diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index b2596d1cd1..2b8d590ed1 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -19,11 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/mount.h> #include <errno.h> +#include <ftw.h> #include <stdlib.h> +#include <sys/mount.h> #include <unistd.h> -#include <ftw.h> #include "alloc-util.h" #include "bus-util.h" diff --git a/src/core/mount.c b/src/core/mount.c index 9b44357e90..2ad4ad4f42 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -335,7 +335,7 @@ static int mount_add_device_links(Mount *m) { if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM) device_wants_mount = true; - r = unit_add_node_link(UNIT(m), p->what, device_wants_mount); + r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES); if (r < 0) return r; diff --git a/src/core/mount.h b/src/core/mount.h index 83d14ae713..9f78aa9075 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -23,8 +23,8 @@ typedef struct Mount Mount; -#include "kill.h" #include "execute.h" +#include "kill.h" typedef enum MountExecCommand { MOUNT_EXEC_MOUNT, diff --git a/src/core/scope.c b/src/core/scope.c index 5f6527c155..1953af1f88 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -402,15 +402,10 @@ static bool scope_check_gc(Unit *u) { /* Never clean up scopes that still have a process around, * even if the scope is formally dead. */ - if (u->cgroup_path) { - int r; + if (!u->cgroup_path) + return false; - r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path); - if (r <= 0) - return true; - } - - return false; + return cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path) <= 0; } static void scope_notify_cgroup_empty_event(Unit *u) { @@ -577,6 +572,7 @@ const UnitVTable scope_vtable = { .no_alias = true, .no_instances = true, + .can_transient = true, .init = scope_init, .load = scope_load, @@ -611,7 +607,5 @@ const UnitVTable scope_vtable = { .bus_set_property = bus_scope_set_property, .bus_commit_properties = bus_scope_commit_properties, - .can_transient = true, - .enumerate = scope_enumerate, }; diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index 4bcdd27389..8856927c88 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -23,10 +23,10 @@ #ifdef HAVE_SELINUX -#include <stdio.h> #include <errno.h> -#include <selinux/selinux.h> #include <selinux/avc.h> +#include <selinux/selinux.h> +#include <stdio.h> #ifdef HAVE_AUDIT #include <libaudit.h> #endif diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index 30725521cb..3566ba529f 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "bus-util.h" #include "manager.h" diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c index d9b00fb95c..d4757e0853 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -29,10 +29,10 @@ #include "log.h" #include "macro.h" +#include "selinux-setup.h" #include "selinux-util.h" #include "string-util.h" #include "util.h" -#include "selinux-setup.h" #ifdef HAVE_SELINUX _printf_(2,3) diff --git a/src/core/service.h b/src/core/service.h index e765668247..d0faad88e0 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -24,10 +24,10 @@ typedef struct Service Service; typedef struct ServiceFDStore ServiceFDStore; +#include "exit-status.h" +#include "kill.h" #include "path.h" #include "ratelimit.h" -#include "kill.h" -#include "exit-status.h" typedef enum ServiceRestart { SERVICE_RESTART_NO, diff --git a/src/core/slice.c b/src/core/slice.c index 39dabae055..06ac6f8450 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -24,12 +24,12 @@ #include "alloc-util.h" #include "dbus-slice.h" #include "log.h" +#include "slice.h" #include "special.h" #include "string-util.h" #include "strv.h" #include "unit-name.h" #include "unit.h" -#include "slice.h" static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = { [SLICE_DEAD] = UNIT_INACTIVE, @@ -305,6 +305,7 @@ const UnitVTable slice_vtable = { .no_alias = true, .no_instances = true, + .can_transient = true, .load = slice_load, diff --git a/src/core/socket.c b/src/core/socket.c index 5b9e32ce9d..860a1e3051 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -289,7 +289,7 @@ static int socket_add_device_link(Socket *s) { return 0; t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device); - return unit_add_node_link(UNIT(s), t, false); + return unit_add_node_link(UNIT(s), t, false, UNIT_BINDS_TO); } static int socket_add_default_dependencies(Socket *s) { @@ -1266,6 +1266,19 @@ static int socket_open_fds(Socket *s) { know_label = true; } + /* Apply the socket protocol */ + switch(p->address.type) { + case SOCK_STREAM: + case SOCK_SEQPACKET: + if (p->socket->socket_protocol == IPPROTO_SCTP) + p->address.protocol = p->socket->socket_protocol; + break; + case SOCK_DGRAM: + if (p->socket->socket_protocol == IPPROTO_UDPLITE) + p->address.protocol = p->socket->socket_protocol; + break; + } + r = socket_address_listen( &p->address, SOCK_CLOEXEC|SOCK_NONBLOCK, diff --git a/src/core/socket.h b/src/core/socket.h index 94cda8a90d..08033287a6 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -23,9 +23,9 @@ typedef struct Socket Socket; -#include "socket-util.h" #include "mount.h" #include "service.h" +#include "socket-util.h" typedef enum SocketExecCommand { SOCKET_EXEC_START_PRE, @@ -120,6 +120,8 @@ struct Socket { bool remove_on_stop; bool writable; + int socket_protocol; + /* Socket options */ bool keep_alive; bool no_delay; diff --git a/src/core/swap.c b/src/core/swap.c index ee0838e676..5568898bd7 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -202,7 +202,7 @@ static int swap_add_device_links(Swap *s) { return 0; if (is_device_path(s->what)) - return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM); + return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM, UNIT_BINDS_TO); else /* File based swap devices need to be ordered after * systemd-remount-fs.service, since they might need a @@ -211,6 +211,8 @@ static int swap_add_device_links(Swap *s) { } static int swap_add_default_dependencies(Swap *s) { + int r; + assert(s); if (!UNIT(s)->default_dependencies) @@ -222,6 +224,12 @@ static int swap_add_default_dependencies(Swap *s) { if (detect_container() > 0) return 0; + /* swap units generated for the swap dev links are missing the + * ordering dep against the swap target. */ + r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true); + if (r < 0) + return r; + return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true); } diff --git a/src/core/system.conf b/src/core/system.conf index 50668e12c4..e2ded27333 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -40,7 +40,8 @@ #DefaultCPUAccounting=no #DefaultBlockIOAccounting=no #DefaultMemoryAccounting=no -#DefaultTasksAccounting=no +#DefaultTasksAccounting=yes +#DefaultTasksMax=512 #DefaultLimitCPU= #DefaultLimitFSIZE= #DefaultLimitDATA= diff --git a/src/core/timer.c b/src/core/timer.c index 51b1d875be..6b0f8e8616 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -27,6 +27,7 @@ #include "dbus-timer.h" #include "fs-util.h" #include "parse-util.h" +#include "random-util.h" #include "special.h" #include "string-table.h" #include "string-util.h" @@ -55,6 +56,7 @@ static void timer_init(Unit *u) { t->next_elapse_monotonic_or_boottime = USEC_INFINITY; t->next_elapse_realtime = USEC_INFINITY; t->accuracy_usec = u->manager->default_timer_accuracy_usec; + t->remain_after_elapse = true; } void timer_free_values(Timer *t) { @@ -217,13 +219,15 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) { "%sUnit: %s\n" "%sPersistent: %s\n" "%sWakeSystem: %s\n" - "%sAccuracy: %s\n", + "%sAccuracy: %s\n" + "%sRemainAfterElapse: %s\n", prefix, timer_state_to_string(t->state), prefix, timer_result_to_string(t->result), prefix, trigger ? trigger->id : "n/a", prefix, yes_no(t->persistent), prefix, yes_no(t->wake_system), - prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1)); + prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1), + prefix, yes_no(t->remain_after_elapse)); LIST_FOREACH(value, v, t->values) { @@ -275,13 +279,13 @@ static int timer_coldplug(Unit *u) { assert(t); assert(t->state == TIMER_DEAD); - if (t->deserialized_state != t->state) { + if (t->deserialized_state == t->state) + return 0; - if (t->deserialized_state == TIMER_WAITING) - timer_enter_waiting(t, false); - else - timer_set_state(t, t->deserialized_state); - } + if (t->deserialized_state == TIMER_WAITING) + timer_enter_waiting(t, false); + else + timer_set_state(t, t->deserialized_state); return 0; } @@ -295,6 +299,23 @@ static void timer_enter_dead(Timer *t, TimerResult f) { timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD); } +static void timer_enter_elapsed(Timer *t, bool leave_around) { + assert(t); + + /* If a unit is marked with RemainAfterElapse=yes we leave it + * around even after it elapsed once, so that starting it + * later again does not necessarily mean immediate + * retriggering. We unconditionally leave units with + * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around, + * since they might be restarted automatically at any time + * later on. */ + + if (t->remain_after_elapse || leave_around) + timer_set_state(t, TIMER_ELAPSED); + else + timer_enter_dead(t, TIMER_SUCCESS); +} + static usec_t monotonic_to_boottime(usec_t t) { usec_t a, b; @@ -310,10 +331,33 @@ static usec_t monotonic_to_boottime(usec_t t) { return 0; } +static void add_random(Timer *t, usec_t *v) { + char s[FORMAT_TIMESPAN_MAX]; + usec_t add; + + assert(t); + assert(*v); + + if (t->random_usec == 0) + return; + if (*v == USEC_INFINITY) + return; + + add = random_u64() % t->random_usec; + + if (*v + add < *v) /* overflow */ + *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */ + else + *v += add; + + log_unit_info(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0)); +} + static void timer_enter_waiting(Timer *t, bool initial) { bool found_monotonic = false, found_realtime = false; usec_t ts_realtime, ts_monotonic; usec_t base = 0; + bool leave_around = false; TimerValue *v; int r; @@ -374,7 +418,7 @@ static void timer_enter_waiting(Timer *t, bool initial) { break; case TIMER_UNIT_ACTIVE: - + leave_around = true; base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic; if (base <= 0) @@ -386,7 +430,7 @@ static void timer_enter_waiting(Timer *t, bool initial) { break; case TIMER_UNIT_INACTIVE: - + leave_around = true; base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic; if (base <= 0) @@ -423,14 +467,18 @@ static void timer_enter_waiting(Timer *t, bool initial) { if (!found_monotonic && !found_realtime) { log_unit_debug(UNIT(t), "Timer is elapsed."); - timer_set_state(t, TIMER_ELAPSED); + timer_enter_elapsed(t, leave_around); return; } if (found_monotonic) { char buf[FORMAT_TIMESPAN_MAX]; + usec_t left; - log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0)); + add_random(t, &t->next_elapse_monotonic_or_boottime); + + left = t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0; + log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0)); if (t->monotonic_event_source) { r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime); @@ -463,6 +511,9 @@ static void timer_enter_waiting(Timer *t, bool initial) { if (found_realtime) { char buf[FORMAT_TIMESTAMP_MAX]; + + add_random(t, &t->next_elapse_realtime); + log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime)); if (t->realtime_event_source) { diff --git a/src/core/timer.h b/src/core/timer.h index ac5af6a93c..0599f07818 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -58,6 +58,7 @@ struct Timer { Unit meta; usec_t accuracy_usec; + usec_t random_usec; LIST_HEAD(TimerValue, values); usec_t next_elapse_realtime; @@ -73,6 +74,7 @@ struct Timer { bool persistent; bool wake_system; + bool remain_after_elapse; char *stamp_path; }; diff --git a/src/core/transaction.c b/src/core/transaction.c index cf37b5eb75..15e79d00b3 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <fcntl.h> +#include <unistd.h> #include "alloc-util.h" #include "bus-common-errors.h" diff --git a/src/core/transaction.h b/src/core/transaction.h index f7aa3df085..5c4a13edab 100644 --- a/src/core/transaction.h +++ b/src/core/transaction.h @@ -23,10 +23,10 @@ typedef struct Transaction Transaction; -#include "unit.h" -#include "manager.h" -#include "job.h" #include "hashmap.h" +#include "job.h" +#include "manager.h" +#include "unit.h" struct Transaction { /* Jobs to be added */ diff --git a/src/core/triggers.systemd.in b/src/core/triggers.systemd.in new file mode 100644 index 0000000000..9e18a39a67 --- /dev/null +++ b/src/core/triggers.systemd.in @@ -0,0 +1,64 @@ +# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */ +# +# This file is part of systemd. +# +# Copyright 2015 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/>. + +# The contents of this are an example to be copied into systemd.spec. + +%transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system +-- This script will run after any package is initially installed or +-- upgraded. We care about the case where a package is initially +-- installed, because other cases are covered by the *un scriptlets, +-- so sometimes we will reload needlessly. + +pid = posix.fork() +if pid == 0 then + assert(posix.exec("%{_bindir}/systemctl", "daemon-reload")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerun -p <lua> -- @systemunitdir@ /etc/systemd/system +-- On removal, we need to run daemon-reload after any units have been +-- removed. %transfiletriggerpostun would be ideal, but it does not get +-- executed for some reason. +-- On upgrade, we need to run daemon-reload after any new unit files +-- have been installed, but before %postun scripts in packages get +-- executed. %transfiletriggerun gets the right list of files +-- but it is invoked too early (before changes happen). +-- %filetriggerpostun happens at the right time, but it fires for +-- every package. +-- To execute the reload at the right time, we create a state +-- file in %transfiletriggerun and execute the daemon-reload in +-- the first %filetriggerpostun. + +posix.mkdir("%{_localstatedir}/lib") +posix.mkdir("%{_localstatedir}/lib/rpm-state") +posix.mkdir("%{_localstatedir}/lib/rpm-state/systemd") +io.open("%{_localstatedir}/lib/rpm-state/systemd/needs-reload", "w") + +%filetriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system +if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then + posix.unlink("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") + posix.rmdir("%{_localstatedir}/lib/rpm-state/systemd") + pid = posix.fork() + if pid == 0 then + assert(posix.exec("%{_bindir}/systemctl", "daemon-reload")) + elseif pid > 0 then + posix.wait(pid) + end +end diff --git a/src/core/unit.c b/src/core/unit.c index f553f24829..e6e67d27c8 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -132,6 +132,9 @@ static void unit_init(Unit *u) { cc->blockio_accounting = u->manager->default_blockio_accounting; cc->memory_accounting = u->manager->default_memory_accounting; cc->tasks_accounting = u->manager->default_tasks_accounting; + + if (u->type != UNIT_SLICE) + cc->tasks_max = u->manager->default_tasks_max; } ec = unit_get_exec_context(u); @@ -314,9 +317,6 @@ bool unit_check_gc(Unit *u) { if (state != UNIT_INACTIVE) return true; - if (UNIT_VTABLE(u)->no_gc) - return true; - if (u->no_gc) return true; @@ -1347,12 +1347,18 @@ static bool unit_assert_test(Unit *u) { return u->assert_result; } +void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) { + DISABLE_WARNING_FORMAT_NONLITERAL; + manager_status_printf(u->manager, STATUS_TYPE_NORMAL, status, unit_status_msg_format, unit_description(u)); + REENABLE_WARNING; +} + _pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) { const char *format; const UnitStatusMessageFormats *format_table; assert(u); - assert(t == JOB_START || t == JOB_STOP || t == JOB_RELOAD); + assert(IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD)); if (t != JOB_RELOAD) { format_table = &UNIT_VTABLE(u)->status_message_formats; @@ -1377,6 +1383,10 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) { assert(u); + /* Reload status messages have traditionally not been printed to console. */ + if (!IN_SET(t, JOB_START, JOB_STOP)) + return; + format = unit_get_status_message_format(u, t); DISABLE_WARNING_FORMAT_NONLITERAL; @@ -1391,7 +1401,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { assert(u); - if (t != JOB_START && t != JOB_STOP && t != JOB_RELOAD) + if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD)) return; if (log_on_console()) @@ -1423,12 +1433,12 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { } void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) { + assert(u); + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); unit_status_log_starting_stopping_reloading(u, t); - - /* Reload status messages have traditionally not been printed to console. */ - if (t != JOB_RELOAD) - unit_status_print_starting_stopping(u, t); + unit_status_print_starting_stopping(u, t); } /* Errors: @@ -2830,7 +2840,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { } } -int unit_add_node_link(Unit *u, const char *what, bool wants) { +int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) { Unit *device; _cleanup_free_ char *e = NULL; int r; @@ -2857,7 +2867,9 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { if (r < 0) return r; - r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == MANAGER_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true); + r = unit_add_two_dependencies(u, UNIT_AFTER, + u->manager->running_as == MANAGER_SYSTEM ? dep : UNIT_WANTS, + device, true); if (r < 0) return r; @@ -2896,13 +2908,6 @@ int unit_coldplug(Unit *u) { return 0; } -void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) { - DISABLE_WARNING_FORMAT_NONLITERAL; - manager_status_printf(u->manager, STATUS_TYPE_NORMAL, - status, unit_status_msg_format, unit_description(u)); - REENABLE_WARNING; -} - bool unit_need_daemon_reload(Unit *u) { _cleanup_strv_free_ char **t = NULL; char **path; @@ -3428,7 +3433,15 @@ int unit_make_transient(Unit *u) { u->load_state = UNIT_STUB; u->load_error = 0; u->transient = true; + u->fragment_path = mfree(u->fragment_path); + u->source_path = mfree(u->source_path); + u->dropin_paths = strv_free(u->dropin_paths); + u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0; + + unit_add_to_dbus_queue(u); + unit_add_to_gc_queue(u); + unit_add_to_load_queue(u); return 0; } @@ -3704,3 +3717,21 @@ int unit_fail_if_symlink(Unit *u, const char* where) { return -ELOOP; } + +bool unit_is_pristine(Unit *u) { + assert(u); + + /* Check if the unit already exists or is already around, + * in a number of different ways. Note that to cater for unit + * types such as slice, we are generally fine with units that + * are marked UNIT_LOADED even even though nothing was + * actually loaded, as those unit types don't require a file + * on disk to validly load. */ + + return !(!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) || + u->fragment_path || + u->source_path || + !strv_isempty(u->dropin_paths) || + u->job || + u->merged_into); +} diff --git a/src/core/unit.h b/src/core/unit.h index 14e3072146..3eb3484fb7 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -30,11 +30,11 @@ typedef struct UnitVTable UnitVTable; typedef struct UnitRef UnitRef; typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; -#include "list.h" #include "condition.h" +#include "failure-action.h" #include "install.h" +#include "list.h" #include "unit-name.h" -#include "failure-action.h" typedef enum KillOperation { KILL_TERMINATE, @@ -242,16 +242,16 @@ typedef enum UnitSetPropertiesMode { UNIT_PERSISTENT = 2, } UnitSetPropertiesMode; -#include "socket.h" +#include "automount.h" #include "busname.h" -#include "target.h" #include "device.h" -#include "automount.h" -#include "swap.h" -#include "timer.h" -#include "slice.h" #include "path.h" #include "scope.h" +#include "slice.h" +#include "socket.h" +#include "swap.h" +#include "target.h" +#include "timer.h" struct UnitVTable { /* How much memory does an object of this unit type need */ @@ -403,9 +403,6 @@ struct UnitVTable { /* Instances make no sense for this type */ bool no_instances:1; - /* Exclude from automatic gc */ - bool no_gc:1; - /* True if transient units of this type are OK */ bool can_transient:1; }; @@ -531,7 +528,7 @@ int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *v 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_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d); int unit_coldplug(Unit *u); @@ -589,6 +586,8 @@ int unit_require_mounts_for(Unit *u, const char *path); bool unit_type_supported(UnitType t); +bool unit_is_pristine(Unit *u); + static inline bool unit_supported(Unit *u) { return unit_type_supported(u->type); } diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 5b806a1e69..e0436d794c 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -20,14 +20,14 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> -#include <stdbool.h> #include <errno.h> -#include <unistd.h> #include <fcntl.h> +#include <stdbool.h> +#include <stdio.h> #include <sys/file.h> -#include <sys/stat.h> #include <sys/prctl.h> +#include <sys/stat.h> +#include <unistd.h> #include "sd-bus.h" #include "sd-device.h" diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index f7c8d11ace..87b8b77f22 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -248,6 +248,7 @@ static int add_mount( assert(what); assert(where); assert(opts); + assert(post); assert(source); if (streq_ptr(fstype, "autofs")) @@ -297,7 +298,7 @@ static int add_mount( "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n", source); - if (post && !noauto && !nofail && !automount) + if (!noauto && !nofail && !automount) fprintf(f, "Before=%s\n", post); if (!automount && opts) { @@ -337,7 +338,7 @@ static int add_mount( if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", unit); - if (!noauto && post) { + if (!noauto) { lnk = strjoin(arg_dest, "/", post, nofail || automount ? ".wants/" : ".requires/", name, NULL); if (!lnk) return log_oom(); @@ -368,10 +369,7 @@ static int add_mount( "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n", source); - if (post) - fprintf(f, - "Before=%s\n", - post); + fprintf(f, "Before=%s\n", post); if (opts) { r = write_requires_after(f, opts); diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index 34852ce381..ce8cecc5cb 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> +#include <blkid/blkid.h> #include <stdlib.h> #include <sys/statfs.h> -#include <blkid/blkid.h> +#include <unistd.h> #include "libudev.h" #include "sd-id128.h" diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index 316a2803d3..2e1259ef68 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> +#include <stdio.h> #include <sys/stat.h> #include "alloc-util.h" diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index 92061532b8..dde2baf661 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -21,8 +21,8 @@ #include <errno.h> #include <string.h> -#include <unistd.h> #include <sys/utsname.h> +#include <unistd.h> #include "alloc-util.h" #include "bus-util.h" diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c index 7b1ac134a0..82f519958c 100644 --- a/src/import/aufs-util.c +++ b/src/import/aufs-util.c @@ -21,10 +21,10 @@ #include <ftw.h> +#include "aufs-util.h" #include "rm-rf.h" #include "string-util.h" #include "util.h" -#include "aufs-util.h" static int nftw_cb( const char *fpath, diff --git a/src/import/curl-util.c b/src/import/curl-util.c index 4278466df1..8e531a64fa 100644 --- a/src/import/curl-util.c +++ b/src/import/curl-util.c @@ -48,9 +48,7 @@ static int curl_glue_on_io(sd_event_source *s, int fd, uint32_t revents, void *u assert(s); assert(g); - translated_fd = PTR_TO_INT(hashmap_get(g->translate_fds, INT_TO_PTR(fd+1))); - assert(translated_fd > 0); - translated_fd--; + translated_fd = PTR_TO_FD(hashmap_get(g->translate_fds, FD_TO_PTR(fd))); if ((revents & (EPOLLIN|EPOLLOUT)) == (EPOLLIN|EPOLLOUT)) action = CURL_POLL_INOUT; @@ -79,7 +77,7 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v assert(curl); assert(g); - io = hashmap_get(g->ios, INT_TO_PTR(s+1)); + io = hashmap_get(g->ios, FD_TO_PTR(s)); if (action == CURL_POLL_REMOVE) { if (io) { @@ -91,8 +89,8 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v sd_event_source_set_enabled(io, SD_EVENT_OFF); sd_event_source_unref(io); - hashmap_remove(g->ios, INT_TO_PTR(s+1)); - hashmap_remove(g->translate_fds, INT_TO_PTR(fd+1)); + hashmap_remove(g->ios, FD_TO_PTR(s)); + hashmap_remove(g->translate_fds, FD_TO_PTR(fd)); safe_close(fd); } @@ -143,17 +141,17 @@ static int curl_glue_socket_callback(CURLM *curl, curl_socket_t s, int action, v sd_event_source_set_description(io, "curl-io"); - r = hashmap_put(g->ios, INT_TO_PTR(s+1), io); + r = hashmap_put(g->ios, FD_TO_PTR(s), io); if (r < 0) { log_oom(); sd_event_source_unref(io); return -1; } - r = hashmap_put(g->translate_fds, INT_TO_PTR(fd+1), INT_TO_PTR(s+1)); + r = hashmap_put(g->translate_fds, FD_TO_PTR(fd), FD_TO_PTR(s)); if (r < 0) { log_oom(); - hashmap_remove(g->ios, INT_TO_PTR(s+1)); + hashmap_remove(g->ios, FD_TO_PTR(s)); sd_event_source_unref(io); return -1; } @@ -229,7 +227,7 @@ CurlGlue *curl_glue_unref(CurlGlue *g) { fd = sd_event_source_get_io_fd(io); assert(fd >= 0); - hashmap_remove(g->translate_fds, INT_TO_PTR(fd+1)); + hashmap_remove(g->translate_fds, FD_TO_PTR(fd)); safe_close(fd); sd_event_source_unref(io); diff --git a/src/import/curl-util.h b/src/import/curl-util.h index 6a2aa81c76..eec53c9266 100644 --- a/src/import/curl-util.h +++ b/src/import/curl-util.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <curl/curl.h> +#include <sys/types.h> #include "sd-event.h" diff --git a/src/import/export-raw.c b/src/import/export-raw.c index 103d45bf21..28c87594d6 100644 --- a/src/import/export-raw.c +++ b/src/import/export-raw.c @@ -20,6 +20,10 @@ ***/ #include <sys/sendfile.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 diff --git a/src/import/export-raw.h b/src/import/export-raw.h index b71de6cb82..e5e298f6ab 100644 --- a/src/import/export-raw.h +++ b/src/import/export-raw.h @@ -22,8 +22,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-compress.h" +#include "macro.h" typedef struct RawExport RawExport; diff --git a/src/import/export-tar.h b/src/import/export-tar.h index ce27a9fc1e..9061e7515d 100644 --- a/src/import/export-tar.h +++ b/src/import/export-tar.h @@ -22,8 +22,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-compress.h" +#include "macro.h" typedef struct TarExport TarExport; diff --git a/src/import/import-compress.h b/src/import/import-compress.h index 50d91f732c..0a13232554 100644 --- a/src/import/import-compress.h +++ b/src/import/import-compress.h @@ -21,11 +21,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> - +#include <bzlib.h> #include <lzma.h> +#include <sys/types.h> #include <zlib.h> -#include <bzlib.h> #include "macro.h" diff --git a/src/import/import-raw.h b/src/import/import-raw.h index bf7c770340..626d965cf8 100644 --- a/src/import/import-raw.h +++ b/src/import/import-raw.h @@ -22,8 +22,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-util.h" +#include "macro.h" typedef struct RawImport RawImport; diff --git a/src/import/import-tar.h b/src/import/import-tar.h index aaecb51398..d12391572d 100644 --- a/src/import/import-tar.h +++ b/src/import/import-tar.h @@ -22,8 +22,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-util.h" +#include "macro.h" typedef struct TarImport TarImport; diff --git a/src/import/pull-common.c b/src/import/pull-common.c index d6567ba7ee..a83cffffa0 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -165,7 +165,7 @@ static int hash_url(const char *url, char **ret) { assert(url); - siphash24((uint8_t *) &h, url, strlen(url), k.bytes); + h = siphash24(url, strlen(url), k.bytes); if (asprintf(ret, "%"PRIx64, h) < 0) return -ENOMEM; diff --git a/src/import/pull-common.h b/src/import/pull-common.h index 7e6db1862c..ea228bb5c8 100644 --- a/src/import/pull-common.h +++ b/src/import/pull-common.h @@ -23,8 +23,8 @@ #include <stdbool.h> -#include "pull-job.h" #include "import-util.h" +#include "pull-job.h" int pull_make_local_copy(const char *final, const char *root, const char *local, bool force_local); diff --git a/src/import/pull-dkr.h b/src/import/pull-dkr.h index 33d18cb394..a95d91205b 100644 --- a/src/import/pull-dkr.h +++ b/src/import/pull-dkr.h @@ -22,6 +22,7 @@ #pragma once #include "sd-event.h" + #include "util.h" typedef enum { DKR_PULL_V1, DKR_PULL_V2 } DkrPullVersion; diff --git a/src/import/pull-job.h b/src/import/pull-job.h index 1777bf1c33..56a74a34ef 100644 --- a/src/import/pull-job.h +++ b/src/import/pull-job.h @@ -23,9 +23,9 @@ #include <gcrypt.h> -#include "macro.h" #include "curl-util.h" #include "import-compress.h" +#include "macro.h" typedef struct PullJob PullJob; diff --git a/src/import/pull-raw.h b/src/import/pull-raw.h index b03b4f5c92..0e4e1daf0e 100644 --- a/src/import/pull-raw.h +++ b/src/import/pull-raw.h @@ -22,8 +22,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-util.h" +#include "macro.h" typedef struct RawPull RawPull; diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index e7fcd293f1..2e48167c54 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/prctl.h> #include <curl/curl.h> +#include <sys/prctl.h> #include "sd-daemon.h" diff --git a/src/import/pull-tar.h b/src/import/pull-tar.h index 420845ae50..9f02f1ec71 100644 --- a/src/import/pull-tar.h +++ b/src/import/pull-tar.h @@ -22,8 +22,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-util.h" +#include "macro.h" typedef struct TarPull TarPull; diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index d4f8673187..a35f2b541c 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -19,11 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> +#include <ctype.h> #include <errno.h> -#include <unistd.h> +#include <stdio.h> #include <sys/epoll.h> -#include <ctype.h> +#include <unistd.h> #include "sd-bus.h" #include "sd-daemon.h" diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 14bfadc132..58cb5e70df 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -22,6 +22,7 @@ #pragma once #include "sd-event.h" + #include "journal-remote-write.h" typedef enum { diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h index 6c2ccb9735..fd81a1c592 100644 --- a/src/journal-remote/journal-remote.h +++ b/src/journal-remote/journal-remote.h @@ -23,11 +23,11 @@ #include "sd-event.h" -#include "hashmap.h" -#include "microhttpd-util.h" +#include "hashmap.h" #include "journal-remote-parse.h" #include "journal-remote-write.h" +#include "microhttpd-util.h" typedef struct MHDDaemonWrapper MHDDaemonWrapper; diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index 3ee6d32bf7..a6d7c3b7e8 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -19,9 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdbool.h> - #include <curl/curl.h> +#include <stdbool.h> #include "alloc-util.h" #include "journal-upload.h" diff --git a/src/journal-remote/journal-upload.h b/src/journal-remote/journal-upload.h index 3b46fa8cbf..b8cd04d527 100644 --- a/src/journal-remote/journal-upload.h +++ b/src/journal-remote/journal-upload.h @@ -2,8 +2,8 @@ #include <inttypes.h> -#include "sd-journal.h" #include "sd-event.h" +#include "sd-journal.h" typedef enum { ENTRY_CURSOR = 0, /* Nothing actually written yet. */ diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index b2c398a845..09e6da0031 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -32,10 +32,10 @@ #include "alloc-util.h" #include "log.h" #include "macro.h" +#include "microhttpd-util.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-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index b2feb9180a..3e8c4fa6d1 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -21,8 +21,8 @@ #pragma once -#include <stdarg.h> #include <microhttpd.h> +#include <stdarg.h> #include "macro.h" diff --git a/src/journal/audit-type.c b/src/journal/audit-type.c index 4888c7d05d..086bf7e7e3 100644 --- a/src/journal/audit-type.c +++ b/src/journal/audit-type.c @@ -25,8 +25,7 @@ # include <libaudit.h> #endif -#include "audit-type.h" -#include "macro.h" #include "missing.h" - +#include "audit-type.h" #include "audit_type-to-name.h" +#include "macro.h" diff --git a/src/journal/catalog.h b/src/journal/catalog.h index a72ecf6de7..bcc73c2631 100644 --- a/src/journal/catalog.h +++ b/src/journal/catalog.h @@ -24,6 +24,7 @@ #include <stdbool.h> #include "sd-id128.h" + #include "hashmap.h" #include "strbuf.h" diff --git a/src/journal/coredump-vacuum.c b/src/journal/coredump-vacuum.c index 39bc2e4270..09ab60c6c4 100644 --- a/src/journal/coredump-vacuum.c +++ b/src/journal/coredump-vacuum.c @@ -157,8 +157,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { if (errno == ENOENT) return 0; - log_error_errno(errno, "Can't open coredump directory: %m"); - return -errno; + return log_error_errno(errno, "Can't open coredump directory: %m"); } for (;;) { @@ -183,7 +182,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { if (errno == ENOENT) continue; - log_warning("Failed to stat /var/lib/systemd/coredump/%s", de->d_name); + log_warning_errno(errno, "Failed to stat /var/lib/systemd/coredump/%s: %m", de->d_name); continue; } @@ -201,7 +200,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { t = timespec_load(&st.st_mtim); - c = hashmap_get(h, UINT32_TO_PTR(uid)); + c = hashmap_get(h, UID_TO_PTR(uid)); if (c) { if (t < c->oldest_mtime) { @@ -229,7 +228,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { n->oldest_mtime = t; - r = hashmap_put(h, UINT32_TO_PTR(uid), n); + r = hashmap_put(h, UID_TO_PTR(uid), n); if (r < 0) return log_oom(); @@ -259,8 +258,7 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { if (errno == ENOENT) continue; - log_error_errno(errno, "Failed to remove file %s: %m", worst->oldest_file); - return -errno; + return log_error_errno(errno, "Failed to remove file %s: %m", worst->oldest_file); } else log_info("Removed old coredump %s.", worst->oldest_file); } @@ -268,6 +266,5 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { return 0; fail: - log_error_errno(errno, "Failed to read directory: %m"); - return -errno; + return log_error_errno(errno, "Failed to read directory: %m"); } diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h index 5959b1fed2..b79221fc2e 100644 --- a/src/journal/fsprg.h +++ b/src/journal/fsprg.h @@ -25,8 +25,8 @@ * */ -#include <sys/types.h> #include <inttypes.h> +#include <sys/types.h> #include "macro.h" #include "util.h" diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index 0c4ac5cdc3..aeec83da1e 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -24,10 +24,10 @@ #include "fd-util.h" #include "fsprg.h" +#include "hexdecoct.h" #include "journal-authenticate.h" #include "journal-def.h" #include "journal-file.h" -#include "hexdecoct.h" static uint64_t journal_file_tag_seqnum(JournalFile *f) { uint64_t r; diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 898d12d992..46c1f3278e 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -29,11 +29,11 @@ #include "sd-id128.h" -#include "sparse-endian.h" +#include "hashmap.h" #include "journal-def.h" #include "macro.h" #include "mmap-cache.h" -#include "hashmap.h" +#include "sparse-endian.h" typedef struct JournalMetrics { /* For all these: -1 means "pick automatically", and 0 means "no limit enforced" */ diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h index 06847402e0..c3e75ad240 100644 --- a/src/journal/journal-internal.h +++ b/src/journal/journal-internal.h @@ -21,9 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <inttypes.h> #include <stdbool.h> +#include <sys/types.h> #include "sd-id128.h" #include "sd-journal.h" diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c index 1db66e89c6..257ddb302b 100644 --- a/src/journal/journal-qrcode.c +++ b/src/journal/journal-qrcode.c @@ -20,12 +20,11 @@ ***/ #include <assert.h> -#include <stdio.h> #include <errno.h> -#include <stdlib.h> -#include <stdbool.h> - #include <qrencode.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> #include "journal-qrcode.h" diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 3676cb8788..715847e018 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <sys/mman.h> #include <fcntl.h> #include <stddef.h> +#include <sys/mman.h> +#include <unistd.h> #include "alloc-util.h" #include "compress.h" diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index 75a48c761c..d9a8063d31 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -2247,7 +2247,8 @@ int main(int argc, char *argv[]) { if (arg_follow) need_seek = true; else { - printf("-- No entries --\n"); + if (!arg_quiet) + printf("-- No entries --\n"); goto finish; } } diff --git a/src/journal/journald-audit.h b/src/journal/journald-audit.h index 68cdfb3410..5c88bb6383 100644 --- a/src/journal/journald-audit.h +++ b/src/journal/journald-audit.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "socket-util.h" #include "journald-server.h" +#include "socket-util.h" void server_process_audit_message(Server *s, const void *buffer, size_t buffer_size, const struct ucred *ucred, const union sockaddr_union *sa, socklen_t salen); diff --git a/src/journal/journald-console.c b/src/journal/journald-console.c index 89f3d4b42f..04487c29b5 100644 --- a/src/journal/journald-console.c +++ b/src/journal/journald-console.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <time.h> #include <fcntl.h> #include <sys/socket.h> +#include <time.h> #include "alloc-util.h" #include "fd-util.h" diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c index 434ddc8ac9..1c406aef8e 100644 --- a/src/journal/journald-rate-limit.c +++ b/src/journal/journald-rate-limit.c @@ -24,11 +24,11 @@ #include "alloc-util.h" #include "hashmap.h" +#include "journald-rate-limit.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 @@ -162,7 +162,7 @@ static JournalRateLimitGroup* journal_rate_limit_group_new(JournalRateLimit *r, siphash24_init(&state, r->hash_key); string_hash_func(g->id, &state); - siphash24_finalize((uint8_t*)&g->hash, &state); + g->hash = siphash24_finalize(&state); journal_rate_limit_vacuum(r, ts); @@ -230,7 +230,7 @@ int journal_rate_limit_test(JournalRateLimit *r, const char *id, int priority, u siphash24_init(&state, r->hash_key); string_hash_func(id, &state); - siphash24_finalize((uint8_t*)&h, &state); + h = siphash24_finalize(&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 be913d26ef..7d11a568aa 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -69,6 +69,7 @@ #include "socket-util.h" #include "string-table.h" #include "string-util.h" +#include "user-util.h" #define USER_JOURNALS_MAX 1024 @@ -281,7 +282,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { if (r < 0) return s->system_journal; - f = ordered_hashmap_get(s->user_journals, UINT32_TO_PTR(uid)); + f = ordered_hashmap_get(s->user_journals, UID_TO_PTR(uid)); if (f) return f; @@ -302,7 +303,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) { server_fix_perms(s, f, uid); - r = ordered_hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f); + r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f); if (r < 0) { journal_file_close(f); return s->system_journal; @@ -348,7 +349,7 @@ void server_rotate(Server *s) { (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)); + r = do_rotate(s, &f, "user", s->seal, PTR_TO_UID(k)); if (r >= 0) ordered_hashmap_replace(s->user_journals, k, f); else if (!f) @@ -359,7 +360,6 @@ void server_rotate(Server *s) { void server_sync(Server *s) { JournalFile *f; - void *k; Iterator i; int r; @@ -369,7 +369,7 @@ void server_sync(Server *s) { log_warning_errno(r, "Failed to sync system journal, ignoring: %m"); } - ORDERED_HASHMAP_FOREACH_KEY(f, k, s->user_journals, i) { + ORDERED_HASHMAP_FOREACH(f, s->user_journals, i) { r = journal_file_set_offline(f); if (r < 0) log_warning_errno(r, "Failed to sync user journal, ignoring: %m"); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index fb800782fb..07a0f1bf41 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -239,14 +239,14 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { assert(s); assert(p); - if (isempty(p)) - return 0; - priority = s->priority; if (s->level_prefix) syslog_parse_priority(&p, &priority, false); + if (isempty(p)) + return 0; + if (s->forward_to_syslog || s->server->forward_to_syslog) server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL); @@ -286,10 +286,12 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { static int stdout_stream_line(StdoutStream *s, char *p) { int r; + char *orig; assert(s); assert(p); + orig = p; p = strstrip(p); switch (s->state) { @@ -378,7 +380,7 @@ static int stdout_stream_line(StdoutStream *s, char *p) { return 0; case STDOUT_STREAM_RUNNING: - return stdout_stream_log(s, p); + return stdout_stream_log(s, orig); } assert_not_reached("Unknown stream state"); diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c index 69540f1141..88bea3b86e 100644 --- a/src/journal/journald-wall.c +++ b/src/journal/journald-wall.c @@ -22,10 +22,10 @@ #include "alloc-util.h" #include "formats-util.h" #include "journald-server.h" +#include "journald-wall.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 b137e3c7be..b9f5c099e1 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -21,16 +21,15 @@ #include <unistd.h> -#include "sd-messages.h" #include "sd-daemon.h" +#include "sd-messages.h" +#include "formats-util.h" #include "journal-authenticate.h" -#include "journald-server.h" #include "journald-kmsg.h" +#include "journald-server.h" #include "journald-syslog.h" - #include "sigbus.h" -#include "formats-util.h" int main(int argc, char *argv[]) { Server server; diff --git a/src/journal/lookup3.c b/src/journal/lookup3.c index 52ffdf7b1d..3d791234f4 100644 --- a/src/journal/lookup3.c +++ b/src/journal/lookup3.c @@ -40,10 +40,10 @@ on 1 byte), but shoehorning those bytes into integers efficiently is messy. */ /* #define SELF_TEST 1 */ -#include <stdio.h> /* defines printf for tests */ -#include <time.h> /* defines time_t for timings in the test */ #include <stdint.h> /* defines uint32_t etc */ +#include <stdio.h> /* defines printf for tests */ #include <sys/param.h> /* attempt to define endianness */ +#include <time.h> /* defines time_t for timings in the test */ #ifdef linux # include <endian.h> /* attempt to define endianness */ #endif diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 3cb1dfa986..5a07ddda76 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -24,13 +24,14 @@ #include <sys/mman.h> #include "alloc-util.h" +#include "fd-util.h" #include "hashmap.h" #include "list.h" #include "log.h" -#include "util.h" #include "macro.h" -#include "sigbus.h" #include "mmap-cache.h" +#include "sigbus.h" +#include "util.h" typedef struct Window Window; typedef struct Context Context; @@ -289,7 +290,7 @@ static void fd_free(FileDescriptor *f) { window_free(f->windows); if (f->cache) - assert_se(hashmap_remove(f->cache->fds, INT_TO_PTR(f->fd + 1))); + assert_se(hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd))); free(f); } @@ -301,7 +302,7 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) { assert(m); assert(fd >= 0); - f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + f = hashmap_get(m->fds, FD_TO_PTR(fd)); if (f) return f; @@ -316,7 +317,7 @@ static FileDescriptor* fd_add(MMapCache *m, int fd) { f->cache = m; f->fd = fd; - r = hashmap_put(m->fds, UINT_TO_PTR(fd + 1), f); + r = hashmap_put(m->fds, FD_TO_PTR(fd), f); if (r < 0) { free(f); return NULL; @@ -429,7 +430,7 @@ static int find_mmap( assert(fd >= 0); assert(size > 0); - f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + f = hashmap_get(m->fds, FD_TO_PTR(fd)); if (!f) return 0; @@ -679,7 +680,7 @@ bool mmap_cache_got_sigbus(MMapCache *m, int fd) { mmap_cache_process_sigbus(m); - f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + f = hashmap_get(m->fds, FD_TO_PTR(fd)); if (!f) return false; @@ -698,7 +699,7 @@ void mmap_cache_close_fd(MMapCache *m, int fd) { mmap_cache_process_sigbus(m); - f = hashmap_get(m->fds, INT_TO_PTR(fd + 1)); + f = hashmap_get(m->fds, FD_TO_PTR(fd)); if (!f) return; diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c index aea8fd15e6..25980b7744 100644 --- a/src/journal/test-catalog.c +++ b/src/journal/test-catalog.c @@ -20,10 +20,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <locale.h> -#include <unistd.h> #include <errno.h> #include <fcntl.h> +#include <locale.h> +#include <unistd.h> #include "sd-messages.h" diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c index 040c7d58fb..8f56ea1907 100644 --- a/src/journal/test-journal-enum.c +++ b/src/journal/test-journal-enum.c @@ -23,9 +23,9 @@ #include "sd-journal.h" +#include "journal-internal.h" #include "log.h" #include "macro.h" -#include "journal-internal.h" int main(int argc, char *argv[]) { unsigned n = 0; diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 4ad89fe4b6..5c055ef748 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -20,8 +20,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <fcntl.h> +#include <unistd.h> #include "sd-journal.h" diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index 887a83efe1..a7abb11fba 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <fcntl.h> #include <stdio.h> #include <unistd.h> -#include <fcntl.h> #include "fd-util.h" #include "journal-file.h" diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 01d4bc968a..266e0d5473 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -22,11 +22,11 @@ #include <fcntl.h> #include <unistd.h> -#include "log.h" -#include "rm-rf.h" -#include "journal-file.h" #include "journal-authenticate.h" +#include "journal-file.h" #include "journal-vacuum.h" +#include "log.h" +#include "rm-rf.h" static bool arg_keep = false; diff --git a/src/libsystemd-network/arp-util.h b/src/libsystemd-network/arp-util.h index 44e5c893a7..63c559f8dd 100644 --- a/src/libsystemd-network/arp-util.h +++ b/src/libsystemd-network/arp-util.h @@ -23,8 +23,8 @@ #include <netinet/if_ether.h> -#include "sparse-endian.h" #include "socket-util.h" +#include "sparse-endian.h" int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac); diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index 51ee7bcce4..d7ae865557 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -35,6 +35,7 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { sd_id128_t machine_id; + uint64_t hash; int r; assert(duid); @@ -50,8 +51,9 @@ int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { *len = sizeof(duid->type) + sizeof(duid->en); /* a bit of snake-oil perhaps, but no need to expose the machine-id - directly */ - siphash24(duid->en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes); + directly; duid->en.id might not be aligned, so we need to copy */ + hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); + memcpy(duid->en.id, &hash, sizeof(duid->en.id)); return 0; } @@ -84,10 +86,12 @@ int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_i } if (name) - siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes); + id = siphash24(name, strlen(name), HASH_KEY.bytes); else /* fall back to MAC address if no predictable name available */ - siphash24((uint8_t*)&id, mac, mac_len, HASH_KEY.bytes); + id = siphash24(mac, mac_len, HASH_KEY.bytes); + + id = htole64(id); /* fold into 32 bits */ unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32)); diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index a5daaa543a..7038212bcf 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -47,8 +47,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_ typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, const void *option, void *userdata); -int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *userdata); +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message); int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, uint8_t type, uint16_t arp_type, size_t optlen, diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index c6b97ca8f7..138bdd9691 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -25,12 +25,11 @@ #include <stdint.h> #include <linux/if_packet.h> -#include "util.h" -#include "list.h" +#include "sd-dhcp-client.h" #include "dhcp-protocol.h" - -#include "sd-dhcp-client.h" +#include "list.h" +#include "util.h" struct sd_dhcp_route { struct in_addr dst_addr; diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 36be7d54ed..1de7f3639c 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -19,10 +19,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdint.h> -#include <string.h> #include <errno.h> +#include <stdint.h> #include <stdio.h> +#include <string.h> + +#include "alloc-util.h" +#include "utf8.h" #include "dhcp-internal.h" @@ -139,72 +142,84 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, } static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, - uint8_t *message_type, dhcp_option_cb_t cb, + uint8_t *message_type, char **error_message, dhcp_option_cb_t cb, void *userdata) { uint8_t code, len; + const uint8_t *option; size_t offset = 0; while (offset < buflen) { - switch (options[offset]) { - case DHCP_OPTION_PAD: - offset++; + code = options[offset ++]; - break; + switch (code) { + case DHCP_OPTION_PAD: + continue; case DHCP_OPTION_END: return 0; + } - case DHCP_OPTION_MESSAGE_TYPE: - if (buflen < offset + 3) - return -ENOBUFS; + if (buflen < offset + 1) + return -ENOBUFS; + + len = options[offset ++]; + + if (buflen < offset + len) + return -EINVAL; + + option = &options[offset]; - len = options[++offset]; + switch (code) { + case DHCP_OPTION_MESSAGE_TYPE: if (len != 1) return -EINVAL; if (message_type) - *message_type = options[++offset]; - else - offset++; - - offset++; + *message_type = *option; break; - case DHCP_OPTION_OVERLOAD: - if (buflen < offset + 3) - return -ENOBUFS; - - len = options[++offset]; - if (len != 1) + case DHCP_OPTION_ERROR_MESSAGE: + if (len == 0) return -EINVAL; - if (overload) - *overload = options[++offset]; - else - offset++; + if (error_message) { + _cleanup_free_ char *string = NULL; - offset++; + /* Accept a trailing NUL byte */ + if (memchr(option, 0, len - 1)) + return -EINVAL; - break; + string = strndup((const char *) option, len); + if (!string) + return -ENOMEM; - default: - if (buflen < offset + 3) - return -ENOBUFS; + if (!ascii_is_valid(string)) + return -EINVAL; - code = options[offset]; - len = options[++offset]; + free(*error_message); + *error_message = string; + string = NULL; + } - if (buflen < ++offset + len) + break; + case DHCP_OPTION_OVERLOAD: + if (len != 1) return -EINVAL; - if (cb) - cb(code, len, &options[offset], userdata); + if (overload) + *overload = *option; + + break; - offset += len; + default: + if (cb) + cb(code, len, option, userdata); break; } + + offset += len; } if (offset < buflen) @@ -213,8 +228,8 @@ static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overlo return 0; } -int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *userdata) { +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) { + _cleanup_free_ char *error_message = NULL; uint8_t overload = 0; uint8_t message_type = 0; int r; @@ -227,27 +242,29 @@ int dhcp_option_parse(DHCPMessage *message, size_t len, len -= sizeof(DHCPMessage); - r = parse_options(message->options, len, &overload, &message_type, - cb, userdata); + r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata); if (r < 0) return r; if (overload & DHCP_OVERLOAD_FILE) { - r = parse_options(message->file, sizeof(message->file), - NULL, &message_type, cb, userdata); + r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata); if (r < 0) return r; } if (overload & DHCP_OVERLOAD_SNAME) { - r = parse_options(message->sname, sizeof(message->sname), - NULL, &message_type, cb, userdata); + r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata); if (r < 0) return r; } - if (message_type) - return message_type; + if (message_type == 0) + return -ENOMSG; + + if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) { + *_error_message = error_message; + error_message = NULL; + } - return -ENOMSG; + return message_type; } diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index cd7f5095ca..9ff42b155e 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -19,13 +19,12 @@ ***/ #include <errno.h> -#include <string.h> #include <net/ethernet.h> #include <net/if_arp.h> +#include <string.h> - -#include "dhcp-protocol.h" #include "dhcp-internal.h" +#include "dhcp-protocol.h" #define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index 88a81d2866..f65529a00e 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/udp.h> #include <netinet/ip.h> +#include <netinet/udp.h> #include <stdint.h> #include "macro.h" @@ -132,11 +132,13 @@ enum { DHCP_OPTION_MESSAGE_TYPE = 53, DHCP_OPTION_SERVER_IDENTIFIER = 54, DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, + DHCP_OPTION_ERROR_MESSAGE = 56, DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, DHCP_OPTION_RENEWAL_T1_TIME = 58, DHCP_OPTION_REBINDING_T2_TIME = 59, DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, DHCP_OPTION_CLIENT_IDENTIFIER = 61, + DHCP_OPTION_FQDN = 81, DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, @@ -144,3 +146,12 @@ enum { DHCP_OPTION_PRIVATE_LAST = 254, DHCP_OPTION_END = 255, }; + +#define DHCP_MAX_FQDN_LENGTH 255 + +enum { + DHCP_FQDN_FLAG_S = (1 << 0), + DHCP_FQDN_FLAG_O = (1 << 1), + DHCP_FQDN_FLAG_E = (1 << 2), + DHCP_FQDN_FLAG_N = (1 << 3), +}; diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index 3b88b93d9a..a42f622c37 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -22,14 +22,13 @@ #pragma once -#include "sd-event.h" #include "sd-dhcp-server.h" +#include "sd-event.h" +#include "dhcp-internal.h" #include "hashmap.h" -#include "util.h" #include "log.h" - -#include "dhcp-internal.h" +#include "util.h" typedef struct DHCPClientId { size_t length; diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 4edecf7711..f6cf0b30d3 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -25,6 +25,7 @@ #include <stdint.h> #include "sd-dhcp6-lease.h" + #include "dhcp6-internal.h" struct sd_dhcp6_lease { diff --git a/src/libsystemd-network/dhcp6-network.c b/src/libsystemd-network/dhcp6-network.c index 318ee9c4b4..fd2d60c9d5 100644 --- a/src/libsystemd-network/dhcp6-network.c +++ b/src/libsystemd-network/dhcp6-network.c @@ -33,36 +33,32 @@ #include "socket-util.h" int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { - struct in6_pktinfo pktinfo = { - .ipi6_ifindex = index, - }; union sockaddr_union src = { .in6.sin6_family = AF_INET6, .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT), - .in6.sin6_addr = IN6ADDR_ANY_INIT, + .in6.sin6_scope_id = index, }; _cleanup_close_ int s = -1; int r, off = 0, on = 1; - if (local_address) - memcpy(&src.in6.sin6_addr, local_address, - sizeof(src.in6.sin6_addr)); + assert(index > 0); + assert(local_address); + + src.in6.sin6_addr = *local_address; - s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_UDP); + s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP); if (s < 0) return -errno; - r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo, - sizeof(pktinfo)); + r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); if (r < 0) return -errno; - r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); if (r < 0) return -errno; - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); + r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (r < 0) return -errno; diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 0f46df6a1b..850212aea1 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/in.h> #include <errno.h> +#include <netinet/in.h> #include <string.h> #include "alloc-util.h" @@ -360,7 +360,6 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * /* End of name */ break; else if (c <= 63) { - _cleanup_free_ char *t = NULL; const char *label; /* Literal label */ @@ -369,21 +368,20 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * if (pos > optlen) return -EMSGSIZE; - r = dns_label_escape(label, c, &t); - if (r < 0) - goto fail; - - if (!GREEDY_REALLOC0(ret, allocated, n + !first + strlen(t) + 1)) { + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { r = -ENOMEM; goto fail; } - if (!first) - ret[n++] = '.'; - else + if (first) first = false; + else + ret[n++] = '.'; + + r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + goto fail; - memcpy(ret + n, t, r); n += r; continue; } else { diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index 91308bf6c3..acad9d7d6a 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -47,17 +47,15 @@ int icmp6_bind_router_solicitation(int index) { .ipv6mr_interface = index, }; _cleanup_close_ int s = -1; - int r, zero = 0, hops = 255; + int r, zero = 0, one = 1, hops = 255; - s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_ICMPV6); + 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)); + r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)); if (r < 0) return -errno; @@ -65,23 +63,23 @@ int icmp6_bind_router_solicitation(int index) { 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)); + 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)); + 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)); + 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)); + r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); + if (r < 0) + return -errno; + + r = setsockopt(s, SOL_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); if (r < 0) return -errno; @@ -101,25 +99,25 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { struct ether_addr rs_opt_mac; } _packed_ rs = { .rs.nd_rs_type = ND_ROUTER_SOLICIT, + .rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR, + .rs_opt.nd_opt_len = 1, }; - struct iovec iov[1] = { - { &rs, }, + struct iovec iov = { + .iov_base = &rs, + .iov_len = sizeof(rs), }; struct msghdr msg = { .msg_name = &dst, .msg_namelen = sizeof(dst), - .msg_iov = iov, + .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); + assert(s >= 0); + assert(ether_addr); + + rs.rs_opt_mac = *ether_addr; r = sendmsg(s, &msg, 0); if (r < 0) diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c index 97b6b485d2..1f1a49adbf 100644 --- a/src/libsystemd-network/lldp-port.c +++ b/src/libsystemd-network/lldp-port.c @@ -22,9 +22,9 @@ #include "alloc-util.h" #include "async.h" -#include "lldp-port.h" -#include "lldp-network.h" #include "lldp-internal.h" +#include "lldp-network.h" +#include "lldp-port.h" int lldp_port_start(lldp_port *p) { int r; diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index 7890160497..66343147a1 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -20,8 +20,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <net/ethernet.h> #include <arpa/inet.h> +#include <net/ethernet.h> #include "alloc-util.h" #include "lldp-tlv.h" diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index ca1da113d5..f5cd77477f 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -24,12 +24,12 @@ #include <net/ethernet.h> -#include "util.h" -#include "lldp.h" -#include "list.h" - #include "sd-lldp.h" +#include "list.h" +#include "lldp.h" +#include "util.h" + typedef struct sd_lldp_packet tlv_packet; typedef struct sd_lldp_section tlv_section; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index 52d76e443e..a4d4f1ae2f 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -29,9 +29,9 @@ #include "condition.h" #include "conf-parser.h" #include "dhcp-lease-internal.h" +#include "hexdecoct.h" #include "log.h" #include "network-internal.h" -#include "hexdecoct.h" #include "parse-util.h" #include "siphash24.h" #include "string-util.h" @@ -56,7 +56,7 @@ const char *net_get_name(struct udev_device *device) { #define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) -int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) { +int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) { size_t l, sz = 0; const char *name = NULL; int r; @@ -81,7 +81,7 @@ int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8 /* Let's hash the machine ID plus the device name. We * use a fixed, but originally randomly created hash * key here. */ - siphash24(result, v, sz, HASH_KEY.bytes); + *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); return 0; } diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index d5d4ef42f2..8a30921966 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -23,8 +23,8 @@ #include <stdbool.h> -#include "udev.h" #include "condition.h" +#include "udev.h" bool net_match_config(const struct ether_addr *match_mac, char * const *match_path, @@ -62,7 +62,7 @@ int config_parse_ifalias(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]); +int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); const char *net_get_name(struct udev_device *device); void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 137537253a..7deb00af9c 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -34,6 +34,8 @@ #include "dhcp-internal.h" #include "dhcp-lease-internal.h" #include "dhcp-protocol.h" +#include "dns-domain.h" +#include "hostname-util.h" #include "random-util.h" #include "string-util.h" #include "util.h" @@ -298,6 +300,9 @@ int sd_dhcp_client_set_hostname(sd_dhcp_client *client, assert_return(client, -EINVAL); + if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname)) + return -EINVAL; + if (streq_ptr(client->hostname, hostname)) return 0; @@ -539,6 +544,24 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, return 0; } +static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset, + const char *fqdn) { + uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH]; + int r; + + buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */ + DHCP_FQDN_FLAG_E; /* Canonical wire format */ + buffer[1] = 0; /* RCODE1 (deprecated) */ + buffer[2] = 0; /* RCODE2 (deprecated) */ + + r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3); + if (r > 0) + r = dhcp_option_append(message, optlen, optoffset, 0, + DHCP_OPTION_FQDN, 3 + r, buffer); + + return r; +} + static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, size_t len) { dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, @@ -576,13 +599,21 @@ static int client_send_discover(sd_dhcp_client *client) { return r; } - /* it is unclear from RFC 2131 if client should send hostname in - DHCPDISCOVER but dhclient does and so we do as well - */ if (client->hostname) { - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_HOST_NAME, - strlen(client->hostname), client->hostname); + /* According to RFC 4702 "clients that send the Client FQDN option in + their messages MUST NOT also send the Host Name option". Just send + one of the two depending on the hostname type. + */ + if (dns_name_is_single_label(client->hostname)) { + /* it is unclear from RFC 2131 if client should send hostname in + DHCPDISCOVER but dhclient does and so we do as well + */ + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_HOST_NAME, + strlen(client->hostname), client->hostname); + } else + r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset, + client->hostname); if (r < 0) return r; } @@ -688,9 +719,13 @@ static int client_send_request(sd_dhcp_client *client) { } if (client->hostname) { - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_HOST_NAME, - strlen(client->hostname), client->hostname); + if (dns_name_is_single_label(client->hostname)) + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_HOST_NAME, + strlen(client->hostname), client->hostname); + else + r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset, + client->hostname); if (r < 0) return r; } @@ -1047,7 +1082,7 @@ static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, return r; } - r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); + r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL); if (r != DHCP_OFFER) { log_dhcp_client(client, "received message was not an OFFER, ignoring"); return -ENOMSG; @@ -1086,7 +1121,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) { int r; - r = dhcp_option_parse(force, len, NULL, NULL); + r = dhcp_option_parse(force, len, NULL, NULL, NULL); if (r != DHCP_FORCERENEW) return -ENOMSG; @@ -1098,6 +1133,7 @@ static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; + _cleanup_free_ char *error_message = NULL; int r; r = dhcp_lease_new(&lease); @@ -1112,9 +1148,9 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, return r; } - r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease); + r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message); if (r == DHCP_NAK) { - log_dhcp_client(client, "NAK"); + log_dhcp_client(client, "NAK: %s", strna(error_message)); return -EADDRNOTAVAIL; } @@ -1478,9 +1514,8 @@ static int client_receive_message_udp(sd_event_source *s, int fd, r = ioctl(fd, FIONREAD, &buflen); if (r < 0) - return r; - - if (buflen < 0) + return -errno; + else if (buflen < 0) /* this can't be right */ return -EIO; @@ -1490,26 +1525,28 @@ static int client_receive_message_udp(sd_event_source *s, int fd, len = read(fd, message, buflen); if (len < 0) { - log_dhcp_client(client, "could not receive message from UDP " - "socket: %m"); - return 0; + if (errno == EAGAIN || errno == EINTR) + return 0; + + log_dhcp_client(client, "Could not receive message from UDP socket: %m"); + return -errno; } else if ((size_t)len < sizeof(DHCPMessage)) { - log_dhcp_client(client, "too small to be a DHCP message: ignoring"); + log_dhcp_client(client, "Too small to be a DHCP message: ignoring"); return 0; } if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) { - log_dhcp_client(client, "not a DHCP message: ignoring"); + log_dhcp_client(client, "Not a DHCP message: ignoring"); return 0; } if (message->op != BOOTREPLY) { - log_dhcp_client(client, "not a BOOTREPLY message: ignoring"); + log_dhcp_client(client, "Not a BOOTREPLY message: ignoring"); return 0; } if (message->htype != client->arp_type) { - log_dhcp_client(client, "packet type does not match client type"); + log_dhcp_client(client, "Packet type does not match client type"); return 0; } @@ -1523,13 +1560,12 @@ static int client_receive_message_udp(sd_event_source *s, int fd, } if (message->hlen != expected_hlen) { - log_dhcp_client(client, "unexpected packet hlen %d", message->hlen); + log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen); return 0; } if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) { - log_dhcp_client(client, "received chaddr does not match " - "expected: ignoring"); + log_dhcp_client(client, "Received chaddr does not match expected: ignoring"); return 0; } @@ -1537,8 +1573,7 @@ static int client_receive_message_udp(sd_event_source *s, int fd, be32toh(message->xid) != client->xid) { /* in BOUND state, we may receive FORCERENEW with xid set by server, so ignore the xid in this case */ - log_dhcp_client(client, "received xid (%u) does not match " - "expected (%u): ignoring", + log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring", be32toh(message->xid), client->xid); return 0; } @@ -1567,9 +1602,8 @@ static int client_receive_message_raw(sd_event_source *s, int fd, r = ioctl(fd, FIONREAD, &buflen); if (r < 0) - return r; - - if (buflen < 0) + return -errno; + else if (buflen < 0) /* this can't be right */ return -EIO; @@ -1582,9 +1616,12 @@ static int client_receive_message_raw(sd_event_source *s, int fd, len = recvmsg(fd, &msg, 0); if (len < 0) { - log_dhcp_client(client, "could not receive message from raw " - "socket: %m"); - return 0; + if (errno == EAGAIN || errno == EINTR) + return 0; + + log_dhcp_client(client, "Could not receive message from raw socket: %m"); + + return -errno; } else if ((size_t)len < sizeof(DHCPPacket)) return 0; diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 8befedc500..fccdc01bc3 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -661,7 +661,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void break; default: - log_debug("Ignoring option DHCP option %i while parsing.", code); + log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code); break; } diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 8d0d9955c3..587ff936ba 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -699,6 +699,7 @@ static int get_pool_offset(sd_dhcp_server *server, be32_t requested_ip) { int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, size_t length) { _cleanup_dhcp_request_free_ DHCPRequest *req = NULL; + _cleanup_free_ char *error_message = NULL; DHCPLease *existing_lease; int type, r; @@ -714,7 +715,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, if (!req) return -ENOMEM; - type = dhcp_option_parse(message, length, parse_request, req); + type = dhcp_option_parse(message, length, parse_request, req, &error_message); if (type < 0) return 0; @@ -753,7 +754,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, siphash24_init(&state, HASH_KEY.bytes); client_id_hash_func(&req->client_id, &state); - siphash24_finalize((uint8_t*)&hash, &state); + hash = htole64(siphash24_finalize(&state)); next_offer = hash % server->pool_size; for (i = 0; i < server->pool_size; i++) { @@ -784,8 +785,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, break; } case DHCP_DECLINE: - log_dhcp_server(server, "DECLINE (0x%x)", - be32toh(req->message->xid)); + log_dhcp_server(server, "DECLINE (0x%x): %s", be32toh(req->message->xid), strna(error_message)); /* TODO: make sure we don't offer this address again */ @@ -963,10 +963,10 @@ static int server_receive_message(sd_event_source *s, int fd, if (ioctl(fd, FIONREAD, &buflen) < 0) return -errno; - if (buflen < 0) + else if (buflen < 0) return -EIO; - message = malloc0(buflen); + message = malloc(buflen); if (!message) return -ENOMEM; @@ -974,9 +974,12 @@ static int server_receive_message(sd_event_source *s, int fd, iov.iov_len = buflen; len = recvmsg(fd, &msg, 0); - if (len < buflen) - return 0; - else if ((size_t)len < sizeof(DHCPMessage)) + if (len < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + return -errno; + } else if ((size_t)len < sizeof(DHCPMessage)) return 0; CMSG_FOREACH(cmsg, &msg) { diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index a443bb3a7a..36d909a4c5 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -32,6 +32,7 @@ #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" #include "fd-util.h" +#include "in-addr-util.h" #include "network-internal.h" #include "random-util.h" #include "string-table.h" @@ -46,6 +47,7 @@ struct sd_dhcp6_client { sd_event *event; int event_priority; int index; + struct in6_addr local_address; uint8_t mac_addr[MAX_MAC_ADDR_LEN]; size_t mac_addr_len; uint16_t arp_type; @@ -133,6 +135,18 @@ int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { return 0; } +int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) { + assert_return(client, -EINVAL); + assert_return(local_address, -EINVAL); + assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->local_address = *local_address; + + return 0; +} + int sd_dhcp6_client_set_mac( sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, @@ -881,7 +895,7 @@ static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *adver static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { sd_dhcp6_client *client = userdata; DHCP6_CLIENT_DONT_DESTROY(client); - _cleanup_free_ DHCP6Message *message; + _cleanup_free_ DHCP6Message *message = NULL; int r, buflen, len; assert(s); @@ -889,18 +903,26 @@ static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, assert(client->event); r = ioctl(fd, FIONREAD, &buflen); - if (r < 0 || buflen <= 0) - buflen = DHCP6_MIN_OPTIONS_SIZE; + if (r < 0) + return -errno; + else if (buflen < 0) + /* This really should not happen */ + return -EIO; - message = malloc0(buflen); + message = malloc(buflen); if (!message) return -ENOMEM; len = read(fd, message, buflen); - if ((size_t)len < sizeof(DHCP6Message)) { - log_dhcp6_client(client, "could not receive message from UDP socket: %m"); + if (len < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + log_dhcp6_client(client, "Could not receive message from UDP socket: %m"); + + return -errno; + } else if ((size_t)len < sizeof(DHCP6Message)) return 0; - } switch(message->type) { case DHCP6_SOLICIT: @@ -1135,9 +1157,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); assert_return(client->index > 0, -EINVAL); + assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL); if (!IN_SET(client->state, DHCP6_STATE_STOPPED)) - return -EALREADY; + return -EBUSY; r = client_reset(client); if (r < 0) @@ -1151,7 +1174,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { if (r < 0) return r; - r = dhcp6_network_bind_udp_socket(client->index, NULL); + r = dhcp6_network_bind_udp_socket(client->index, &client->local_address); if (r < 0) return r; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 0d915e20e7..30a7ef5785 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -101,6 +101,8 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) { if (!ll) return -ENOMEM; + ll->n_ref = 1; + r = sd_ipv4acd_new(&ll->acd); if (r < 0) return r; @@ -109,8 +111,6 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) { if (r < 0) return r; - ll->n_ref = 1; - *ret = ll; ll = NULL; @@ -143,15 +143,14 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { assert_return(ll, -EINVAL); if (!ll->random_data) { - uint8_t seed[8]; + uint64_t seed; /* If no random data is set, generate some from the MAC */ - siphash24(seed, &addr->ether_addr_octet, - ETH_ALEN, HASH_KEY.bytes); + seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes); assert_cc(sizeof(unsigned) <= 8); - r = sd_ipv4ll_set_address_seed(ll, *(unsigned*)seed); + r = sd_ipv4ll_set_address_seed(ll, (unsigned) htole64(seed)); if (r < 0) return r; } diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 0881973e7f..f2bce3b99f 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -32,6 +32,7 @@ #include "in-addr-util.h" #include "list.h" #include "socket-util.h" +#include "string-util.h" #define NDISC_ROUTER_SOLICITATION_INTERVAL 4 * USEC_PER_SEC #define NDISC_MAX_ROUTER_SOLICITATIONS 3 @@ -417,8 +418,7 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, return 0; } -static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, - ssize_t len) { +static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, ssize_t len) { void *opt; struct nd_opt_hdr *opt_hdr; @@ -481,30 +481,86 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_free_ struct nd_router_advert *ra = NULL; sd_ndisc *nd = userdata; - int r, buflen = 0, pref, stateful; - union sockaddr_union router = {}; - socklen_t router_len = sizeof(router); + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_LEN(sizeof(int))]; + } control = {}; + struct iovec iov = {}; + union sockaddr_union sa = {}; + struct msghdr msg = { + .msg_name = &sa.sa, + .msg_namelen = sizeof(sa), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = &control, + .msg_controllen = sizeof(control), + }; + struct cmsghdr *cmsg; + struct in6_addr *gw; unsigned lifetime; ssize_t len; + int r, pref, stateful, buflen = 0; assert(s); assert(nd); assert(nd->event); r = ioctl(fd, FIONREAD, &buflen); - if (r < 0 || buflen <= 0) - buflen = ICMP6_RECV_SIZE; + if (r < 0) + return -errno; + else if (buflen < 0) + /* This really should not happen */ + return -EIO; + + iov.iov_len = buflen; - ra = malloc(buflen); + ra = malloc(iov.iov_len); if (!ra) return -ENOMEM; - len = recvfrom(fd, ra, buflen, 0, &router.sa, &router_len); + iov.iov_base = ra; + + len = recvmsg(fd, &msg, 0); if (len < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + log_ndisc(nd, "Could not receive message from ICMPv6 socket: %m"); + return -errno; + } else if ((size_t)len < sizeof(struct nd_router_advert)) { return 0; - } else if (router_len != sizeof(router.in6) && router_len != 0) { - log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)router_len); + } else if (msg.msg_namelen == 0) + gw = NULL; /* only happens when running the test-suite over a socketpair */ + else if (msg.msg_namelen != sizeof(sa.in6)) { + log_ndisc(nd, "Received invalid source address size from ICMPv6 socket: %zu bytes", (size_t)msg.msg_namelen); + return 0; + } else + gw = &sa.in6.sin6_addr; + + assert(!(msg.msg_flags & MSG_CTRUNC)); + assert(!(msg.msg_flags & MSG_TRUNC)); + + CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_IPV6 && + cmsg->cmsg_type == IPV6_HOPLIMIT && + cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + int hops = *(int*)CMSG_DATA(cmsg); + + if (hops != 255) { + log_ndisc(nd, "Received RA with invalid hop limit %d. Ignoring.", hops); + return 0; + } + + break; + } + } + + if (gw && !in_addr_is_link_local(AF_INET6, (const union in_addr_union*) gw)) { + _cleanup_free_ char *addr = NULL; + + (void)in_addr_to_string(AF_INET6, (const union in_addr_union*) gw, &addr); + + log_ndisc(nd, "Received RA from non-link-local address %s. Ignoring.", strna(addr)); return 0; } @@ -544,7 +600,7 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r } if (nd->router_callback) - nd->router_callback(nd, stateful, router_len != 0 ? &router.in6.sin6_addr : NULL, lifetime, pref, nd->userdata); + nd->router_callback(nd, stateful, gw, lifetime, pref, nd->userdata); return 0; } @@ -552,8 +608,6 @@ static int ndisc_router_advertisment_recv(sd_event_source *s, int fd, uint32_t r static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, void *userdata) { sd_ndisc *nd = userdata; uint64_t time_now, next_timeout; - struct ether_addr unset = { }; - struct ether_addr *addr = NULL; int r; assert(s); @@ -567,10 +621,7 @@ static int ndisc_router_solicitation_timeout(sd_event_source *s, uint64_t usec, nd->callback(nd, SD_NDISC_EVENT_TIMEOUT, nd->userdata); nd->state = NDISC_STATE_ADVERTISMENT_LISTEN; } else { - if (memcmp(&nd->mac_addr, &unset, sizeof(struct ether_addr))) - addr = &nd->mac_addr; - - r = icmp6_send_router_solicitation(nd->fd, addr); + r = icmp6_send_router_solicitation(nd->fd, &nd->mac_addr); if (r < 0) log_ndisc(nd, "Error sending Router Solicitation"); else { @@ -628,7 +679,7 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd) { assert(nd->event); if (nd->state != NDISC_STATE_IDLE) - return -EINVAL; + return -EBUSY; if (nd->index < 1) return -EINVAL; diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c index 94c31af3f3..69eff5116f 100644 --- a/src/libsystemd-network/test-acd.c +++ b/src/libsystemd-network/test-acd.c @@ -19,21 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <errno.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-ipv4acd.h" +#include "sd-netlink.h" -#include "util.h" #include "event-util.h" -#include "netlink-util.h" #include "in-addr-util.h" +#include "netlink-util.h" +#include "util.h" static void acd_handler(sd_ipv4acd *acd, int event, void *userdata) { assert_se(acd); diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 5b52c1cbb9..4478147a83 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -32,8 +32,8 @@ #include "dhcp-internal.h" #include "dhcp-protocol.h" #include "event-util.h" -#include "util.h" #include "fd-util.h" +#include "util.h" static uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'}; @@ -223,7 +223,7 @@ int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, const voi static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp) { int res; - res = dhcp_option_parse(dhcp, size, check_options, NULL); + res = dhcp_option_parse(dhcp, size, check_options, NULL, NULL); assert_se(res == DHCP_DISCOVER); if (verbose) @@ -390,7 +390,7 @@ static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) { uint8_t *msg_bytes = (uint8_t *)request; int res; - res = dhcp_option_parse(request, size, check_options, NULL); + res = dhcp_option_parse(request, size, check_options, NULL, NULL); assert_se(res == DHCP_REQUEST); assert_se(xid == request->xid); @@ -420,7 +420,7 @@ static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) { uint8_t *msg_bytes = (uint8_t *)discover; int res; - res = dhcp_option_parse(discover, size, check_options, NULL); + res = dhcp_option_parse(discover, size, check_options, NULL, NULL); assert_se(res == DHCP_DISCOVER); assert_se(msg_bytes[size - 1] == DHCP_OPTION_END); diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index 2d29e28f16..75d22c4df3 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -1,8 +1,8 @@ /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ -#include <stdio.h> -#include <stdbool.h> #include <errno.h> +#include <stdbool.h> +#include <stdio.h> #include <string.h> #include "alloc-util.h" @@ -75,9 +75,8 @@ static const char *dhcp_type(int type) { static void test_invalid_buffer_length(void) { DHCPMessage message; - assert_se(dhcp_option_parse(&message, 0, NULL, NULL) == -EINVAL); - assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL) - == -EINVAL); + assert_se(dhcp_option_parse(&message, 0, NULL, NULL, NULL) == -EINVAL); + assert_se(dhcp_option_parse(&message, sizeof(DHCPMessage) - 1, NULL, NULL, NULL) == -EINVAL); } static void test_message_init(void) { @@ -101,7 +100,7 @@ static void test_message_init(void) { assert_se(magic[2] == 83); assert_se(magic[3] == 99); - assert_se(dhcp_option_parse(message, len, NULL, NULL) >= 0); + assert_se(dhcp_option_parse(message, len, NULL, NULL, NULL) >= 0); } static DHCPMessage *create_message(uint8_t *options, uint16_t optlen, @@ -264,19 +263,12 @@ static void test_options(struct option_desc *desc) { buflen = sizeof(DHCPMessage) + optlen; if (!desc) { - assert_se((res = dhcp_option_parse(message, buflen, - test_options_cb, - NULL)) == -ENOMSG); + assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, NULL, NULL)) == -ENOMSG); } else if (desc->success) { - assert_se((res = dhcp_option_parse(message, buflen, - test_options_cb, - desc)) >= 0); - assert_se(desc->pos == -1 && desc->filepos == -1 && - desc->snamepos == -1); + assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) >= 0); + assert_se(desc->pos == -1 && desc->filepos == -1 && desc->snamepos == -1); } else - assert_se((res = dhcp_option_parse(message, buflen, - test_options_cb, - desc)) < 0); + assert_se((res = dhcp_option_parse(message, buflen, test_options_cb, desc, NULL)) < 0); if (verbose) printf("DHCP type %s\n", dhcp_type(res)); diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 1a5c8c4605..2b5f59e4d6 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -200,13 +200,11 @@ static void test_message_handler(void) { 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; + return htole64(siphash24_finalize(&state)); } static void test_client_id_hash(void) { diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 17ed6d58f3..9e05fde8f6 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -562,6 +562,7 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event, sd_event *e = userdata; sd_dhcp6_lease *lease; struct in6_addr *addrs; + struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; char **domains; assert_se(e); @@ -590,6 +591,8 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event, assert_se(sd_dhcp6_client_set_callback(client, test_client_solicit_cb, e) >= 0); + assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0); + assert_se(sd_dhcp6_client_start(client) >= 0); } @@ -701,6 +704,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()); + struct in6_addr address = { { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01 } } }; int val = true; if (verbose) @@ -729,6 +733,8 @@ static int test_client_solicit(sd_event *e) { time_now + 2 * USEC_PER_SEC, 0, test_hangcheck, NULL) >= 0); + assert_se(sd_dhcp6_client_set_local_address(client, &address) >= 0); + assert_se(sd_dhcp6_client_start(client) >= 0); sd_event_loop(e); diff --git a/src/libsystemd/sd-bus/bus-bloom.c b/src/libsystemd/sd-bus/bus-bloom.c index 91fab90cb0..c0c5d445eb 100644 --- a/src/libsystemd/sd-bus/bus-bloom.c +++ b/src/libsystemd/sd-bus/bus-bloom.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "siphash24.h" #include "bus-bloom.h" +#include "siphash24.h" +#include "util.h" static inline void set_bit(uint64_t filter[], unsigned long b) { filter[b >> 6] |= 1ULL << (b & 63); @@ -45,7 +45,7 @@ static void bloom_add_data( const void *data, /* Data to hash */ size_t n) { /* Size of data to hash in bytes */ - uint8_t h[8]; + uint64_t h; uint64_t m; unsigned w, i, c = 0; unsigned hash_index; @@ -72,11 +72,11 @@ static void bloom_add_data( for (d = 0; d < w; d++) { if (c <= 0) { - siphash24(h, data, n, hash_keys[hash_index++].bytes); + h = siphash24(data, n, hash_keys[hash_index++].bytes); c += 8; } - p = (p << 8ULL) | (uint64_t) h[8 - c]; + p = (p << 8ULL) | (uint64_t) ((uint8_t *)&h)[8 - c]; c--; } diff --git a/src/libsystemd/sd-bus/bus-bloom.h b/src/libsystemd/sd-bus/bus-bloom.h index a9350d7f51..38892044f1 100644 --- a/src/libsystemd/sd-bus/bus-bloom.h +++ b/src/libsystemd/sd-bus/bus-bloom.h @@ -22,6 +22,7 @@ ***/ #include <stdbool.h> +#include <stddef.h> #include <stdint.h> /* diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 52f8dfd3be..8d486fcbbd 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -22,8 +22,9 @@ #include <errno.h> #include "sd-bus.h" -#include "bus-error.h" + #include "bus-common-errors.h" +#include "bus-error.h" BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_UNIT, ENOENT), diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 589a90bbff..7da6ba9903 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <fcntl.h> +#include <unistd.h> #include "bus-container.h" #include "bus-internal.h" diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index ddd3a55b6c..94251fe87c 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -23,8 +23,8 @@ #include <valgrind/memcheck.h> #endif -#include <stddef.h> #include <errno.h> +#include <stddef.h> #include "sd-bus.h" diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h index 5009ca8e61..e01b075832 100644 --- a/src/libsystemd/sd-bus/bus-control.h +++ b/src/libsystemd/sd-bus/bus-control.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "bus-match.h" int bus_add_match_internal(sd_bus *bus, const char *match, struct bus_match_component *components, unsigned n_components, uint64_t cookie); diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h index d2522edeba..71e56991fa 100644 --- a/src/libsystemd/sd-bus/bus-dump.h +++ b/src/libsystemd/sd-bus/bus-dump.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> #include "sd-bus.h" diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c index 239d7245e6..404eaa3c89 100644 --- a/src/libsystemd/sd-bus/bus-error.c +++ b/src/libsystemd/sd-bus/bus-error.c @@ -29,10 +29,10 @@ #include "sd-bus.h" #include "alloc-util.h" +#include "bus-error.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[] = { SD_BUS_ERROR_MAP("org.freedesktop.DBus.Error.Failed", EACCES), diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h index fb0199c948..d7fd8612d0 100644 --- a/src/libsystemd/sd-bus/bus-error.h +++ b/src/libsystemd/sd-bus/bus-error.h @@ -24,6 +24,7 @@ #include <stdbool.h> #include "sd-bus.h" + #include "macro.h" bool bus_error_is_dirty(sd_bus_error *e); diff --git a/src/libsystemd/sd-bus/bus-gvariant.c b/src/libsystemd/sd-bus/bus-gvariant.c index 402d43d66d..ec027590b2 100644 --- a/src/libsystemd/sd-bus/bus-gvariant.c +++ b/src/libsystemd/sd-bus/bus-gvariant.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "bus-type.h" #include "bus-gvariant.h" #include "bus-signature.h" +#include "bus-type.h" int bus_gvariant_get_size(const char *signature) { const char *p; diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h index 1914e6cb8b..57c2430ee8 100644 --- a/src/libsystemd/sd-bus/bus-introspect.h +++ b/src/libsystemd/sd-bus/bus-introspect.h @@ -24,6 +24,7 @@ #include <stdio.h> #include "sd-bus.h" + #include "set.h" struct introspect { diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 8c472626a8..303e49fa84 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -23,6 +23,7 @@ #include "bus-internal.h" #include "bus-introspect.h" #include "bus-message.h" +#include "bus-objects.h" #include "bus-signature.h" #include "bus-slot.h" #include "bus-type.h" @@ -30,7 +31,6 @@ #include "set.h" #include "string-util.h" #include "strv.h" -#include "bus-objects.h" static int node_vtable_get_userdata( sd_bus *bus, diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index 550bad27ba..e405a04c53 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -24,8 +24,8 @@ #include "alloc-util.h" #include "bus-control.h" #include "bus-objects.h" -#include "string-util.h" #include "bus-slot.h" +#include "string-util.h" sd_bus_slot *bus_slot_allocate( sd_bus *bus, diff --git a/src/libsystemd/sd-bus/bus-slot.h b/src/libsystemd/sd-bus/bus-slot.h index 23a15e4d02..c997e58f9a 100644 --- a/src/libsystemd/sd-bus/bus-slot.h +++ b/src/libsystemd/sd-bus/bus-slot.h @@ -22,6 +22,7 @@ ***/ #include "sd-bus.h" + #include "bus-internal.h" sd_bus_slot *bus_slot_allocate(sd_bus *bus, bool floating, BusSlotType type, size_t extra, void *userdata); diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index a8d79b01b0..99780c8cce 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -20,12 +20,12 @@ ***/ #include <endian.h> -#include <stdlib.h> -#include <unistd.h> #include <netdb.h> #include <poll.h> -#include <sys/mman.h> #include <pthread.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <unistd.h> #include "sd-bus.h" @@ -46,10 +46,10 @@ #include "cgroup-util.h" #include "def.h" #include "fd-util.h" +#include "hexdecoct.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" diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index 767aef63ff..f20eced4ac 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <fcntl.h> #include <pthread.h> +#include <stdlib.h> #include <unistd.h> -#include <fcntl.h> #include "sd-bus.h" @@ -31,11 +31,11 @@ #include "bus-internal.h" #include "bus-match.h" #include "bus-util.h" +#include "fd-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-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index 580117165a..bd0101af9e 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -20,6 +20,7 @@ ***/ #include "sd-bus.h" + #include "bus-dump.h" #include "bus-util.h" #include "cgroup-util.h" diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 5753c04b0e..9d6c221eb0 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -20,10 +20,11 @@ ***/ #include "sd-bus.h" + +#include "bus-common-errors.h" #include "bus-error.h" #include "bus-util.h" #include "errno-list.h" -#include "bus-common-errors.h" static void test_error(void) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c index f39dedeb24..26ba16d119 100644 --- a/src/libsystemd/sd-bus/test-bus-introspect.c +++ b/src/libsystemd/sd-bus/test-bus-introspect.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" #include "bus-introspect.h" +#include "log.h" static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { return -EINVAL; diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index 0747d6a37c..0a6093e78b 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <math.h> +#include <stdlib.h> #ifdef HAVE_GLIB #include <gio/gio.h> @@ -38,8 +38,8 @@ #include "bus-message.h" #include "bus-util.h" #include "fd-util.h" -#include "log.h" #include "hexdecoct.h" +#include "log.h" #include "util.h" static void test_bus_path_encode_unique(void) { diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index 75ea28371b..94896c196a 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -19,13 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" -#include "macro.h" - #include "bus-match.h" #include "bus-message.h" -#include "bus-util.h" #include "bus-slot.h" +#include "bus-util.h" +#include "log.h" +#include "macro.h" static bool mask[32]; diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 5bc72e2355..edd63f9ea7 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> #include <pthread.h> +#include <stdlib.h> #include "sd-bus.h" diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c index 92a810a7d8..949d16e6e9 100644 --- a/src/libsystemd/sd-bus/test-bus-signature.c +++ b/src/libsystemd/sd-bus/test-bus-signature.c @@ -19,10 +19,10 @@ 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" +#include "bus-signature.h" +#include "log.h" +#include "string-util.h" int main(int argc, char *argv[]) { char prefix[256]; diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c index ff8df61a9e..1cf8416fa4 100644 --- a/src/libsystemd/sd-bus/test-bus-zero-copy.c +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@ -27,11 +27,11 @@ #include "bus-dump.h" #include "bus-kernel.h" #include "bus-message.h" +#include "fd-util.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-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index ee4886700e..3191b458d1 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -34,6 +34,7 @@ #include "macro.h" #include "missing.h" #include "prioq.h" +#include "process-util.h" #include "set.h" #include "signal-util.h" #include "string-util.h" @@ -415,11 +416,9 @@ _public_ int sd_event_new(sd_event** ret) { e->original_pid = getpid(); e->perturb = USEC_INFINITY; - e->pending = prioq_new(pending_prioq_compare); - if (!e->pending) { - r = -ENOMEM; + r = prioq_ensure_allocated(&e->pending, pending_prioq_compare); + if (r < 0) goto fail; - } e->epoll_fd = epoll_create1(EPOLL_CLOEXEC); if (e->epoll_fd < 0) { @@ -436,7 +435,9 @@ fail: } _public_ sd_event* sd_event_ref(sd_event *e) { - assert_return(e, NULL); + + if (!e) + return NULL; assert(e->n_ref >= 1); e->n_ref++; @@ -808,7 +809,7 @@ static void source_disconnect(sd_event_source *s) { s->event->n_enabled_child_sources--; } - (void) hashmap_remove(s->event->child_sources, INT_TO_PTR(s->child.pid)); + (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); event_gc_signal_data(s->event, &s->priority, SIGCHLD); } @@ -1049,17 +1050,13 @@ _public_ int sd_event_add_time( d = event_get_clock_data(e, type); assert(d); - if (!d->earliest) { - d->earliest = prioq_new(earliest_time_prioq_compare); - if (!d->earliest) - return -ENOMEM; - } + r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); + if (r < 0) + return r; - if (!d->latest) { - d->latest = prioq_new(latest_time_prioq_compare); - if (!d->latest) - return -ENOMEM; - } + r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); + if (r < 0) + return r; if (d->fd < 0) { r = event_setup_timer_fd(e, d, clock); @@ -1188,7 +1185,7 @@ _public_ int sd_event_add_child( if (r < 0) return r; - if (hashmap_contains(e->child_sources, INT_TO_PTR(pid))) + if (hashmap_contains(e->child_sources, PID_TO_PTR(pid))) return -EBUSY; s = source_new(e, !ret, SOURCE_CHILD); @@ -1201,7 +1198,7 @@ _public_ int sd_event_add_child( s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; - r = hashmap_put(e->child_sources, INT_TO_PTR(pid), s); + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); if (r < 0) { source_free(s); return r; @@ -1310,11 +1307,9 @@ _public_ int sd_event_add_exit( assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); - if (!e->exit) { - e->exit = prioq_new(exit_prioq_compare); - if (!e->exit) - return -ENOMEM; - } + r = prioq_ensure_allocated(&e->exit, exit_prioq_compare); + if (r < 0) + return r; s = source_new(e, !ret, SOURCE_EXIT); if (!s) @@ -1338,7 +1333,9 @@ _public_ int sd_event_add_exit( } _public_ sd_event_source* sd_event_source_ref(sd_event_source *s) { - assert_return(s, NULL); + + if (!s) + return NULL; assert(s->n_ref >= 1); s->n_ref++; @@ -2432,7 +2429,9 @@ _public_ int sd_event_prepare(sd_event *e) { e->iteration++; + e->state = SD_EVENT_PREPARING; r = event_prepare(e); + e->state = SD_EVENT_INITIAL; if (r < 0) return r; diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index c1a3b49483..9417a8d1d1 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -158,11 +158,22 @@ static int exit_handler(sd_event_source *s, void *userdata) { return 3; } +static bool got_post = false; + +static int post_handler(sd_event_source *s, void *userdata) { + log_info("got post handler"); + + got_post = true; + + return 2; +} + static void test_basic(void) { sd_event *e = NULL; sd_event_source *w = NULL, *x = NULL, *y = NULL, *z = NULL, *q = NULL, *t = NULL; static const char ch = 'x'; int a[2] = { -1, -1 }, b[2] = { -1, -1}, d[2] = { -1, -1}, k[2] = { -1, -1 }; + uint64_t event_now; assert_se(pipe(a) >= 0); assert_se(pipe(b) >= 0); @@ -170,6 +181,7 @@ static void test_basic(void) { assert_se(pipe(k) >= 0); assert_se(sd_event_default(&e) >= 0); + assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0); assert_se(sd_event_set_watchdog(e, true) >= 0); @@ -230,10 +242,14 @@ static void test_basic(void) { sd_event_source_unref(y); do_quit = true; - assert_se(sd_event_source_set_time(z, now(CLOCK_MONOTONIC) + 200 * USEC_PER_MSEC) >= 0); + assert_se(sd_event_add_post(e, NULL, post_handler, NULL) >= 0); + assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0); + assert_se(sd_event_source_set_time(z, event_now + 200 * USEC_PER_MSEC) >= 0); assert_se(sd_event_source_set_enabled(z, SD_EVENT_ONESHOT) >= 0); assert_se(sd_event_loop(e) >= 0); + assert_se(got_post); + assert_se(got_exit); sd_event_source_unref(z); sd_event_source_unref(q); diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index 1e17ea6a06..c12bb1e20b 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -26,9 +26,9 @@ #include "sd-id128.h" #include "fd-util.h" +#include "hexdecoct.h" #include "io-util.h" #include "macro.h" -#include "hexdecoct.h" #include "random-util.h" #include "util.h" diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c index a00865b56b..d431ba4be4 100644 --- a/src/libsystemd/sd-netlink/local-addresses.c +++ b/src/libsystemd/sd-netlink/local-addresses.c @@ -23,9 +23,9 @@ #include "sd-netlink.h" #include "alloc-util.h" -#include "netlink-util.h" -#include "macro.h" #include "local-addresses.h" +#include "macro.h" +#include "netlink-util.h" static int address_compare(const void *_a, const void *_b) { const struct local_address *a = _a, *b = _b; diff --git a/src/libsystemd/sd-netlink/local-addresses.h b/src/libsystemd/sd-netlink/local-addresses.h index 5d0f11a2c1..74d4f25534 100644 --- a/src/libsystemd/sd-netlink/local-addresses.h +++ b/src/libsystemd/sd-netlink/local-addresses.h @@ -23,6 +23,7 @@ #include "sd-netlink.h" + #include "in-addr-util.h" struct local_address { diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index bf7c641541..9e636a0b53 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -21,6 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "macro.h" + enum { NETLINK_TYPE_UNSPEC, NETLINK_TYPE_U8, /* NLA_U8 */ diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 6f9fd2993b..95690b7ff1 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -21,8 +21,8 @@ #include "sd-netlink.h" -#include "netlink-util.h" #include "netlink-internal.h" +#include "netlink-util.h" int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) { _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c index 7180175970..0b53297ab8 100644 --- a/src/libsystemd/sd-netlink/test-local-addresses.c +++ b/src/libsystemd/sd-netlink/test-local-addresses.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "af-list.h" #include "alloc-util.h" #include "in-addr-util.h" #include "local-addresses.h" -#include "af-list.h" static void print_local_addresses(struct local_address *a, unsigned n) { unsigned i; diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c index 381397cc52..9e52db3b3d 100644 --- a/src/libsystemd/sd-utf8/sd-utf8.c +++ b/src/libsystemd/sd-utf8/sd-utf8.c @@ -21,8 +21,8 @@ #include "sd-utf8.h" -#include "util.h" #include "utf8.h" +#include "util.h" _public_ const char *sd_utf8_is_valid(const char *s) { assert_return(s, NULL); diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 5f50496291..52c5075110 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -21,8 +21,8 @@ #define _LIBUDEV_PRIVATE_H_ #include <signal.h> -#include <stdint.h> #include <stdbool.h> +#include <stdint.h> #include "libudev.h" diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c index 58410b1b8f..e3dffa6925 100644 --- a/src/libudev/libudev-queue.c +++ b/src/libudev/libudev-queue.c @@ -18,11 +18,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> #include <errno.h> +#include <stddef.h> +#include <stdlib.h> #include <sys/inotify.h> +#include <unistd.h> #include "alloc-util.h" #include "fd-util.h" diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h index 93e9ed02eb..1f55759798 100644 --- a/src/login/logind-acl.h +++ b/src/login/logind-acl.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <stdbool.h> +#include <sys/types.h> #include "libudev.h" diff --git a/src/login/logind-action.h b/src/login/logind-action.h index e9b424b5f6..63c279cde7 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -35,8 +35,8 @@ typedef enum HandleAction { _HANDLE_ACTION_INVALID = -1 } HandleAction; -#include "logind.h" #include "logind-inhibit.h" +#include "logind.h" int manager_handle_action( Manager *m, diff --git a/src/login/logind-core.c b/src/login/logind-core.c index b3f30c8dc9..36cdbbe0f9 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> -#include <sys/ioctl.h> #include <fcntl.h> #include <pwd.h> +#include <sys/ioctl.h> +#include <sys/types.h> #include <linux/vt.h> #include "alloc-util.h" @@ -98,15 +98,16 @@ int manager_add_session(Manager *m, const char *id, Session **_session) { int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) { User *u; + int r; assert(m); assert(name); u = hashmap_get(m->users, UID_TO_PTR(uid)); if (!u) { - u = user_new(m, uid, gid, name); - if (!u) - return -ENOMEM; + r = user_new(&u, m, uid, gid, name); + if (r < 0) + return r; } if (_user) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 7890d68aa0..e507a19aef 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -308,8 +308,10 @@ static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd r = sd_bus_message_read(message, "u", &pid); if (r < 0) return r; + if (pid < 0) + return -EINVAL; - if (pid <= 0) { + if (pid == 0) { r = manager_get_session_from_creds(m, message, NULL, error, &session); if (r < 0) return r; @@ -369,8 +371,10 @@ static int method_get_user_by_pid(sd_bus_message *message, void *userdata, sd_bu r = sd_bus_message_read(message, "u", &pid); if (r < 0) return r; + if (pid < 0) + return -EINVAL; - if (pid <= 0) { + if (pid == 0) { r = manager_get_user_from_creds(m, message, UID_INVALID, error, &user); if (r < 0) return r; @@ -573,12 +577,14 @@ static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bu static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) { const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop; - uint32_t uid, leader, audit_id = 0; + uint32_t audit_id = 0; _cleanup_free_ char *id = NULL; Session *session = NULL; Manager *m = userdata; User *user = NULL; Seat *seat = NULL; + pid_t leader; + uid_t uid; int remote; uint32_t vtnr = 0; SessionType t; @@ -588,11 +594,16 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus assert(message); assert(m); + assert_cc(sizeof(pid_t) == sizeof(uint32_t)); + assert_cc(sizeof(uid_t) == sizeof(uint32_t)); + r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host); if (r < 0) return r; - if (leader == 1) + if (!uid_is_valid(uid)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID"); + if (leader < 0 || leader == 1) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID"); if (isempty(type)) @@ -684,7 +695,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus c = SESSION_USER; } - if (leader <= 0) { + if (leader == 0) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); @@ -1093,7 +1104,9 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu r = sd_bus_creds_get_owner_uid(creds, &uid); if (r < 0) return r; - } + + } else if (!uid_is_valid(uid)) + return -EINVAL; errno = 0; pw = getpwuid(uid); @@ -2607,11 +2620,8 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err } session = hashmap_get(m->session_units, unit); - if (session) { - - if (streq_ptr(path, session->scope_job)) - session->scope_job = mfree(session->scope_job); - + if (session && streq_ptr(path, session->scope_job)) { + session->scope_job = mfree(session->scope_job); session_jobs_reply(session, unit, result); session_save(session); @@ -2620,7 +2630,9 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err } user = hashmap_get(m->user_units, unit); - if (user) { + if (user && + (streq_ptr(path, user->service_job) || + streq_ptr(path, user->slice_job))) { if (streq_ptr(path, user->service_job)) user->service_job = mfree(user->service_job); @@ -2740,13 +2752,101 @@ int manager_send_changed(Manager *manager, const char *property, ...) { l); } +int manager_start_slice( + Manager *manager, + const char *slice, + const char *description, + const char *after, + const char *after2, + uint64_t tasks_max, + sd_bus_error *error, + char **job) { + + _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + int r; + + assert(manager); + assert(slice); + + r = sd_bus_message_new_method_call( + manager->bus, + &m, + "org.freedesktop.systemd1", + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartTransientUnit"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "ss", strempty(slice), "fail"); + if (r < 0) + return r; + + r = sd_bus_message_open_container(m, 'a', "(sv)"); + if (r < 0) + return r; + + if (!isempty(description)) { + r = sd_bus_message_append(m, "(sv)", "Description", "s", description); + if (r < 0) + return r; + } + + if (!isempty(after)) { + r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after); + if (r < 0) + return r; + } + + if (!isempty(after2)) { + r = sd_bus_message_append(m, "(sv)", "After", "as", 1, after2); + if (r < 0) + return r; + } + + r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max); + if (r < 0) + return r; + + r = sd_bus_message_close_container(m); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "a(sa(sv))", 0); + if (r < 0) + return r; + + r = sd_bus_call(manager->bus, m, 0, error, &reply); + if (r < 0) + return r; + + if (job) { + const char *j; + char *copy; + + r = sd_bus_message_read(reply, "o", &j); + if (r < 0) + return r; + + copy = strdup(j); + if (!copy) + return -ENOMEM; + + *job = copy; + } + + return 1; +} + int manager_start_scope( Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, - const char *after, const char *after2, + const char *after, + const char *after2, + uint64_t tasks_max, sd_bus_error *error, char **job) { @@ -2814,6 +2914,10 @@ int manager_start_scope( if (r < 0) return r; + r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", tasks_max); + if (r < 0) + return r; + r = sd_bus_message_close_container(m); if (r < 0) return r; @@ -2859,7 +2963,7 @@ int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, "StartUnit", error, &reply, - "ss", unit, "fail"); + "ss", unit, "replace"); if (r < 0) return r; diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 9218d098e0..8552c464cc 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -34,3 +34,4 @@ Login.IdleAction, config_parse_handle_action, 0, offsetof(Manag Login.IdleActionSec, config_parse_sec, 0, offsetof(Manager, idle_action_usec) Login.RuntimeDirectorySize, config_parse_tmpfs_size, 0, offsetof(Manager, runtime_dir_size) Login.RemoveIPC, config_parse_bool, 0, offsetof(Manager, remove_ipc) +Login.UserTasksMax, config_parse_uint64, 0, offsetof(Manager, user_tasks_max) diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 1d561a6f8a..9f03a7b31e 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -36,7 +36,6 @@ #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" @@ -513,25 +512,31 @@ static int session_start_scope(Session *s) { assert(s); assert(s->user); - assert(s->user->slice); if (!s->scope) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *description = NULL; char *scope, *job = NULL; - - description = strjoin("Session ", s->id, " of user ", s->user->name, NULL); - if (!description) - return log_oom(); + const char *description; scope = strjoin("session-", s->id, ".scope", NULL); if (!scope) return log_oom(); - r = manager_start_scope(s->manager, scope, s->leader, s->user->slice, description, "systemd-logind.service", "systemd-user-sessions.service", &error, &job); + description = strjoina("Session ", s->id, " of user ", s->user->name, NULL); + + r = manager_start_scope( + s->manager, + scope, + s->leader, + s->user->slice, + description, + "systemd-logind.service", + "systemd-user-sessions.service", + (uint64_t) -1, /* disable TasksMax= for the scope, rely on the slice setting for it */ + &error, + &job); if (r < 0) { - log_error("Failed to start session scope %s: %s %s", - scope, bus_error_message(&error, r), error.name); + log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(&error, r)); free(scope); return r; } else { @@ -543,7 +548,7 @@ static int session_start_scope(Session *s) { } if (s->scope) - hashmap_put(s->manager->session_units, s->scope, s); + (void) hashmap_put(s->manager->session_units, s->scope, s); return 0; } diff --git a/src/login/logind-session.h b/src/login/logind-session.h index d054c33cec..d27407fc92 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -25,8 +25,8 @@ typedef struct Session Session; typedef enum KillWho KillWho; #include "list.h" -#include "logind-user.h" #include "login-util.h" +#include "logind-user.h" typedef enum SessionState { SESSION_OPENING, /* Session scope is being created */ diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 56bc5a010c..778f19b50d 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -25,6 +25,7 @@ #include <unistd.h> #include "alloc-util.h" +#include "bus-common-errors.h" #include "bus-error.h" #include "bus-util.h" #include "clean-ipc.h" @@ -44,47 +45,68 @@ #include "rm-rf.h" #include "smack-util.h" #include "special.h" +#include "stdio-util.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; +int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name) { + _cleanup_(user_freep) User *u = NULL; + char lu[DECIMAL_STR_MAX(uid_t) + 1]; + int r; + assert(out); assert(m); assert(name); u = new0(User, 1); if (!u) - return NULL; + return -ENOMEM; + + u->manager = m; + u->uid = uid; + u->gid = gid; + xsprintf(lu, UID_FMT, uid); u->name = strdup(name); if (!u->name) - goto fail; + return -ENOMEM; if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0) - goto fail; + return -ENOMEM; - if (hashmap_put(m->users, UID_TO_PTR(uid), u) < 0) - goto fail; + if (asprintf(&u->runtime_path, "/run/user/"UID_FMT, uid) < 0) + return -ENOMEM; - u->manager = m; - u->uid = uid; - u->gid = gid; + r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &u->slice); + if (r < 0) + return r; - return u; + r = unit_name_build("user", lu, ".service", &u->service); + if (r < 0) + return r; -fail: - free(u->state_file); - free(u->name); - free(u); + r = hashmap_put(m->users, UID_TO_PTR(uid), u); + if (r < 0) + return r; + + r = hashmap_put(m->user_units, u->slice, u); + if (r < 0) + return r; - return NULL; + r = hashmap_put(m->user_units, u->service, u); + if (r < 0) + return r; + + *out = u; + u = NULL; + return 0; } -void user_free(User *u) { - assert(u); +User *user_free(User *u) { + if (!u) + return NULL; if (u->in_gc_queue) LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u); @@ -92,26 +114,24 @@ void user_free(User *u) { while (u->sessions) session_free(u->sessions); - if (u->slice) { - hashmap_remove(u->manager->user_units, u->slice); - free(u->slice); - } + if (u->service) + hashmap_remove_value(u->manager->user_units, u->service, u); - if (u->service) { - hashmap_remove(u->manager->user_units, u->service); - free(u->service); - } + if (u->slice) + hashmap_remove_value(u->manager->user_units, u->slice, u); - free(u->slice_job); - free(u->service_job); + hashmap_remove_value(u->manager->users, UID_TO_PTR(u->uid), u); - free(u->runtime_path); + u->slice_job = mfree(u->slice_job); + u->service_job = mfree(u->service_job); - hashmap_remove(u->manager->users, UID_TO_PTR(u->uid)); + u->service = mfree(u->service); + u->slice = mfree(u->slice); + u->runtime_path = mfree(u->runtime_path); + u->state_file = mfree(u->state_file); + u->name = mfree(u->name); - free(u->name); - free(u->state_file); - free(u); + return mfree(u); } static int user_save_internal(User *u) { @@ -139,16 +159,13 @@ static int user_save_internal(User *u) { u->name, user_state_to_string(user_get_state(u))); + /* LEGACY: no-one reads RUNTIME= anymore, drop it at some point */ if (u->runtime_path) fprintf(f, "RUNTIME=%s\n", u->runtime_path); - if (u->service) - fprintf(f, "SERVICE=%s\n", u->service); if (u->service_job) fprintf(f, "SERVICE_JOB=%s\n", u->service_job); - if (u->slice) - fprintf(f, "SLICE=%s\n", u->slice); if (u->slice_job) fprintf(f, "SLICE_JOB=%s\n", u->slice_job); @@ -286,10 +303,7 @@ int user_load(User *u) { assert(u); r = parse_env_file(u->state_file, NEWLINE, - "RUNTIME", &u->runtime_path, - "SERVICE", &u->service, "SERVICE_JOB", &u->service_job, - "SLICE", &u->slice, "SLICE_JOB", &u->slice_job, "DISPLAY", &display, "REALTIME", &realtime, @@ -325,7 +339,6 @@ int user_load(User *u) { } static int user_mkdir_runtime_path(User *u) { - char *p; int r; assert(u); @@ -334,16 +347,10 @@ static int user_mkdir_runtime_path(User *u) { if (r < 0) return log_error_errno(r, "Failed to create /run/user: %m"); - if (!u->runtime_path) { - if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0) - return log_oom(); - } else - p = u->runtime_path; - - if (path_is_mount_point(p, 0) <= 0) { + if (path_is_mount_point(u->runtime_path, 0) <= 0) { _cleanup_free_ char *t = NULL; - (void) mkdir_label(p, 0700); + (void) mkdir_label(u->runtime_path, 0700); if (mac_smack_use()) r = asprintf(&t, "mode=0700,smackfsroot=*,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size); @@ -354,10 +361,10 @@ static int user_mkdir_runtime_path(User *u) { goto fail; } - r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t); + r = mount("tmpfs", u->runtime_path, "tmpfs", MS_NODEV|MS_NOSUID, t); if (r < 0) { if (errno != EPERM) { - r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", p); + r = log_error_errno(errno, "Failed to mount per-user tmpfs directory %s: %m", u->runtime_path); goto fail; } @@ -365,62 +372,54 @@ static int user_mkdir_runtime_path(User *u) { * CAP_SYS_ADMIN-less container? In this case, * just use a normal directory. */ - r = chmod_and_chown(p, 0700, u->uid, u->gid); + r = chmod_and_chown(u->runtime_path, 0700, u->uid, u->gid); if (r < 0) { log_error_errno(r, "Failed to change runtime directory ownership and mode: %m"); goto fail; } } - r = label_fix(p, false, false); + r = label_fix(u->runtime_path, false, false); if (r < 0) - log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", p); + log_warning_errno(r, "Failed to fix label of '%s', ignoring: %m", u->runtime_path); } - u->runtime_path = p; return 0; fail: - if (p) { - /* Try to clean up, but ignore errors */ - (void) rmdir(p); - free(p); - } - - u->runtime_path = NULL; + /* Try to clean up, but ignore errors */ + (void) rmdir(u->runtime_path); return r; } static int user_start_slice(User *u) { + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + const char *description; char *job; int r; assert(u); - if (!u->slice) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice; - sprintf(lu, UID_FMT, u->uid); - - r = slice_build_subslice(SPECIAL_USER_SLICE, lu, &slice); - if (r < 0) - return r; - - r = manager_start_unit(u->manager, slice, &error, &job); - if (r < 0) { - log_error("Failed to start user slice: %s", bus_error_message(&error, r)); - free(slice); - } else { - u->slice = slice; - - free(u->slice_job); - u->slice_job = job; - } + u->slice_job = mfree(u->slice_job); + description = strjoina("User Slice of ", u->name); + + r = manager_start_slice( + u->manager, + u->slice, + description, + "systemd-logind.service", + "systemd-user-sessions.service", + u->manager->user_tasks_max, + &error, + &job); + if (r < 0) { + /* we don't fail due to this, let's try to continue */ + if (!sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS)) + log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", u->slice, bus_error_message(&error, r), error.name); + } else { + u->slice_job = job; } - if (u->slice) - hashmap_put(u->manager->user_units, u->slice, u); - return 0; } @@ -431,29 +430,20 @@ static int user_start_service(User *u) { assert(u); - if (!u->service) { - char lu[DECIMAL_STR_MAX(uid_t) + 1], *service; - sprintf(lu, UID_FMT, u->uid); - - r = unit_name_build("user", lu, ".service", &service); - if (r < 0) - return log_error_errno(r, "Failed to build service name: %m"); - - r = manager_start_unit(u->manager, service, &error, &job); - if (r < 0) { - log_error("Failed to start user service: %s", bus_error_message(&error, r)); - free(service); - } else { - u->service = service; + u->service_job = mfree(u->service_job); - free(u->service_job); - u->service_job = job; - } + r = manager_start_unit( + u->manager, + u->service, + &error, + &job); + if (r < 0) { + /* we don't fail due to this, let's try to continue */ + log_error_errno(r, "Failed to start user service, ignoring: %s", bus_error_message(&error, r)); + } else { + u->service_job = job; } - if (u->service) - hashmap_put(u->manager->user_units, u->service, u); - return 0; } @@ -462,15 +452,32 @@ int user_start(User *u) { assert(u); - if (u->started) + if (u->started && !u->stopping) return 0; - log_debug("New user %s logged in.", u->name); - - /* Make XDG_RUNTIME_DIR */ - r = user_mkdir_runtime_path(u); - if (r < 0) - return r; + /* + * If u->stopping is set, the user is marked for removal and the slice + * and service stop-jobs are queued. We have to clear that flag before + * queing the start-jobs again. If they succeed, the user object can be + * re-used just fine (pid1 takes care of job-ordering and proper + * restart), but if they fail, we want to force another user_stop() so + * possibly pending units are stopped. + * Note that we don't clear u->started, as we have no clue what state + * the user is in on failure here. Hence, we pretend the user is + * running so it will be properly taken down by GC. However, we clearly + * return an error from user_start() in that case, so no further + * reference to the user is taken. + */ + u->stopping = false; + + if (!u->started) { + log_debug("New user %s logged in.", u->name); + + /* Make XDG_RUNTIME_DIR */ + r = user_mkdir_runtime_path(u); + if (r < 0) + return r; + } /* Create cgroup */ r = user_start_slice(u); @@ -488,16 +495,16 @@ int user_start(User *u) { if (r < 0) return r; - if (!dual_timestamp_is_set(&u->timestamp)) - dual_timestamp_get(&u->timestamp); - - u->started = true; + if (!u->started) { + if (!dual_timestamp_is_set(&u->timestamp)) + dual_timestamp_get(&u->timestamp); + user_send_signal(u, true); + u->started = true; + } /* Save new user data */ user_save(u); - user_send_signal(u, true); - return 0; } @@ -508,9 +515,6 @@ static int user_stop_slice(User *u) { assert(u); - if (!u->slice) - return 0; - r = manager_stop_unit(u->manager, u->slice, &error, &job); if (r < 0) { log_error("Failed to stop user slice: %s", bus_error_message(&error, r)); @@ -530,9 +534,6 @@ static int user_stop_service(User *u) { assert(u); - if (!u->service) - return 0; - r = manager_stop_unit(u->manager, u->service, &error, &job); if (r < 0) { log_error("Failed to stop user service: %s", bus_error_message(&error, r)); @@ -550,9 +551,6 @@ static int user_remove_runtime_path(User *u) { assert(u); - if (!u->runtime_path) - return 0; - r = rm_rf(u->runtime_path, 0); if (r < 0) log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path); @@ -568,8 +566,6 @@ static int user_remove_runtime_path(User *u) { if (r < 0) log_error_errno(r, "Failed to remove runtime directory %s: %m", u->runtime_path); - u->runtime_path = mfree(u->runtime_path); - return r; } @@ -761,9 +757,6 @@ UserState user_get_state(User *u) { int user_kill(User *u, int signo) { assert(u); - if (!u->slice) - return -ESRCH; - return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL); } diff --git a/src/login/logind-user.h b/src/login/logind-user.h index 722247806b..de99cf47b4 100644 --- a/src/login/logind-user.h +++ b/src/login/logind-user.h @@ -39,16 +39,13 @@ typedef enum UserState { struct User { Manager *manager; - uid_t uid; gid_t gid; char *name; - char *state_file; char *runtime_path; - - char *service; char *slice; + char *service; char *service_job; char *slice_job; @@ -65,8 +62,11 @@ struct User { LIST_FIELDS(User, gc_queue); }; -User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name); -void user_free(User *u); +int user_new(User **out, Manager *m, uid_t uid, gid_t gid, const char *name); +User *user_free(User *u); + +DEFINE_TRIVIAL_CLEANUP_FUNC(User *, user_free); + bool user_check_gc(User *u, bool drop_not_started); void user_add_to_gc_queue(User *u); int user_start(User *u); diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 3e7a935a34..3bd61a81fd 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -20,9 +20,9 @@ ***/ #include <errno.h> +#include <pwd.h> #include <string.h> #include <unistd.h> -#include <pwd.h> #include "sd-messages.h" diff --git a/src/login/logind.c b/src/login/logind.c index be6bbe5b5c..7b41174c64 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -70,6 +70,7 @@ static Manager *manager_new(void) { m->idle_action_not_before_usec = now(CLOCK_MONOTONIC); m->runtime_dir_size = PAGE_ALIGN((size_t) (physical_memory() / 10)); /* 10% */ + m->user_tasks_max = UINT64_C(4096); m->devices = hashmap_new(&string_hash_ops); m->seats = hashmap_new(&string_hash_ops); diff --git a/src/login/logind.conf b/src/login/logind.conf index 6df6f04c77..81f6695434 100644 --- a/src/login/logind.conf +++ b/src/login/logind.conf @@ -32,3 +32,4 @@ #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=yes +#UserTasksMax=4096 diff --git a/src/login/logind.h b/src/login/logind.h index 44e05d8b01..f34544e64c 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -134,6 +134,7 @@ struct Manager { sd_event_source *lid_switch_ignore_event_source; size_t runtime_dir_size; + uint64_t user_tasks_max; }; int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device); @@ -171,7 +172,8 @@ int bus_manager_shutdown_or_sleep_now_or_later(Manager *m, const char *unit_name int manager_send_changed(Manager *manager, const char *property, ...) _sentinel_; -int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, sd_bus_error *error, char **job); +int manager_start_slice(Manager *manager, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job); +int manager_start_scope(Manager *manager, const char *scope, pid_t pid, const char *slice, const char *description, const char *after, const char *after2, uint64_t tasks_max, sd_bus_error *error, char **job); int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job); int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error); diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 0d61f528db..ed4f7c726f 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -267,29 +267,21 @@ _public_ PAM_EXTERN int pam_sm_open_session( pam_get_item(handle, PAM_SERVICE, (const void**) &service); if (streq_ptr(service, "systemd-user")) { - _cleanup_free_ char *p = NULL, *rt = NULL; + _cleanup_free_ char *rt = NULL; - if (asprintf(&p, "/run/systemd/users/"UID_FMT, pw->pw_uid) < 0) + if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0) return PAM_BUF_ERR; - r = parse_env_file(p, NEWLINE, - "RUNTIME", &rt, - NULL); - if (r < 0 && r != -ENOENT) - return PAM_SESSION_ERR; - - if (rt) { - r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0); - if (r != PAM_SUCCESS) { - pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); - return r; - } - - r = export_legacy_dbus_address(handle, pw->pw_uid, rt); - if (r != PAM_SUCCESS) - return r; + r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0); + if (r != PAM_SUCCESS) { + pam_syslog(handle, LOG_ERR, "Failed to set runtime dir."); + return r; } + r = export_legacy_dbus_address(handle, pw->pw_uid, rt); + if (r != PAM_SUCCESS) + return r; + return PAM_SUCCESS; } @@ -501,7 +493,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( return PAM_SESSION_ERR; } - r = pam_set_data(handle, "systemd.session-fd", INT_TO_PTR(session_fd+1), NULL); + r = pam_set_data(handle, "systemd.session-fd", FD_TO_PTR(session_fd), NULL); if (r != PAM_SUCCESS) { pam_syslog(handle, LOG_ERR, "Failed to install session fd."); safe_close(session_fd); diff --git a/src/login/test-login-shared.c b/src/login/test-login-shared.c index 4c4275d124..ac327f71fb 100644 --- a/src/login/test-login-shared.c +++ b/src/login/test-login-shared.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "macro.h" #include "login-util.h" +#include "macro.h" static void test_session_id_valid(void) { assert_se(session_id_valid("c1")); diff --git a/src/login/test-login-tables.c b/src/login/test-login-tables.c index a4196bf14b..4fbc893a9a 100644 --- a/src/login/test-login-tables.c +++ b/src/login/test-login-tables.c @@ -19,7 +19,6 @@ #include "logind-action.h" #include "logind-session.h" - #include "test-tables.h" int main(int argc, char **argv) { diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index f1165ea09c..d805bcfdca 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -26,8 +26,8 @@ #include "log.h" #include "machine-id-setup.h" -#include "util.h" #include "path-util.h" +#include "util.h" static char *arg_root = NULL; static bool arg_commit = false; diff --git a/src/machine/machine.c b/src/machine/machine.c index 196bc4b8f4..6b1fae2769 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -29,6 +29,7 @@ #include "bus-error.h" #include "bus-util.h" #include "escape.h" +#include "extract-word.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" @@ -37,12 +38,12 @@ #include "machine.h" #include "mkdir.h" #include "parse-util.h" +#include "process-util.h" #include "special.h" #include "string-table.h" #include "terminal-util.h" #include "unit-name.h" #include "util.h" -#include "extract-word.h" Machine* machine_new(Manager *manager, MachineClass class, const char *name) { Machine *m; @@ -105,7 +106,7 @@ void machine_free(Machine *m) { m->manager->host_machine = NULL; if (m->leader > 0) - (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m); + (void) hashmap_remove_value(m->manager->machine_leaders, PID_TO_PTR(m->leader), m); sd_bus_message_unref(m->create_message); @@ -401,7 +402,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) { if (m->started) return 0; - r = hashmap_put(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m); + r = hashmap_put(m->manager->machine_leaders, PID_TO_PTR(m->leader), m); if (r < 0) return r; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 7827f063c1..961767c4a9 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -199,6 +199,9 @@ static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd if (r < 0) return r; + if (pid < 0) + return -EINVAL; + if (pid == 0) { _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; @@ -1505,7 +1508,7 @@ int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) { assert(pid >= 1); assert(machine); - mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid)); + mm = hashmap_get(m->machine_leaders, PID_TO_PTR(pid)); if (!mm) { _cleanup_free_ char *unit = NULL; diff --git a/src/machine/machined.h b/src/machine/machined.h index dac7a29ed1..bc5d4abb80 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -31,9 +31,9 @@ typedef struct Manager Manager; -#include "machine.h" -#include "machine-dbus.h" #include "image-dbus.h" +#include "machine-dbus.h" +#include "machine.h" struct Manager { sd_event *event; diff --git a/src/machine/test-machine-tables.c b/src/machine/test-machine-tables.c index 4aae426050..f851a4d37d 100644 --- a/src/machine/test-machine-tables.c +++ b/src/machine/test-machine-tables.c @@ -18,7 +18,6 @@ ***/ #include "machine.h" - #include "test-tables.h" int main(int argc, char **argv) { diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 446b048ef1..6fcb3050c7 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -36,7 +36,6 @@ #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" diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h index e6207ccce6..7f5bdf1d2f 100644 --- a/src/network/networkd-address-pool.h +++ b/src/network/networkd-address-pool.h @@ -23,6 +23,7 @@ typedef struct AddressPool AddressPool; +#include "in-addr-util.h" #include "networkd.h" struct AddressPool { diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index c0562e5788..1ce1f4d8d6 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -347,9 +347,9 @@ int address_update(Address *address, unsigned char flags, unsigned char scope, s link_check_ready(address->link); if (address->family == AF_INET6 && - in_addr_is_link_local(AF_INET6, &address->in_addr) && - !address->link->ipv6ll_address) { - r = link_ipv6ll_gained(address->link); + in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && + in_addr_is_null(AF_INET6, (const union in_addr_union*) &address->link->ipv6ll_address) > 0) { + r = link_ipv6ll_gained(address->link, &address->in_addr.in6); if (r < 0) return r; } diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 4049a23bdc..accd0a027d 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -28,9 +28,9 @@ typedef struct Address Address; -#include "networkd.h" -#include "networkd-network.h" #include "networkd-link.h" +#include "networkd-network.h" +#include "networkd.h" #define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index b9c60a3c77..48e3d84055 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -255,6 +255,7 @@ static int dhcp_lease_lost(Link *link) { } link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease); + link_dirty(link); link->dhcp4_configured = false; return 0; @@ -331,6 +332,7 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) { sd_dhcp_lease_unref(link->dhcp_lease); link->dhcp4_configured = false; link->dhcp_lease = sd_dhcp_lease_ref(lease); + link_dirty(link); r = sd_dhcp_lease_get_address(lease, &address); if (r < 0) @@ -408,6 +410,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { NULL); link->dhcp_lease = sd_dhcp_lease_ref(lease); + link_dirty(link); if (link->network->dhcp_mtu) { uint16_t mtu; diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index d407b31b78..e67e51f7ef 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -211,6 +211,9 @@ int dhcp6_configure(Link *link) { assert(link); + if (link->dhcp6_client) + return 0; + r = sd_dhcp6_client_new(&client); if (r < 0) return r; @@ -221,7 +224,7 @@ int dhcp6_configure(Link *link) { r = sd_dhcp6_client_set_information_request(client, true); if (r < 0) - return r; + goto error; r = sd_dhcp6_client_set_mac(client, (const uint8_t *) &link->mac, diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index c9222b8cb8..6e5480ee22 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <net/if.h> #include <net/ethernet.h> +#include <net/if.h> #include "alloc-util.h" #include "conf-parser.h" diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h index f0efb902d0..c8e3f2ce56 100644 --- a/src/network/networkd-fdb.h +++ b/src/network/networkd-fdb.h @@ -23,8 +23,8 @@ typedef struct FdbEntry FdbEntry; -#include "networkd.h" #include "networkd-network.h" +#include "networkd.h" struct FdbEntry { Network *network; diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index ed0d861e7a..f4aac4bb93 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -22,8 +22,8 @@ #include <netinet/ether.h> #include <linux/if.h> -#include "networkd-link.h" #include "network-internal.h" +#include "networkd-link.h" static int ipv4ll_address_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; @@ -201,7 +201,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){ } int ipv4ll_configure(Link *link) { - uint8_t seed[8]; + uint64_t seed; int r; assert(link); @@ -215,11 +215,11 @@ int ipv4ll_configure(Link *link) { } if (link->udev_device) { - r = net_get_unique_predictable_data(link->udev_device, seed); + r = net_get_unique_predictable_data(link->udev_device, &seed); if (r >= 0) { assert_cc(sizeof(unsigned) <= 8); - r = sd_ipv4ll_set_address_seed(link->ipv4ll, *(unsigned *)seed); + r = sd_ipv4ll_set_address_seed(link->ipv4ll, (unsigned)seed); if (r < 0) return r; } diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 11b35d6cf8..d09a3c2d07 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -19,13 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "bus-util.h" -#include "strv.h" - #include "alloc-util.h" +#include "bus-util.h" #include "networkd-link.h" #include "networkd.h" #include "parse-util.h" +#include "strv.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); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a415035887..a9d91b07f6 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -615,7 +615,7 @@ void link_check_ready(Link *link) { return; if (link_ipv6ll_enabled(link)) - if (!link->ipv6ll_address) + if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0) return; if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) && @@ -1260,11 +1260,16 @@ static int link_acquire_ipv6_conf(Link *link) { if (link_dhcp6_enabled(link)) { assert(link->dhcp6_client); + assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); log_link_debug(link, "Acquiring DHCPv6 lease"); + r = sd_dhcp6_client_set_local_address(link->dhcp6_client, &link->ipv6ll_address); + if (r < 0 && r != -EBUSY) + return log_link_warning_errno(link, r, "Could not set IPv6LL address in DHCP client: %m"); + r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0) + if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m"); } @@ -1274,7 +1279,7 @@ static int link_acquire_ipv6_conf(Link *link) { log_link_debug(link, "Discovering IPv6 routers"); r = sd_ndisc_router_discovery_start(link->ndisc_router_discovery); - if (r < 0) + if (r < 0 && r != -EBUSY) return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m"); } @@ -2035,9 +2040,13 @@ static int link_configure(Link *link) { assert(link->network); assert(link->state == LINK_STATE_PENDING); - r = link_drop_foreign_config(link); - if (r < 0) - return r; + /* Drop foreign config, but ignore loopback device. + * We do not want to remove loopback address. */ + if (!(link->flags & IFF_LOOPBACK)) { + r = link_drop_foreign_config(link); + if (r < 0) + return r; + } r = link_set_bridge_fdb(link); if (r < 0) @@ -2089,7 +2098,8 @@ static int link_configure(Link *link) { return r; } - if (link_dhcp6_enabled(link)) { + if (link_dhcp6_enabled(link) || + link_ipv6_accept_ra_enabled(link)) { r = dhcp6_configure(link); if (r < 0) return r; @@ -2121,7 +2131,7 @@ static int link_configure(Link *link) { if (r < 0) return r; - if (link->ipv6ll_address) { + if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) { r = link_acquire_ipv6_conf(link); if (r < 0) return r; @@ -2290,7 +2300,8 @@ network_file_fail: if (r < 0) { log_link_debug_errno(link, r, "Failed to extract next address string: %m"); continue; - } if (r == 0) + } + if (r == 0) break; prefixlen_str = strchr(address_str, '/'); @@ -2320,6 +2331,8 @@ network_file_fail: } if (routes) { + p = routes; + for (;;) { Route *route; _cleanup_free_ char *route_str = NULL; @@ -2334,7 +2347,8 @@ network_file_fail: if (r < 0) { log_link_debug_errno(link, r, "Failed to extract next route string: %m"); continue; - } if (r == 0) + } + if (r == 0) break; prefixlen_str = strchr(route_str, '/'); @@ -2472,14 +2486,14 @@ failed: return r; } -int link_ipv6ll_gained(Link *link) { +int link_ipv6ll_gained(Link *link, const struct in6_addr *address) { int r; assert(link); log_link_info(link, "Gained IPv6LL"); - link->ipv6ll_address = true; + link->ipv6ll_address = *address; link_check_ready(link); if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index b564bcbca0..3964a12f37 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -56,9 +56,9 @@ typedef enum LinkOperationalState { _LINK_OPERSTATE_INVALID = -1 } LinkOperationalState; -#include "networkd.h" -#include "networkd-network.h" #include "networkd-address.h" +#include "networkd-network.h" +#include "networkd.h" struct Link { Manager *manager; @@ -69,6 +69,7 @@ struct Link { char *ifname; char *state_file; struct ether_addr mac; + struct in6_addr ipv6ll_address; uint32_t mtu; struct udev_device *udev_device; @@ -101,7 +102,6 @@ struct Link { sd_ipv4ll *ipv4ll; bool ipv4ll_address:1; bool ipv4ll_route:1; - bool ipv6ll_address:1; bool static_configured; @@ -144,7 +144,7 @@ int link_save(Link *link); int link_carrier_reset(Link *link); bool link_has_carrier(Link *link); -int link_ipv6ll_gained(Link *link); +int link_ipv6ll_gained(Link *link, const struct in6_addr *address); int link_set_mtu(Link *link, uint32_t mtu); int link_set_hostname(Link *link, const char *hostname); diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 126f9c0fe9..ce9e513ceb 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -75,7 +75,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr address->family = AF_INET6; address->in_addr.in6 = *prefix; if (in_addr_is_null(AF_INET6, (const union in_addr_union *) &link->network->ipv6_token) == 0) - memcpy(&address->in_addr.in6 + 8, &link->network->ipv6_token + 8, 8); + memcpy(((char *)&address->in_addr.in6) + 8, ((char *)&link->network->ipv6_token) + 8, 8); else { /* see RFC4291 section 2.5.1 */ address->in_addr.in6.__in6_u.__u6_addr8[8] = link->mac.ether_addr_octet[0]; @@ -159,7 +159,7 @@ static void ndisc_router_handler(sd_ndisc *nd, uint8_t flags, const struct in6_a dhcp6_request_address(link); r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0 && r != -EALREADY) + if (r < 0 && r != -EBUSY) log_link_warning_errno(link, r, "Starting DHCPv6 client on NDisc request failed: %m"); } @@ -205,8 +205,12 @@ static void ndisc_handler(sd_ndisc *nd, int event, void *userdata) { dhcp6_request_address(link); r = sd_dhcp6_client_start(link->dhcp6_client); - if (r < 0 && r != -EALREADY) + if (r < 0 && r != -EBUSY) log_link_warning_errno(link, r, "Starting DHCPv6 client after NDisc timeout failed: %m"); + + link->ndisc_configured = true; + link_check_ready(link); + break; case SD_NDISC_EVENT_STOP: break; diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index 4e4755f86f..50b9021d09 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -29,8 +29,8 @@ #include "conf-parser.h" #include "missing.h" #include "networkd-netdev-bond.h" -#include "string-util.h" #include "string-table.h" +#include "string-util.h" /* * Number of seconds between instances where the bonding diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index 57c58d83b4..a991bdb5fb 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -22,9 +22,9 @@ #include <net/if.h> -#include "networkd-netdev-bridge.h" #include "missing.h" #include "netlink-util.h" +#include "networkd-netdev-bridge.h" /* callback for brige netdev's parameter set */ static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index 851e83537e..3d504a8564 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -19,8 +19,8 @@ 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/if_tun.h> #include "alloc-util.h" diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c index bee1a16726..773a1ee6d1 100644 --- a/src/network/networkd-netdev-veth.c +++ b/src/network/networkd-netdev-veth.c @@ -23,6 +23,7 @@ #include <linux/veth.h> #include "sd-netlink.h" + #include "networkd-netdev-veth.h" static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index 755ad2f934..7932b93335 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -22,10 +22,11 @@ #include <net/if.h> #include "sd-netlink.h" -#include "networkd-netdev-vxlan.h" -#include "networkd-link.h" + #include "conf-parser.h" #include "missing.h" +#include "networkd-link.h" +#include "networkd-netdev-vxlan.h" static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { VxLan *v; diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index d21f355f5d..16977ea6a9 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -23,9 +23,8 @@ typedef struct VxLan VxLan; -#include "networkd-netdev.h" - #include "in-addr-util.h" +#include "networkd-netdev.h" #define VXLAN_VID_MAX (1u << 24) - 1 diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index dd0b400c6a..a86a6383da 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -411,7 +411,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) { int netdev_get_mac(const char *ifname, struct ether_addr **ret) { _cleanup_free_ struct ether_addr *mac = NULL; - uint8_t result[8]; + uint64_t result; size_t l, sz; uint8_t *v; int r; @@ -438,10 +438,10 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) { /* Let's hash the host machine ID plus the container name. We * use a fixed, but originally randomly created hash key here. */ - siphash24(result, v, sz, HASH_KEY.bytes); + result = siphash24(v, sz, HASH_KEY.bytes); assert_cc(ETH_ALEN <= sizeof(result)); - memcpy(mac->ether_addr_octet, result, ETH_ALEN); + memcpy(mac->ether_addr_octet, &result, ETH_ALEN); /* see eth_random_addr in the kernel */ mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */ diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 3b9ab27b67..3ab39efd57 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -26,8 +26,8 @@ typedef struct NetDev NetDev; typedef struct NetDevVTable NetDevVTable; -#include "networkd.h" #include "networkd-link.h" +#include "networkd.h" typedef struct netdev_join_callback netdev_join_callback; @@ -103,16 +103,16 @@ struct NetDev { LIST_HEAD(netdev_join_callback, callbacks); }; -#include "networkd-netdev-bridge.h" #include "networkd-netdev-bond.h" -#include "networkd-netdev-vlan.h" -#include "networkd-netdev-macvlan.h" +#include "networkd-netdev-bridge.h" +#include "networkd-netdev-dummy.h" #include "networkd-netdev-ipvlan.h" -#include "networkd-netdev-vxlan.h" -#include "networkd-netdev-veth.h" +#include "networkd-netdev-macvlan.h" #include "networkd-netdev-tunnel.h" -#include "networkd-netdev-dummy.h" #include "networkd-netdev-tuntap.h" +#include "networkd-netdev-veth.h" +#include "networkd-netdev-vlan.h" +#include "networkd-netdev-vxlan.h" struct NetDevVTable { /* How much memory does an object of this unit type need */ diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index a27c67eea5..cb3a50d9ba 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -25,12 +25,12 @@ typedef struct Network Network; -#include "networkd.h" -#include "networkd-netdev.h" #include "networkd-address.h" -#include "networkd-route.h" #include "networkd-fdb.h" +#include "networkd-netdev.h" +#include "networkd-route.h" #include "networkd-util.h" +#include "networkd.h" #define DHCP_ROUTE_METRIC 1024 #define IPV4LL_ROUTE_METRIC 2048 diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index b276756674..37c12907d7 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -23,8 +23,8 @@ typedef struct Route Route; -#include "networkd.h" #include "networkd-network.h" +#include "networkd.h" struct Route { Network *network; diff --git a/src/network/networkd.h b/src/network/networkd.h index 97665fac7a..8086e528bf 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -23,19 +23,19 @@ #include <arpa/inet.h> +#include "sd-bus.h" #include "sd-event.h" #include "sd-netlink.h" -#include "sd-bus.h" -#include "udev.h" #include "hashmap.h" #include "list.h" +#include "udev.h" typedef struct Manager Manager; -#include "networkd-network.h" #include "networkd-address-pool.h" #include "networkd-link.h" +#include "networkd-network.h" #include "networkd-util.h" struct Manager { diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c index 438214015d..ecbbe6c3c9 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -1,11 +1,10 @@ -#include "networkd.h" -#include "networkd-netdev-bond.h" -#include "networkd-netdev-macvlan.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" -#include "netlink-internal.h" #include "ethtool-util.h" - +#include "netlink-internal.h" +#include "networkd-netdev-bond.h" +#include "networkd-netdev-macvlan.h" +#include "networkd.h" #include "test-tables.h" int main(int argc, char **argv) { diff --git a/src/network/test-network.c b/src/network/test-network.c index dbed3795e3..a1a77b6867 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -20,9 +20,9 @@ ***/ #include "alloc-util.h" -#include "networkd.h" -#include "network-internal.h" #include "dhcp-lease-internal.h" +#include "network-internal.h" +#include "networkd.h" static void test_deserialize_in_addr(void) { _cleanup_free_ struct in_addr *addresses = NULL; diff --git a/src/nspawn/nspawn-cgroup.h b/src/nspawn/nspawn-cgroup.h index 985fdfaad5..4e8db63750 100644 --- a/src/nspawn/nspawn-cgroup.h +++ b/src/nspawn/nspawn-cgroup.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <stdbool.h> +#include <sys/types.h> int chown_cgroup(pid_t pid, uid_t uid_shift); int sync_cgroup(pid_t pid, bool unified_requested); diff --git a/src/nspawn/nspawn-expose-ports.h b/src/nspawn/nspawn-expose-ports.h index 39cec28695..cb7340bad7 100644 --- a/src/nspawn/nspawn-expose-ports.h +++ b/src/nspawn/nspawn-expose-ports.h @@ -25,8 +25,9 @@ #include "sd-event.h" #include "sd-netlink.h" -#include "list.h" + #include "in-addr-util.h" +#include "list.h" typedef struct ExposePort { int protocol; diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index c71552879d..8f74c41c71 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -29,11 +29,11 @@ #include "alloc-util.h" #include "ether-addr-util.h" #include "netlink-util.h" +#include "nspawn-network.h" #include "siphash24.h" #include "string-util.h" #include "udev-util.h" #include "util.h" -#include "nspawn-network.h" #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1) #define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2) @@ -47,7 +47,7 @@ static int generate_mac( sd_id128_t hash_key, uint64_t idx) { - uint8_t result[8]; + uint64_t result; size_t l, sz; uint8_t *v, *i; int r; @@ -74,10 +74,10 @@ static int generate_mac( /* Let's hash the host machine ID plus the container name. We * use a fixed, but originally randomly created hash key here. */ - siphash24(result, v, sz, hash_key.bytes); + result = htole64(siphash24(v, sz, hash_key.bytes)); assert_cc(ETH_ALEN <= sizeof(result)); - memcpy(mac->ether_addr_octet, result, ETH_ALEN); + memcpy(mac->ether_addr_octet, &result, ETH_ALEN); /* see eth_random_addr in the kernel */ mac->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */ diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index b86effef47..c91fc79c42 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -22,9 +22,8 @@ ***/ #include <net/if.h> - -#include <sys/types.h> #include <stdbool.h> +#include <sys/types.h> int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge); int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs); diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index 374f958c20..50871464c5 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -105,6 +105,10 @@ int register_machine( return bus_log_create_error(r); } + r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", 8192); + if (r < 0) + return bus_log_create_error(r); + r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict"); if (r < 0) return bus_log_create_error(r); diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index dde0d8bd45..10230a5b83 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -24,9 +24,8 @@ #include <stdio.h> #include "macro.h" - -#include "nspawn-mount.h" #include "nspawn-expose-ports.h" +#include "nspawn-mount.h" typedef enum SettingsMask { SETTING_BOOT = 1 << 0, diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index d2ce731c72..f6a2c0386e 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -2283,7 +2283,7 @@ static int wait_for_container(pid_t pid, ContainerStatus *container) { static int on_orderly_shutdown(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { pid_t pid; - pid = PTR_TO_UINT32(userdata); + pid = PTR_TO_PID(userdata); if (pid > 0) { if (kill(pid, arg_kill_signal) >= 0) { log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination."); @@ -3510,8 +3510,8 @@ int main(int argc, char *argv[]) { if (arg_kill_signal > 0) { /* Try to kill the init system on SIGINT or SIGTERM */ - sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, UINT32_TO_PTR(pid)); - sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, UINT32_TO_PTR(pid)); + sd_event_add_signal(event, NULL, SIGINT, on_orderly_shutdown, PID_TO_PTR(pid)); + sd_event_add_signal(event, NULL, SIGTERM, on_orderly_shutdown, PID_TO_PTR(pid)); } else { /* Immediately exit */ sd_event_add_signal(event, NULL, SIGINT, NULL, NULL); diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 969fa9619e..c98a959b3b 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -416,6 +416,9 @@ enum nss_status _nss_mymachines_getpwnam_r( if (!e || e == p) goto not_found; + if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */ + goto not_found; + r = parse_uid(e + 1, &uid); if (r < 0) goto not_found; @@ -573,6 +576,9 @@ enum nss_status _nss_mymachines_getgrnam_r( if (!e || e == p) goto not_found; + if (e - p > HOST_NAME_MAX - 1) /* -1 for the last dash */ + goto not_found; + r = parse_gid(e + 1, &gid); if (r < 0) goto not_found; diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index dc2911e4e8..883d96608d 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -25,11 +25,11 @@ #include <sys/prctl.h> #include <unistd.h> +#include "proc-cmdline.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/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index 57f99c9ef0..9fc56284d2 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -19,19 +19,22 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> #include <errno.h> +#include <mntent.h> #include <string.h> +#include <sys/prctl.h> #include <sys/stat.h> #include <sys/wait.h> -#include <mntent.h> +#include <unistd.h> #include "exit-status.h" #include "log.h" #include "mount-setup.h" #include "mount-util.h" #include "path-util.h" +#include "process-util.h" #include "signal-util.h" +#include "strv.h" #include "util.h" /* Goes through /etc/fstab and remounts all API file systems, applying @@ -39,10 +42,10 @@ * respected */ int main(int argc, char *argv[]) { - int ret = EXIT_FAILURE; + _cleanup_hashmap_free_free_ Hashmap *pids = NULL; _cleanup_endmntent_ FILE *f = NULL; struct mntent* me; - Hashmap *pids = NULL; + int r; if (argc > 1) { log_error("This program takes no argument."); @@ -57,21 +60,21 @@ int main(int argc, char *argv[]) { f = setmntent("/etc/fstab", "r"); if (!f) { - if (errno == ENOENT) - return EXIT_SUCCESS; + if (errno == ENOENT) { + r = 0; + goto finish; + } - log_error_errno(errno, "Failed to open /etc/fstab: %m"); - return EXIT_FAILURE; + r = log_error_errno(errno, "Failed to open /etc/fstab: %m"); + goto finish; } pids = hashmap_new(NULL); if (!pids) { - log_error("Failed to allocate set"); + r = log_oom(); goto finish; } - ret = EXIT_SUCCESS; - while ((me = getmntent(f))) { pid_t pid; int k; @@ -87,25 +90,18 @@ int main(int argc, char *argv[]) { pid = fork(); if (pid < 0) { - log_error_errno(errno, "Failed to fork: %m"); - ret = EXIT_FAILURE; - continue; + r = log_error_errno(errno, "Failed to fork: %m"); + goto finish; } if (pid == 0) { - const char *arguments[5]; /* Child */ (void) reset_all_signal_handlers(); (void) reset_signal_mask(); + (void) prctl(PR_SET_PDEATHSIG, SIGTERM); - arguments[0] = MOUNT_PATH; - arguments[1] = me->mnt_dir; - arguments[2] = "-o"; - arguments[3] = "remount"; - arguments[4] = NULL; - - execv(MOUNT_PATH, (char **) arguments); + execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount")); log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m"); _exit(EXIT_FAILURE); @@ -115,20 +111,19 @@ int main(int argc, char *argv[]) { s = strdup(me->mnt_dir); if (!s) { - log_oom(); - ret = EXIT_FAILURE; - continue; + r = log_oom(); + goto finish; } - - k = hashmap_put(pids, UINT_TO_PTR(pid), s); + k = hashmap_put(pids, PID_TO_PTR(pid), s); if (k < 0) { - log_error_errno(k, "Failed to add PID to set: %m"); - ret = EXIT_FAILURE; - continue; + free(s); + r = log_oom(); + goto finish; } } + r = 0; while (!hashmap_isempty(pids)) { siginfo_t si = {}; char *s; @@ -138,12 +133,11 @@ int main(int argc, char *argv[]) { if (errno == EINTR) continue; - log_error_errno(errno, "waitid() failed: %m"); - ret = EXIT_FAILURE; - break; + r = log_error_errno(errno, "waitid() failed: %m"); + goto finish; } - s = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)); + s = hashmap_remove(pids, PID_TO_PTR(si.si_pid)); if (s) { if (!is_clean_exit(si.si_code, si.si_status, NULL)) { if (si.si_code == CLD_EXITED) @@ -151,7 +145,7 @@ int main(int argc, char *argv[]) { else log_error(MOUNT_PATH " for %s terminated by signal %s.", s, signal_to_string(si.si_status)); - ret = EXIT_FAILURE; + r = -ENOEXEC; } free(s); @@ -159,9 +153,5 @@ int main(int argc, char *argv[]) { } finish: - - if (pids) - hashmap_free_free(pids); - - return ret; + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c index 432e62dd9f..f68751a2e5 100644 --- a/src/resolve-host/resolve-host.c +++ b/src/resolve-host/resolve-host.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <net/if.h> #include <getopt.h> +#include <net/if.h> #include "sd-bus.h" @@ -28,6 +28,7 @@ #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" +#include "escape.h" #include "in-addr-util.h" #include "parse-util.h" #include "resolved-def.h" @@ -41,6 +42,7 @@ static int arg_type = 0; static uint16_t arg_class = 0; static bool arg_legend = true; static uint64_t arg_flags = 0; +static bool arg_resolve_service = false; static void print_source(uint64_t flags, usec_t rtt) { char rtt_str[FORMAT_TIMESTAMP_MAX]; @@ -102,10 +104,8 @@ static int resolve_host(sd_bus *bus, const char *name) { ts = now(CLOCK_MONOTONIC); r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); - if (r < 0) { - log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); - return r; - } + if (r < 0) + return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r)); ts = now(CLOCK_MONOTONIC) - ts; @@ -114,10 +114,10 @@ static int resolve_host(sd_bus *bus, const char *name) { return bus_log_parse_error(r); while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { - const void *a; - size_t sz; _cleanup_free_ char *pretty = NULL; int ifindex, family; + const void *a; + size_t sz; assert_cc(sizeof(int) == sizeof(int32_t)); @@ -140,7 +140,7 @@ static int resolve_host(sd_bus *bus, const char *name) { if (sz != FAMILY_ADDRESS_SIZE(family)) { log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown"); - continue; + return -EINVAL; } ifname[0] = 0; @@ -437,6 +437,207 @@ static int resolve_record(sd_bus *bus, const char *name) { return 0; } +static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) { + const char *canonical_name, *canonical_type, *canonical_domain; + _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; + _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + char ifname[IF_NAMESIZE] = ""; + size_t indent, sz; + uint64_t flags; + const char *p; + unsigned c; + usec_t ts; + int r; + + assert(bus); + assert(domain); + + if (isempty(name)) + name = NULL; + if (isempty(type)) + type = NULL; + + if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname)) + return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex); + + if (name) + log_debug("Resolving service \"%s\" of type %s in %s (family %s, interface %s).", name, type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname); + else if (type) + log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname); + else + log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname); + + r = sd_bus_message_new_method_call( + bus, + &req, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResolveService"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags); + if (r < 0) + return bus_log_create_error(r); + + ts = now(CLOCK_MONOTONIC); + + r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); + if (r < 0) + return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r)); + + ts = now(CLOCK_MONOTONIC) - ts; + + r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)"); + if (r < 0) + return bus_log_parse_error(r); + + indent = + (name ? strlen(name) + 1 : 0) + + (type ? strlen(type) + 1 : 0) + + strlen(domain) + 2; + + c = 0; + while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) { + uint16_t priority, weight, port; + const char *hostname, *canonical; + + r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname); + if (r < 0) + return bus_log_parse_error(r); + + if (name) + printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " "); + if (type) + printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " "); + + printf("%*s%s %s:%u [priority=%u, weight=%u]\n", + (int) strlen(domain), c == 0 ? domain : "", + c == 0 ? ":" : " ", + hostname, port, + priority, weight); + + r = sd_bus_message_enter_container(reply, 'a', "(iiay)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) { + _cleanup_free_ char *pretty = NULL; + int ifindex, family; + const void *a; + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_read(reply, "ii", &ifindex, &family); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read_array(reply, 'y', &a, &sz); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + if (!IN_SET(family, AF_INET, AF_INET6)) { + log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown"); + continue; + } + + if (sz != FAMILY_ADDRESS_SIZE(family)) { + log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown"); + return -EINVAL; + } + + ifname[0] = 0; + if (ifindex > 0 && !if_indextoname(ifindex, ifname)) + log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); + + r = in_addr_to_string(family, a, &pretty); + if (r < 0) + return log_error_errno(r, "Failed to print address for %s: %m", name); + + printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname); + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read(reply, "s", &canonical); + if (r < 0) + return bus_log_parse_error(r); + + if (!streq(hostname, canonical)) + printf("%*s(%s)\n", (int) indent, "", canonical); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + c++; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_enter_container(reply, 'a', "ay"); + if (r < 0) + return bus_log_parse_error(r); + + c = 0; + while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) { + _cleanup_free_ char *escaped = NULL; + + escaped = cescape_length(p, sz); + if (!escaped) + return log_oom(); + + printf("%*s%s\n", (int) indent, "", escaped); + c++; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags); + if (r < 0) + return bus_log_parse_error(r); + + if (isempty(canonical_name)) + canonical_name = NULL; + if (isempty(canonical_type)) + canonical_type = NULL; + + if (!streq_ptr(name, canonical_name) || + !streq_ptr(type, canonical_type) || + !streq_ptr(domain, canonical_domain)) { + + printf("%*s(", (int) indent, ""); + + if (canonical_name) + printf("%s/", canonical_name); + if (canonical_type) + printf("%s/", canonical_type); + + printf("%s)\n", canonical_domain); + } + + print_source(flags, ts); + + return 0; +} + static void help_dns_types(void) { int i; const char *t; @@ -464,33 +665,49 @@ static void help_dns_classes(void) { } static void help(void) { - printf("%s [OPTIONS...]\n\n" - "Resolve IPv4 or IPv6 addresses.\n\n" - " -h --help Show this help\n" - " --version Show package version\n" - " -4 Resolve IPv4 addresses\n" - " -6 Resolve IPv6 addresses\n" - " -i INTERFACE Look on interface\n" - " -p --protocol=PROTOCOL Look via protocol\n" - " -t --type=TYPE Query RR with DNS type\n" - " -c --class=CLASS Query RR with DNS class\n" - " --legend[=BOOL] Do [not] print column headers\n" - , program_invocation_short_name); + printf("%s [OPTIONS...] NAME...\n" + "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n" + "Resolve domain names, IPv4 or IPv6 addresses, resource records, and services.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " -4 Resolve IPv4 addresses\n" + " -6 Resolve IPv6 addresses\n" + " -i INTERFACE Look on interface\n" + " -p --protocol=PROTOCOL Look via protocol\n" + " -t --type=TYPE Query RR with DNS type\n" + " -c --class=CLASS Query RR with DNS class\n" + " --service Resolve service (SRV)\n" + " --service-address=BOOL Do [not] resolve address for services\n" + " --service-txt=BOOL Do [not] resolve TXT records for services\n" + " --cname=BOOL Do [not] follow CNAME redirects\n" + " --search=BOOL Do [not] use search domains\n" + " --legend=BOOL Do [not] print column headers\n" + , program_invocation_short_name, program_invocation_short_name); } static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_LEGEND, + ARG_SERVICE, + ARG_CNAME, + ARG_SERVICE_ADDRESS, + ARG_SERVICE_TXT, + ARG_SEARCH, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "type", required_argument, NULL, 't' }, - { "class", required_argument, NULL, 'c' }, - { "legend", optional_argument, NULL, ARG_LEGEND }, - { "protocol", required_argument, NULL, 'p' }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "type", required_argument, NULL, 't' }, + { "class", required_argument, NULL, 'c' }, + { "legend", required_argument, NULL, ARG_LEGEND }, + { "protocol", required_argument, NULL, 'p' }, + { "cname", required_argument, NULL, ARG_CNAME }, + { "service", no_argument, NULL, ARG_SERVICE }, + { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, + { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, + { "search", required_argument, NULL, ARG_SEARCH }, {} }; @@ -563,16 +780,11 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_LEGEND: - if (optarg) { - r = parse_boolean(optarg); - if (r < 0) { - log_error("Failed to parse --legend= argument"); - return r; - } - - arg_legend = !!r; - } else - arg_legend = false; + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --legend= argument"); + + arg_legend = r; break; case 'p': @@ -591,6 +803,50 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_SERVICE: + arg_resolve_service = true; + break; + + case ARG_CNAME: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --cname= argument."); + if (r == 0) + arg_flags |= SD_RESOLVED_NO_CNAME; + else + arg_flags &= ~SD_RESOLVED_NO_CNAME; + break; + + case ARG_SERVICE_ADDRESS: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --service-address= argument."); + if (r == 0) + arg_flags |= SD_RESOLVED_NO_ADDRESS; + else + arg_flags &= ~SD_RESOLVED_NO_ADDRESS; + break; + + case ARG_SERVICE_TXT: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --service-txt= argument."); + if (r == 0) + arg_flags |= SD_RESOLVED_NO_TXT; + else + arg_flags &= ~SD_RESOLVED_NO_TXT; + break; + + case ARG_SEARCH: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --search argument."); + if (r == 0) + arg_flags |= SD_RESOLVED_NO_SEARCH; + else + arg_flags &= ~SD_RESOLVED_NO_SEARCH; + break; + case '?': return -EINVAL; @@ -599,7 +855,12 @@ static int parse_argv(int argc, char *argv[]) { } if (arg_type == 0 && arg_class != 0) { - log_error("--class= may only be used in conjunction with --type="); + log_error("--class= may only be used in conjunction with --type=."); + return -EINVAL; + } + + if (arg_type != 0 && arg_resolve_service) { + log_error("--service and --type= may not be combined."); return -EINVAL; } @@ -632,6 +893,28 @@ int main(int argc, char **argv) { goto finish; } + if (arg_resolve_service) { + + if (argc < optind + 1) { + log_error("Domain specification required."); + r = -EINVAL; + goto finish; + + } else if (argc == optind + 1) + r = resolve_service(bus, NULL, NULL, argv[optind]); + else if (argc == optind + 2) + r = resolve_service(bus, NULL, argv[optind], argv[optind+1]); + else if (argc == optind + 3) + r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]); + else { + log_error("Too many arguments"); + r = -EINVAL; + goto finish; + } + + goto finish; + } + while (argv[optind]) { int family, ifindex, k; union in_addr_union a; diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index f0a3b607d4..62bb08a2e8 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -31,15 +31,14 @@ static int reply_query_state(DnsQuery *q) { const char *name; int r; - if (q->request_hostname) - name = q->request_hostname; - else { + if (q->request_address_valid) { r = in_addr_to_string(q->request_family, &q->request_address, &ip); if (r < 0) return r; name = ip; - } + } else + name = dns_question_first_name(q->question); switch (q->state) { @@ -132,10 +131,9 @@ static int append_address(sd_bus_message *reply, DnsResourceRecord *rr, int ifin } static void bus_method_resolve_hostname_complete(DnsQuery *q) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *canonical = NULL; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned added = 0, i; + unsigned added = 0; int r; assert(q); @@ -145,6 +143,16 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { goto finish; } + r = dns_query_process_cname(q); + if (r == -ELOOP) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question)); + goto finish; + } + if (r < 0) + goto finish; + if (r > 0) /* This was a cname, and the query was restarted. */ + return; + r = sd_bus_message_new_method_return(q->request, &reply); if (r < 0) goto finish; @@ -154,92 +162,42 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { goto finish; if (q->answer) { - answer = dns_answer_ref(q->answer); + DnsResourceRecord *rr; + int ifindex; - for (i = 0; i < answer->n_rrs; i++) { - r = dns_question_matches_rr(q->question, answer->items[i].rr); + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); if (r < 0) goto finish; - if (r == 0) { - /* Hmm, if this is not an address record, - maybe it's a cname? If so, remember this */ - r = dns_question_matches_cname(q->question, answer->items[i].rr); - if (r < 0) - goto finish; - if (r > 0) - cname = dns_resource_record_ref(answer->items[i].rr); - + if (r == 0) continue; - } - r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex); + r = append_address(reply, rr, ifindex); if (r < 0) goto finish; if (!canonical) - canonical = dns_resource_record_ref(answer->items[i].rr); + canonical = dns_resource_record_ref(rr); added ++; } } - if (added == 0) { - if (!cname) { - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of requested type", q->request_hostname); - goto finish; - } - - /* This has a cname? Then update the query with the - * new cname. */ - r = dns_query_cname_redirect(q, cname); - if (r < 0) { - if (r == -ELOOP) - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop on '%s'", q->request_hostname); - else - r = sd_bus_reply_method_errno(q->request, -r, NULL); - - goto finish; - } - - /* Before we restart the query, let's see if any of - * the RRs we already got already answers our query */ - for (i = 0; i < answer->n_rrs; i++) { - r = dns_question_matches_rr(q->question, answer->items[i].rr); - if (r < 0) - goto finish; - if (r == 0) - continue; - - r = append_address(reply, answer->items[i].rr, answer->items[i].ifindex); - if (r < 0) - goto finish; - - if (!canonical) - canonical = dns_resource_record_ref(answer->items[i].rr); - - added++; - } - - /* If we didn't find anything, then let's restart the - * query, this time with the cname */ - if (added <= 0) { - r = dns_query_go(q); - if (r < 0) { - r = sd_bus_reply_method_errno(q->request, -r, NULL); - goto finish; - } - - return; - } + if (added <= 0) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question)); + goto finish; } r = sd_bus_message_close_container(reply); if (r < 0) goto finish; - /* Return the precise spelling and uppercasing reported by the server */ + /* Return the precise spelling and uppercasing and CNAME target reported by the server */ assert(canonical); - r = sd_bus_message_append(reply, "st", DNS_RESOURCE_KEY_NAME(canonical->key), SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); + r = sd_bus_message_append( + reply, "st", + DNS_RESOURCE_KEY_NAME(canonical->key), + SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); if (r < 0) goto finish; @@ -248,23 +206,23 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { finish: if (r < 0) { log_error_errno(r, "Failed to send hostname reply: %m"); - sd_bus_reply_method_errno(q->request, -r, NULL); + sd_bus_reply_method_errno(q->request, r, NULL); } dns_query_free(q); } -static int check_ifindex_flags(int ifindex, uint64_t *flags, sd_bus_error *error) { +static int check_ifindex_flags(int ifindex, uint64_t *flags, uint64_t ok, sd_bus_error *error) { assert(flags); if (ifindex < 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); - if (*flags & ~SD_RESOLVED_FLAGS_ALL) + if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); - if (*flags == 0) - *flags = SD_RESOLVED_FLAGS_DEFAULT; + if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */ + *flags |= SD_RESOLVED_PROTOCOLS_ALL; return 0; } @@ -281,6 +239,8 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, assert(message); assert(m); + assert_cc(sizeof(int) == sizeof(int32_t)); + r = sd_bus_message_read(message, "isit", &ifindex, &hostname, &family, &flags); if (r < 0) return r; @@ -288,41 +248,19 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); - r = dns_name_normalize(hostname, NULL); + r = dns_name_is_valid(hostname); if (r < 0) + return r; + if (r == 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", hostname); - r = check_ifindex_flags(ifindex, &flags, error); + r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_SEARCH, error); if (r < 0) return r; - question = dns_question_new(family == AF_UNSPEC ? 2 : 1); - if (!question) - return -ENOMEM; - - if (family != AF_INET6) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - - key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, hostname); - if (!key) - return -ENOMEM; - - r = dns_question_add(question, key); - if (r < 0) - return r; - } - - if (family != AF_INET) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; - - key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, hostname); - if (!key) - return -ENOMEM; - - r = dns_question_add(question, key); - if (r < 0) - return r; - } + r = dns_question_new_address(&question, family, hostname); + if (r < 0) + return r; r = dns_query_new(m, &q, question, ifindex, flags); if (r < 0) @@ -330,27 +268,28 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, q->request = sd_bus_message_ref(message); q->request_family = family; - q->request_hostname = hostname; q->complete = bus_method_resolve_hostname_complete; r = dns_query_bus_track(q, message); if (r < 0) - return r; + goto fail; r = dns_query_go(q); - if (r < 0) { - dns_query_free(q); - return r; - } + if (r < 0) + goto fail; return 1; + +fail: + dns_query_free(q); + return r; } static void bus_method_resolve_address_complete(DnsQuery *q) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned added = 0, i; - int r; + DnsResourceRecord *rr; + unsigned added = 0; + int ifindex, r; assert(q); @@ -359,6 +298,16 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { goto finish; } + r = dns_query_process_cname(q); + if (r == -ELOOP) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question)); + goto finish; + } + if (r < 0) + goto finish; + if (r > 0) /* This was a cname, and the query was restarted. */ + return; + r = sd_bus_message_new_method_return(q->request, &reply); if (r < 0) goto finish; @@ -368,16 +317,14 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { goto finish; if (q->answer) { - answer = dns_answer_ref(q->answer); - - for (i = 0; i < answer->n_rrs; i++) { - r = dns_question_matches_rr(q->question, answer->items[i].rr); + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(q->question, rr, NULL); if (r < 0) goto finish; if (r == 0) continue; - r = sd_bus_message_append(reply, "(is)", answer->items[i].ifindex, answer->items[i].rr->ptr.name); + r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name); if (r < 0) goto finish; @@ -385,12 +332,11 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { } } - if (added == 0) { + if (added <= 0) { _cleanup_free_ char *ip = NULL; in_addr_to_string(q->request_family, &q->request_address, &ip); - - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", ip); + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Address '%s' does not have any RR of requested type", strna(ip)); goto finish; } @@ -407,16 +353,14 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { finish: if (r < 0) { log_error_errno(r, "Failed to send address reply: %m"); - sd_bus_reply_method_errno(q->request, -r, NULL); + sd_bus_reply_method_errno(q->request, r, NULL); } dns_query_free(q); } static int bus_method_resolve_address(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; - _cleanup_free_ char *reverse = NULL; Manager *m = userdata; int family, ifindex; uint64_t flags; @@ -428,6 +372,8 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s assert(message); assert(m); + assert_cc(sizeof(int) == sizeof(int32_t)); + r = sd_bus_message_read(message, "ii", &ifindex, &family); if (r < 0) return r; @@ -446,54 +392,77 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s if (r < 0) return r; - r = check_ifindex_flags(ifindex, &flags, error); + r = check_ifindex_flags(ifindex, &flags, 0, error); if (r < 0) return r; - r = dns_name_reverse(family, d, &reverse); + r = dns_question_new_reverse(&question, family, d); if (r < 0) return r; - question = dns_question_new(1); - if (!question) - return -ENOMEM; + r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH); + if (r < 0) + return r; - key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse); - if (!key) - return -ENOMEM; + q->request = sd_bus_message_ref(message); + q->request_family = family; + memcpy(&q->request_address, d, sz); + q->complete = bus_method_resolve_address_complete; + + r = dns_query_bus_track(q, message); + if (r < 0) + goto fail; - reverse = NULL; + r = dns_query_go(q); + if (r < 0) + goto fail; - r = dns_question_add(question, key); + return 1; + +fail: + dns_query_free(q); + return r; +} + +static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) { + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + size_t start; + int r; + + assert(m); + assert(rr); + + r = sd_bus_message_open_container(m, 'r', "iqqay"); if (r < 0) return r; - r = dns_query_new(m, &q, question, ifindex, flags); + r = sd_bus_message_append(m, "iqq", + ifindex, + rr->key->class, + rr->key->type); if (r < 0) return r; - q->request = sd_bus_message_ref(message); - q->request_family = family; - memcpy(&q->request_address, d, sz); - q->complete = bus_method_resolve_address_complete; + r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); + if (r < 0) + return r; - r = dns_query_bus_track(q, message); + p->refuse_compression = true; + + r = dns_packet_append_rr(p, rr, &start); if (r < 0) return r; - r = dns_query_go(q); - if (r < 0) { - dns_query_free(q); + r = sd_bus_message_append_array(m, 'y', DNS_PACKET_DATA(p) + start, p->size - start); + if (r < 0) return r; - } - return 1; + return sd_bus_message_close_container(m); } static void bus_method_resolve_record_complete(DnsQuery *q) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned added = 0, i; + unsigned added = 0; int r; assert(q); @@ -503,6 +472,16 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { goto finish; } + r = dns_query_process_cname(q); + if (r == -ELOOP) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question)); + goto finish; + } + if (r < 0) + goto finish; + if (r > 0) /* Following a CNAME */ + return; + r = sd_bus_message_new_method_return(q->request, &reply); if (r < 0) goto finish; @@ -512,44 +491,17 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { goto finish; if (q->answer) { - answer = dns_answer_ref(q->answer); - - for (i = 0; i < answer->n_rrs; i++) { - _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - size_t start; + DnsResourceRecord *rr; + int ifindex; - r = dns_question_matches_rr(q->question, answer->items[i].rr); + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(q->question, rr, NULL); if (r < 0) goto finish; if (r == 0) continue; - r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); - if (r < 0) - goto finish; - - p->refuse_compression = true; - - r = dns_packet_append_rr(p, answer->items[i].rr, &start); - if (r < 0) - goto finish; - - r = sd_bus_message_open_container(reply, 'r', "iqqay"); - if (r < 0) - goto finish; - - r = sd_bus_message_append(reply, "iqq", - answer->items[i].ifindex, - answer->items[i].rr->key->class, - answer->items[i].rr->key->type); - if (r < 0) - goto finish; - - r = sd_bus_message_append_array(reply, 'y', DNS_PACKET_DATA(p) + start, p->size - start); - if (r < 0) - goto finish; - - r = sd_bus_message_close_container(reply); + r = bus_message_append_rr(reply, rr, ifindex); if (r < 0) goto finish; @@ -558,7 +510,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { } if (added <= 0) { - r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", q->request_hostname); + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "Name '%s' does not have any RR of the requested type", dns_question_first_name(q->question)); goto finish; } @@ -575,7 +527,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { finish: if (r < 0) { log_error_errno(r, "Failed to send record reply: %m"); - sd_bus_reply_method_errno(q->request, -r, NULL); + sd_bus_reply_method_errno(q->request, r, NULL); } dns_query_free(q); @@ -594,15 +546,19 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd assert(message); assert(m); + assert_cc(sizeof(int) == sizeof(int32_t)); + r = sd_bus_message_read(message, "isqqt", &ifindex, &name, &class, &type, &flags); if (r < 0) return r; - r = dns_name_normalize(name, NULL); + r = dns_name_is_valid(name); if (r < 0) + return r; + if (r == 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid name '%s'", name); - r = check_ifindex_flags(ifindex, &flags, error); + r = check_ifindex_flags(ifindex, &flags, 0, error); if (r < 0) return r; @@ -618,32 +574,657 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd if (r < 0) return r; - r = dns_query_new(m, &q, question, ifindex, flags); + r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH); if (r < 0) return r; q->request = sd_bus_message_ref(message); - q->request_hostname = name; q->complete = bus_method_resolve_record_complete; r = dns_query_bus_track(q, message); if (r < 0) - return r; + goto fail; r = dns_query_go(q); + if (r < 0) + goto fail; + + return 1; + +fail: + dns_query_free(q); + return r; +} + +static int append_srv(DnsQuery *q, sd_bus_message *reply, DnsResourceRecord *rr) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + DnsQuery *aux; + int r; + + assert(q); + assert(reply); + assert(rr); + assert(rr->key); + + if (rr->key->type != DNS_TYPE_SRV) + return 0; + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + /* First, let's see if we could find an appropriate A or AAAA + * record for the SRV record */ + LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) { + DnsResourceRecord *zz; + + if (aux->state != DNS_TRANSACTION_SUCCESS) + continue; + if (aux->auxiliary_result != 0) + continue; + + r = dns_name_equal(dns_question_first_name(aux->question), rr->srv.name); + if (r < 0) + return r; + if (r == 0) + continue; + + DNS_ANSWER_FOREACH(zz, aux->answer) { + + r = dns_question_matches_rr(aux->question, zz, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + + canonical = dns_resource_record_ref(zz); + break; + } + + if (canonical) + break; + } + + /* Is there are successful A/AAAA lookup for this SRV RR? If not, don't add it */ + if (!canonical) + return 0; + } + + r = sd_bus_message_open_container(reply, 'r', "qqqsa(iiay)s"); + if (r < 0) + return r; + + r = sd_bus_message_append( + reply, + "qqqs", + rr->srv.priority, rr->srv.weight, rr->srv.port, rr->srv.name); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(iiay)"); + if (r < 0) + return r; + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) { + DnsResourceRecord *zz; + int ifindex; + + if (aux->state != DNS_TRANSACTION_SUCCESS) + continue; + if (aux->auxiliary_result != 0) + continue; + + r = dns_name_equal(dns_question_first_name(aux->question), rr->srv.name); + if (r < 0) + return r; + if (r == 0) + continue; + + DNS_ANSWER_FOREACH_IFINDEX(zz, ifindex, aux->answer) { + + r = dns_question_matches_rr(aux->question, zz, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + + r = append_address(reply, zz, ifindex); + if (r < 0) + return r; + } + } + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + /* Note that above we appended the hostname as encoded in the + * SRV, and here the canonical hostname this maps to. */ + r = sd_bus_message_append(reply, "s", canonical ? DNS_RESOURCE_KEY_NAME(canonical->key) : rr->srv.name); + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return 1; +} + +static int append_txt(sd_bus_message *reply, DnsResourceRecord *rr) { + DnsTxtItem *i; + int r; + + assert(reply); + assert(rr); + assert(rr->key); + + if (rr->key->type != DNS_TYPE_TXT) + return 0; + + LIST_FOREACH(items, i, rr->txt.items) { + + if (i->length <= 0) + continue; + + r = sd_bus_message_append_array(reply, 'y', i->data, i->length); + if (r < 0) + return r; + } + + return 1; +} + +static void resolve_service_all_complete(DnsQuery *q) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL; + DnsQuery *aux; + unsigned added = false; + int r; + + assert(q); + + if (q->block_all_complete > 0) + return; + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + DnsQuery *bad = NULL; + bool have_success = false; + + LIST_FOREACH(auxiliary_queries, aux, q->auxiliary_queries) { + + switch (aux->state) { + + case DNS_TRANSACTION_PENDING: + /* If an auxiliary query is still pending, let's wait */ + return; + + case DNS_TRANSACTION_SUCCESS: + if (aux->auxiliary_result == 0) + have_success = true; + else + bad = aux; + break; + + default: + bad = aux; + break; + } + } + + if (!have_success) { + /* We can only return one error, hence pick the last error we encountered */ + + assert(bad); + + if (bad->state == DNS_TRANSACTION_SUCCESS) { + assert(bad->auxiliary_result != 0); + + if (bad->auxiliary_result == -ELOOP) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(bad->question)); + goto finish; + } + + r = bad->auxiliary_result; + goto finish; + } + + r = reply_query_state(bad); + goto finish; + } + } + + r = sd_bus_message_new_method_return(q->request, &reply); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(reply, 'a', "(qqqsa(iiay)s)"); + if (r < 0) + goto finish; + + if (q->answer) { + DnsResourceRecord *rr; + + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(q->question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + r = append_srv(q, reply, rr); + if (r < 0) + goto finish; + if (r == 0) /* not an SRV record */ + continue; + + if (!canonical) + canonical = dns_resource_record_ref(rr); + + added++; + } + } + + if (added <= 0) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question)); + goto finish; + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + goto finish; + + r = sd_bus_message_open_container(reply, 'a', "ay"); + if (r < 0) + goto finish; + + if (q->answer) { + DnsResourceRecord *rr; + + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(q->question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + r = append_txt(reply, rr); + if (r < 0) + goto finish; + } + } + + r = sd_bus_message_close_container(reply); + if (r < 0) + goto finish; + + assert(canonical); + r = dns_service_split(DNS_RESOURCE_KEY_NAME(canonical->key), &name, &type, &domain); + if (r < 0) + goto finish; + + r = sd_bus_message_append( + reply, + "ssst", + name, type, domain, + SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); + if (r < 0) + goto finish; + + r = sd_bus_send(q->manager->bus, reply, NULL); + +finish: if (r < 0) { - dns_query_free(q); + log_error_errno(r, "Failed to send service reply: %m"); + sd_bus_reply_method_errno(q->request, r, NULL); + } + + dns_query_free(q); +} + +static void resolve_service_hostname_complete(DnsQuery *q) { + int r; + + assert(q); + assert(q->auxiliary_for); + + if (q->state != DNS_TRANSACTION_SUCCESS) { + resolve_service_all_complete(q->auxiliary_for); + return; + } + + r = dns_query_process_cname(q); + if (r > 0) /* This was a cname, and the query was restarted. */ + return; + + /* This auxiliary lookup is finished or failed, let's see if all are finished now. */ + q->auxiliary_result = r; + resolve_service_all_complete(q->auxiliary_for); +} + +static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifindex) { + _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; + DnsQuery *aux; + int r; + + assert(q); + assert(rr); + assert(rr->key); + assert(rr->key->type == DNS_TYPE_SRV); + + /* OK, we found an SRV record for the service. Let's resolve + * the hostname included in it */ + + r = dns_question_new_address(&question, q->request_family, rr->srv.name); + if (r < 0) + return r; + + r = dns_query_new(q->manager, &aux, question, ifindex, q->flags|SD_RESOLVED_NO_SEARCH); + if (r < 0) return r; + + aux->request_family = q->request_family; + aux->complete = resolve_service_hostname_complete; + + r = dns_query_make_auxiliary(aux, q); + if (r == -EAGAIN) { + /* Too many auxiliary lookups? If so, don't complain, + * let's just not add this one, we already have more + * than enough */ + + dns_query_free(aux); + return 0; } + if (r < 0) + goto fail; + + /* Note that auxiliary queries do not track the original bus + * client, only the primary request does that. */ + + r = dns_query_go(aux); + if (r < 0) + goto fail; return 1; + +fail: + dns_query_free(aux); + return r; +} + +static void bus_method_resolve_service_complete(DnsQuery *q) { + unsigned found = 0; + int r; + + assert(q); + + if (q->state != DNS_TRANSACTION_SUCCESS) { + r = reply_query_state(q); + goto finish; + } + + r = dns_query_process_cname(q); + if (r == -ELOOP) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_question_first_name(q->question)); + goto finish; + } + if (r < 0) + goto finish; + if (r > 0) /* This was a cname, and the query was restarted. */ + return; + + if (q->answer) { + DnsResourceRecord *rr; + int ifindex; + + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(q->question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + if (rr->key->type != DNS_TYPE_SRV) + continue; + + if ((q->flags & SD_RESOLVED_NO_ADDRESS) == 0) { + q->block_all_complete ++; + r = resolve_service_hostname(q, rr, ifindex); + q->block_all_complete --; + + if (r < 0) + goto finish; + } + + found++; + } + } + + if (found <= 0) { + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_RR, "'%s' does not have any RR of the requested type", dns_question_first_name(q->question)); + goto finish; + } + + /* Maybe we are already finished? check now... */ + resolve_service_all_complete(q); + return; + +finish: + if (r < 0) { + log_error_errno(r, "Failed to send service reply: %m"); + sd_bus_reply_method_errno(q->request, r, NULL); + } + + dns_query_free(q); +} + +static int bus_method_resolve_service(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; + const char *name, *type, *domain, *joined; + _cleanup_free_ char *n = NULL; + Manager *m = userdata; + int family, ifindex; + uint64_t flags; + DnsQuery *q; + int r; + + assert(message); + assert(m); + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_read(message, "isssit", &ifindex, &name, &type, &domain, &family, &flags); + if (r < 0) + return r; + + if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + + if (isempty(name)) + name = NULL; + else { + if (!dns_service_name_is_valid(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service name '%s'", name); + } + + if (isempty(type)) + type = NULL; + else if (!dns_srv_type_is_valid(type)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type); + + r = dns_name_is_valid(domain); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid domain '%s'", domain); + + if (name && !type) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Service name cannot be specified without service type."); + + r = check_ifindex_flags(ifindex, &flags, SD_RESOLVED_NO_TXT|SD_RESOLVED_NO_ADDRESS, error); + if (r < 0) + return r; + + if (type) { + /* If the type is specified, we generate the full domain name to look up ourselves */ + r = dns_service_join(name, type, domain, &n); + if (r < 0) + return r; + + joined = n; + } else + /* If no type is specified, we assume the domain + * contains the full domain name to lookup already */ + joined = domain; + + r = dns_question_new_service(&question, joined, !(flags & SD_RESOLVED_NO_TXT)); + if (r < 0) + return r; + + r = dns_query_new(m, &q, question, ifindex, flags|SD_RESOLVED_NO_SEARCH); + if (r < 0) + return r; + + q->request = sd_bus_message_ref(message); + q->request_family = family; + q->complete = bus_method_resolve_service_complete; + + r = dns_query_bus_track(q, message); + if (r < 0) + goto fail; + + r = dns_query_go(q); + if (r < 0) + goto fail; + + return 1; + +fail: + dns_query_free(q); + return r; +} + +static int append_dns_server(sd_bus_message *reply, DnsServer *s) { + int r; + + assert(reply); + assert(s); + + r = sd_bus_message_open_container(reply, 'r', "iiay"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "ii", s->link ? s->link->ifindex : 0, s->family); + if (r < 0) + return r; + + r = sd_bus_message_append_array(reply, 'y', &s->address, FAMILY_ADDRESS_SIZE(s->family)); + if (r < 0) + return r; + + return sd_bus_message_close_container(reply); +} + +static int bus_property_get_dns_servers( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + unsigned c = 0; + DnsServer *s; + Iterator i; + Link *l; + int r; + + assert(reply); + assert(m); + + r = sd_bus_message_open_container(reply, 'a', "(iiay)"); + if (r < 0) + return r; + + LIST_FOREACH(servers, s, m->dns_servers) { + r = append_dns_server(reply, s); + if (r < 0) + return r; + + c++; + } + + HASHMAP_FOREACH(l, m->links, i) { + LIST_FOREACH(servers, s, l->dns_servers) { + r = append_dns_server(reply, s); + if (r < 0) + return r; + c++; + } + } + + if (c == 0) { + LIST_FOREACH(servers, s, m->fallback_dns_servers) { + r = append_dns_server(reply, s); + if (r < 0) + return r; + } + } + + return sd_bus_message_close_container(reply); +} + +static int bus_property_get_search_domains( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Manager *m = userdata; + DnsSearchDomain *d; + Iterator i; + Link *l; + int r; + + assert(reply); + assert(m); + + r = sd_bus_message_open_container(reply, 'a', "(is)"); + if (r < 0) + return r; + + LIST_FOREACH(domains, d, m->search_domains) { + r = sd_bus_message_append(reply, "(is)", 0, d->name); + if (r < 0) + return r; + } + + HASHMAP_FOREACH(l, m->links, i) { + LIST_FOREACH(domains, d, l->search_domains) { + r = sd_bus_message_append(reply, "is", l->ifindex, d->name); + if (r < 0) + return r; + } + } + + return sd_bus_message_close_container(reply); } static const sd_bus_vtable resolve_vtable[] = { SD_BUS_VTABLE_START(0), + SD_BUS_PROPERTY("LLMNRHostname", "s", NULL, offsetof(Manager, llmnr_hostname), 0), + SD_BUS_PROPERTY("DNSServers", "a(iiay)", bus_property_get_dns_servers, 0, 0), + SD_BUS_PROPERTY("SearchDomains", "a(is)", bus_property_get_search_domains, 0, 0), + SD_BUS_METHOD("ResolveHostname", "isit", "a(iiay)st", bus_method_resolve_hostname, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResolveAddress", "iiayt", "a(is)t", bus_method_resolve_address, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ResolveRecord", "isqqt", "a(iqqay)t", bus_method_resolve_record, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("ResolveService", "isssit", "a(qqqsa(iiay)s)aayssst", bus_method_resolve_service, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END, }; diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 9207719551..3fc7d9ae3d 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -27,53 +27,99 @@ #include "resolved-conf.h" #include "string-util.h" -int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string) { - DnsServer *first; +int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) { + union in_addr_union address; + int family, r; + DnsServer *s; + + assert(m); + assert(word); + + r = in_addr_from_string_auto(word, &family, &address); + if (r < 0) + return r; + + /* Filter out duplicates */ + s = dns_server_find(manager_get_first_dns_server(m, type), family, &address); + if (s) { + /* + * Drop the marker. This is used to find the servers + * that ceased to exist, see + * manager_mark_dns_servers() and + * manager_flush_marked_dns_servers(). + */ + dns_server_move_back_and_unmark(s); + return 0; + } + + return dns_server_new(m, NULL, type, NULL, family, &address); +} + +int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) { int r; assert(m); assert(string); - first = type == DNS_SERVER_FALLBACK ? m->fallback_dns_servers : m->dns_servers; - for(;;) { _cleanup_free_ char *word = NULL; - union in_addr_union addr; - bool found = false; - DnsServer *s; - int family; 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); + return r; if (r == 0) break; - r = in_addr_from_string_auto(word, &family, &addr); - if (r < 0) { - log_warning("Ignoring invalid DNS address '%s'", word); - continue; - } + r = manager_add_dns_server_by_string(m, type, word); + if (r < 0) + log_warning_errno(r, "Failed to add DNS server address '%s', ignoring.", word); + } + + return 0; +} - /* Filter out duplicates */ - LIST_FOREACH(servers, s, first) - if (s->family == family && in_addr_equal(family, &s->address, &addr)) { - found = true; - break; - } +int manager_add_search_domain_by_string(Manager *m, const char *domain) { + DnsSearchDomain *d; + int r; - if (found) - continue; + assert(m); + assert(domain); - r = dns_server_new(m, NULL, type, NULL, family, &addr); + r = dns_search_domain_find(m->search_domains, domain, &d); + if (r < 0) + return r; + if (r > 0) { + dns_search_domain_move_back_and_unmark(d); + return 0; + } + + return dns_search_domain_new(m, NULL, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain); +} + +int manager_parse_search_domains_and_warn(Manager *m, const char *string) { + int r; + + assert(m); + assert(string); + + for(;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES); if (r < 0) return r; + if (r == 0) + break; + + r = manager_add_search_domain_by_string(m, word); + if (r < 0) + log_warning_errno(r, "Failed to add search domain '%s', ignoring.", word); } return 0; } -int config_parse_dnsv( +int config_parse_dns_servers( const char *unit, const char *filename, unsigned line, @@ -95,10 +141,10 @@ int config_parse_dnsv( if (isempty(rvalue)) /* Empty assignment means clear the list */ - manager_flush_dns_servers(m, ltype); + dns_server_unlink_all(manager_get_first_dns_server(m, ltype)); else { /* Otherwise, add to the list */ - r = manager_parse_dns_server(m, ltype, rvalue); + r = manager_parse_dns_server_string_and_warn(m, ltype, rvalue); if (r < 0) { log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue); return 0; @@ -109,6 +155,47 @@ int config_parse_dnsv( * /etc/resolv.conf */ if (ltype == DNS_SERVER_SYSTEM) m->read_resolv_conf = false; + if (ltype == DNS_SERVER_FALLBACK) + m->need_builtin_fallbacks = false; + + return 0; +} + +int config_parse_search_domains( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Manager *m = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(m); + + if (isempty(rvalue)) + /* Empty assignment means clear the list */ + dns_search_domain_unlink_all(m->search_domains); + else { + /* Otherwise, add to the list */ + r = manager_parse_search_domains_and_warn(m, rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse search domains string '%s'. Ignoring.", rvalue); + return 0; + } + } + + /* If we have a manual setting, then we stop reading + * /etc/resolv.conf */ + m->read_resolv_conf = false; return 0; } @@ -148,11 +235,24 @@ int config_parse_support( } int manager_parse_config_file(Manager *m) { + int r; + assert(m); - return config_parse_many(PKGSYSCONFDIR "/resolved.conf", - CONF_PATHS_NULSTR("systemd/resolved.conf.d"), - "Resolve\0", - config_item_perf_lookup, resolved_gperf_lookup, - false, m); + r = config_parse_many(PKGSYSCONFDIR "/resolved.conf", + CONF_PATHS_NULSTR("systemd/resolved.conf.d"), + "Resolve\0", + config_item_perf_lookup, resolved_gperf_lookup, + false, m); + if (r < 0) + return r; + + if (m->need_builtin_fallbacks) { + r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_FALLBACK, DNS_SERVERS); + if (r < 0) + return r; + } + + return 0; + } diff --git a/src/resolve/resolved-conf.h b/src/resolve/resolved-conf.h index b3dbea7b6b..28d2549d35 100644 --- a/src/resolve/resolved-conf.h +++ b/src/resolve/resolved-conf.h @@ -23,10 +23,16 @@ #include "resolved-manager.h" -int manager_parse_dns_server(Manager *m, DnsServerType type, const char *string); int manager_parse_config_file(Manager *m); +int manager_add_search_domain_by_string(Manager *m, const char *domain); +int manager_parse_search_domains_and_warn(Manager *m, const char *string); + +int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word); +int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string); + const struct ConfigPerfItem* resolved_gperf_lookup(const char *key, unsigned length); -int config_parse_dnsv(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_dns_servers(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_search_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_support(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/resolve/resolved-def.h b/src/resolve/resolved-def.h index 086d111205..be29f51663 100644 --- a/src/resolve/resolved-def.h +++ b/src/resolve/resolved-def.h @@ -21,10 +21,13 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#define SD_RESOLVED_DNS ((uint64_t) 1) -#define SD_RESOLVED_LLMNR_IPV4 ((uint64_t) 2) -#define SD_RESOLVED_LLMNR_IPV6 ((uint64_t) 4) -#define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) +#define SD_RESOLVED_DNS (UINT64_C(1) << 0) +#define SD_RESOLVED_LLMNR_IPV4 (UINT64_C(1) << 1) +#define SD_RESOLVED_LLMNR_IPV6 (UINT64_C(1) << 2) +#define SD_RESOLVED_NO_CNAME (UINT64_C(1) << 5) +#define SD_RESOLVED_NO_TXT (UINT64_C(1) << 6) +#define SD_RESOLVED_NO_ADDRESS (UINT64_C(1) << 7) +#define SD_RESOLVED_NO_SEARCH (UINT64_C(1) << 8) -#define SD_RESOLVED_FLAGS_ALL (SD_RESOLVED_DNS|SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) -#define SD_RESOLVED_FLAGS_DEFAULT SD_RESOLVED_FLAGS_ALL +#define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) +#define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_LLMNR|SD_RESOLVED_DNS) diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 3cf9c68074..4db67f7278 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -141,7 +141,7 @@ int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) { return 0; for (i = 0; i < a->n_rrs; i++) { - r = dns_resource_key_match_rr(key, a->items[i].rr); + r = dns_resource_key_match_rr(key, a->items[i].rr, NULL); if (r < 0) return r; if (r > 0) diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 044d73b19c..8814919deb 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -58,3 +58,20 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local); int dns_answer_reserve(DnsAnswer **a, unsigned n_free); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref); + +#define DNS_ANSWER_FOREACH(kk, a) \ + for (unsigned _i = ({ \ + (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \ + 0; \ + }); \ + (a) && ((_i) < (a)->n_rrs); \ + _i++, (kk) = (_i < (a)->n_rrs ? (a)->items[_i].rr : NULL)) + +#define DNS_ANSWER_FOREACH_IFINDEX(kk, ifindex, a) \ + for (unsigned _i = ({ \ + (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \ + (ifindex) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].ifindex : 0; \ + 0; \ + }); \ + (a) && ((_i) < (a)->n_rrs); \ + _i++, (kk) = ((_i < (a)->n_rrs) ? (a)->items[_i].rr : NULL), (ifindex) = ((_i < (a)->n_rrs) ? (a)->items[_i].ifindex : 0)) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 04f64022e0..d963ce6e00 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -20,8 +20,10 @@ ***/ #include "alloc-util.h" +#include "dns-domain.h" #include "resolved-dns-cache.h" #include "resolved-dns-packet.h" +#include "string-util.h" /* Never cache more than 1K entries */ #define CACHE_MAX 1024 @@ -521,25 +523,53 @@ fail: static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceKey *k) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *cname_key = NULL; - DnsCacheItem *i, *j; + DnsCacheItem *i; + const char *n; + int r; assert(c); assert(k); + /* If we hit some OOM error, or suchlike, we don't care too + * much, after all this is just a cache */ + i = hashmap_get(c->by_key, k); - if (i || k->type == DNS_TYPE_CNAME) + if (i || k->type == DNS_TYPE_CNAME || k->type == DNS_TYPE_DNAME) return i; - /* check if we have a CNAME record instead */ + /* Check if we have a CNAME record instead */ cname_key = dns_resource_key_new_cname(k); if (!cname_key) return NULL; - j = hashmap_get(c->by_key, cname_key); - if (j) - return j; + i = hashmap_get(c->by_key, cname_key); + if (i) + return i; + + /* OK, let's look for cached DNAME records. */ + n = DNS_RESOURCE_KEY_NAME(k); + for (;;) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *dname_key = NULL; + char label[DNS_LABEL_MAX]; + + if (isempty(n)) + return NULL; - return i; + dname_key = dns_resource_key_new(k->class, DNS_TYPE_DNAME, n); + if (!dname_key) + return NULL; + + i = hashmap_get(c->by_key, dname_key); + if (i) + return i; + + /* Jump one label ahead */ + r = dns_label_unescape(&n, label, sizeof(label)); + if (r <= 0) + return NULL; + } + + return NULL; } int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret) { diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index 60cf6a4784..164435b4fb 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -23,18 +23,18 @@ #include "hashmap.h" +#include "list.h" #include "prioq.h" #include "time-util.h" -#include "list.h" typedef struct DnsCache { Hashmap *by_key; Prioq *by_expiry; } DnsCache; -#include "resolved-dns-rr.h" -#include "resolved-dns-question.h" #include "resolved-dns-answer.h" +#include "resolved-dns-question.h" +#include "resolved-dns-rr.h" void dns_cache_flush(DnsCache *c); void dns_cache_prune(DnsCache *c); diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index f23b3cf893..40b662246f 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -370,6 +370,28 @@ int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) { return 0; } +int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start) { + void *d; + int r; + + assert(p); + assert(s || size == 0); + + if (size > 255) + return -E2BIG; + + r = dns_packet_extend(p, 1 + size, &d, start); + if (r < 0) + return r; + + ((uint8_t*) d)[0] = (uint8_t) size; + + if (size > 0) + memcpy(((uint8_t*) d) + 1, s, size); + + return 0; +} + int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) { void *w; int r; @@ -643,19 +665,20 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star break; case DNS_TYPE_SPF: /* exactly the same as TXT */ - case DNS_TYPE_TXT: { - char **s; + case DNS_TYPE_TXT: - if (strv_isempty(rr->txt.strings)) { + if (!rr->txt.items) { /* RFC 6763, section 6.1 suggests to generate * single empty string for an empty array. */ - r = dns_packet_append_string(p, "", NULL); + r = dns_packet_append_raw_string(p, NULL, 0, NULL); if (r < 0) goto fail; } else { - STRV_FOREACH(s, rr->txt.strings) { - r = dns_packet_append_string(p, *s, NULL); + DnsTxtItem *i; + + LIST_FOREACH(items, i, rr->txt.items) { + r = dns_packet_append_raw_string(p, i->data, i->length, NULL); if (r < 0) goto fail; } @@ -663,7 +686,6 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star r = 0; break; - } case DNS_TYPE_A: r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL); @@ -1062,6 +1084,35 @@ fail: return r; } +int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start) { + size_t saved_rindex; + uint8_t c; + int r; + + assert(p); + + saved_rindex = p->rindex; + + r = dns_packet_read_uint8(p, &c, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read(p, c, ret, NULL); + if (r < 0) + goto fail; + + if (size) + *size = c; + if (start) + *start = saved_rindex; + + return 0; + +fail: + dns_packet_rewind(p, saved_rindex); + return r; +} + int dns_packet_read_name( DnsPacket *p, char **_ret, @@ -1094,7 +1145,6 @@ int dns_packet_read_name( /* End of name */ break; else if (c <= 63) { - _cleanup_free_ char *t = NULL; const char *label; /* Literal label */ @@ -1102,21 +1152,20 @@ int dns_packet_read_name( if (r < 0) goto fail; - r = dns_label_escape(label, c, &t); - if (r < 0) - goto fail; - - if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) { + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { r = -ENOMEM; goto fail; } - if (!first) - ret[n++] = '.'; - else + if (first) first = false; + else + ret[n++] = '.'; + + r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + goto fail; - memcpy(ret + n, t, r); n += r; continue; } else if (allow_compression && (c & 0xc0) == 0xc0) { @@ -1412,24 +1461,37 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { case DNS_TYPE_SPF: /* exactly the same as TXT */ case DNS_TYPE_TXT: if (rdlength <= 0) { + DnsTxtItem *i; /* RFC 6763, section 6.1 suggests to treat * empty TXT RRs as equivalent to a TXT record * with a single empty string. */ - r = strv_extend(&rr->txt.strings, ""); - if (r < 0) - goto fail; + i = malloc0(offsetof(DnsTxtItem, data) + 1); /* for safety reasons we add an extra NUL byte */ + if (!i) + return -ENOMEM; + + rr->txt.items = i; } else { + DnsTxtItem *last = NULL; + while (p->rindex < offset + rdlength) { - char *s; + DnsTxtItem *i; + const void *data; + size_t sz; - r = dns_packet_read_string(p, &s, NULL); + r = dns_packet_read_raw_string(p, &data, &sz, NULL); if (r < 0) - goto fail; + return r; - r = strv_consume(&rr->txt.strings, s); - if (r < 0) - goto fail; + i = malloc0(offsetof(DnsTxtItem, data) + sz + 1); /* extra NUL byte at the end */ + if (!i) + return -ENOMEM; + + memcpy(i->data, data, sz); + i->length = sz; + + LIST_INSERT_AFTER(items, rr->txt.items, last, i); + last = i; } } @@ -1682,12 +1744,9 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; - /* The types bitmap must contain at least the NSEC record itself, so an empty bitmap means - something went wrong */ - if (bitmap_isclear(rr->nsec.types)) { - r = -EBADMSG; - goto fail; - } + /* We accept empty NSEC bitmaps. The bit indicating the presence of the NSEC record itself + * is redundant and in e.g., RFC4956 this fact is used to define a use for NSEC records + * without the NSEC bit set. */ break; diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index fbbabaf232..90b5a7c8bd 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -21,21 +21,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/udp.h> #include <netinet/ip.h> +#include <netinet/udp.h> -#include "macro.h" -#include "sparse-endian.h" #include "hashmap.h" #include "in-addr-util.h" +#include "macro.h" +#include "sparse-endian.h" typedef struct DnsPacketHeader DnsPacketHeader; typedef struct DnsPacket DnsPacket; -#include "resolved-dns-rr.h" -#include "resolved-dns-question.h" -#include "resolved-dns-answer.h" #include "resolved-def.h" +#include "resolved-dns-answer.h" +#include "resolved-dns-question.h" +#include "resolved-dns-rr.h" typedef enum DnsProtocol { DNS_PROTOCOL_DNS, @@ -155,9 +155,9 @@ int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start); int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start); int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start); int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start); +int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start); int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, size_t *start); -int dns_packet_append_name(DnsPacket *p, const char *name, - bool allow_compression, size_t *start); +int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, size_t *start); int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start); int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start); @@ -167,8 +167,8 @@ int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start); int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start); int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start); int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start); -int dns_packet_read_name(DnsPacket *p, char **ret, - bool allow_compression, size_t *start); +int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, size_t *start); +int dns_packet_read_name(DnsPacket *p, char **ret, bool allow_compression, size_t *start); int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start); int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start); @@ -177,6 +177,14 @@ void dns_packet_rewind(DnsPacket *p, size_t idx); int dns_packet_skip_question(DnsPacket *p); int dns_packet_extract(DnsPacket *p); +static inline bool DNS_PACKET_SHALL_CACHE(DnsPacket *p) { + /* Never cache data originating from localhost, under the + * assumption, that it's coming from a locally DNS forwarder + * or server, that is caching on its own. */ + + return in_addr_is_localhost(p->family, &p->sender) == 0; +} + enum { DNS_RCODE_SUCCESS = 0, DNS_RCODE_FORMERR = 1, diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index f7cb84e2a6..a96cf439ad 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -30,29 +30,286 @@ #define CNAME_MAX 8 #define QUERIES_MAX 2048 +#define AUXILIARY_QUERIES_MAX 64 -static void dns_query_stop(DnsQuery *q) { - DnsTransaction *t; +static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) { + DnsQueryCandidate *c; + assert(ret); assert(q); + assert(s); - q->timeout_event_source = sd_event_source_unref(q->timeout_event_source); + c = new0(DnsQueryCandidate, 1); + if (!c) + return -ENOMEM; + + c->query = q; + c->scope = s; + + LIST_PREPEND(candidates_by_query, q->candidates, c); + LIST_PREPEND(candidates_by_scope, s->query_candidates, c); + + *ret = c; + return 0; +} - while ((t = set_steal_first(q->transactions))) { - set_remove(t->queries, q); +static void dns_query_candidate_stop(DnsQueryCandidate *c) { + DnsTransaction *t; + + assert(c); + + while ((t = set_steal_first(c->transactions))) { + set_remove(t->query_candidates, c); dns_transaction_gc(t); } } +DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) { + + if (!c) + return NULL; + + dns_query_candidate_stop(c); + + set_free(c->transactions); + dns_search_domain_unref(c->search_domain); + + if (c->query) + LIST_REMOVE(candidates_by_query, c->query->candidates, c); + + if (c->scope) + LIST_REMOVE(candidates_by_scope, c->scope->query_candidates, c); + + free(c); + + return NULL; +} + +static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) { + _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *previous = NULL; + DnsSearchDomain *next = NULL; + + assert(c); + + if (c->search_domain && c->search_domain->linked) { + next = c->search_domain->domains_next; + + if (!next) /* We hit the end of the list */ + return 0; + + } else { + next = dns_scope_get_search_domains(c->scope); + + if (!next) /* OK, there's nothing. */ + return 0; + } + + dns_search_domain_unref(c->search_domain); + c->search_domain = dns_search_domain_ref(next); + + return 1; +} + +static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) { + DnsTransaction *t; + int r; + + assert(c); + assert(key); + + r = set_ensure_allocated(&c->transactions, NULL); + if (r < 0) + return r; + + t = dns_scope_find_transaction(c->scope, key, true); + if (!t) { + r = dns_transaction_new(&t, c->scope, key); + if (r < 0) + return r; + } + + r = set_ensure_allocated(&t->query_candidates, NULL); + if (r < 0) + goto gc; + + r = set_put(t->query_candidates, c); + if (r < 0) + goto gc; + + r = set_put(c->transactions, t); + if (r < 0) { + set_remove(t->query_candidates, c); + goto gc; + } + + return 0; + +gc: + dns_transaction_gc(t); + return r; +} + +static int dns_query_candidate_go(DnsQueryCandidate *c) { + DnsTransaction *t; + Iterator i; + int r; + + assert(c); + + /* Start the transactions that are not started yet */ + SET_FOREACH(t, c->transactions, i) { + if (t->state != DNS_TRANSACTION_NULL) + continue; + + r = dns_transaction_go(t); + if (r < 0) + return r; + } + + return 0; +} + +static DnsTransactionState dns_query_candidate_state(DnsQueryCandidate *c) { + DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; + DnsTransaction *t; + Iterator i; + + assert(c); + + if (c->error_code != 0) + return DNS_TRANSACTION_RESOURCES; + + SET_FOREACH(t, c->transactions, i) { + + switch (t->state) { + + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_NULL: + return t->state; + + case DNS_TRANSACTION_SUCCESS: + state = t->state; + break; + + default: + if (state != DNS_TRANSACTION_SUCCESS) + state = t->state; + + break; + } + } + + return state; +} + +static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) { + DnsResourceKey *key; + int n = 0, r; + + assert(c); + + dns_query_candidate_stop(c); + + /* Create one transaction per question key */ + DNS_QUESTION_FOREACH(key, c->query->question) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL; + + if (c->search_domain) { + r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name); + if (r < 0) + goto fail; + } + + r = dns_query_candidate_add_transaction(c, new_key ?: key); + if (r < 0) + goto fail; + + n++; + } + + return n; + +fail: + dns_query_candidate_stop(c); + return r; +} + +void dns_query_candidate_ready(DnsQueryCandidate *c) { + DnsTransactionState state; + int r; + + assert(c); + + state = dns_query_candidate_state(c); + + if (IN_SET(state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL)) + return; + + if (state != DNS_TRANSACTION_SUCCESS && c->search_domain) { + + r = dns_query_candidate_next_search_domain(c); + if (r < 0) + goto fail; + + if (r > 0) { + /* OK, there's another search domain to try, let's do so. */ + + r = dns_query_candidate_setup_transactions(c); + if (r < 0) + goto fail; + + if (r > 0) { + /* New transactions where queued. Start them and wait */ + + r = dns_query_candidate_go(c); + if (r < 0) + goto fail; + + return; + } + } + + } + + dns_query_ready(c->query); + return; + +fail: + log_warning_errno(r, "Failed to follow search domains: %m"); + c->error_code = r; + dns_query_ready(c->query); +} + +static void dns_query_stop(DnsQuery *q) { + DnsQueryCandidate *c; + + assert(q); + + q->timeout_event_source = sd_event_source_unref(q->timeout_event_source); + + LIST_FOREACH(candidates_by_query, c, q->candidates) + dns_query_candidate_stop(c); +} + DnsQuery *dns_query_free(DnsQuery *q) { if (!q) return NULL; - dns_query_stop(q); - set_free(q->transactions); + while (q->auxiliary_queries) + dns_query_free(q->auxiliary_queries); + + if (q->auxiliary_for) { + assert(q->auxiliary_for->n_auxiliary_queries > 0); + q->auxiliary_for->n_auxiliary_queries--; + LIST_REMOVE(auxiliary_queries, q->auxiliary_for->auxiliary_queries, q); + } + + while (q->candidates) + dns_query_candidate_free(q->candidates); dns_question_unref(q->question); dns_answer_unref(q->answer); + dns_search_domain_unref(q->answer_search_domain); sd_bus_message_unref(q->request); sd_bus_track_unref(q->bus_track); @@ -75,7 +332,7 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex assert(m); assert(question); - r = dns_question_is_valid(question); + r = dns_question_is_valid_for_query(question); if (r < 0) return r; @@ -89,6 +346,8 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex q->question = dns_question_ref(question); q->ifindex = ifindex; q->flags = flags; + q->answer_family = AF_UNSPEC; + q->answer_protocol = _DNS_PROTOCOL_INVALID; for (i = 0; i < question->n_keys; i++) { _cleanup_free_ char *p; @@ -111,6 +370,29 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex return 0; } +int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for) { + assert(q); + assert(auxiliary_for); + + /* Ensure that that the query is not auxiliary yet, and + * nothing else is auxiliary to it either */ + assert(!q->auxiliary_for); + assert(!q->auxiliary_queries); + + /* Ensure that the unit we shall be made auxiliary for isn't + * auxiliary itself */ + assert(!auxiliary_for->auxiliary_for); + + if (auxiliary_for->n_auxiliary_queries >= AUXILIARY_QUERIES_MAX) + return -EAGAIN; + + LIST_PREPEND(auxiliary_queries, auxiliary_for->auxiliary_queries, q); + q->auxiliary_for = auxiliary_for; + + auxiliary_for->n_auxiliary_queries++; + return 0; +} + static void dns_query_complete(DnsQuery *q, DnsTransactionState state) { assert(q); assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); @@ -137,64 +419,40 @@ static int on_query_timeout(sd_event_source *s, usec_t usec, void *userdata) { return 0; } -static int dns_query_add_transaction(DnsQuery *q, DnsScope *s, DnsResourceKey *key) { - DnsTransaction *t; +static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) { + DnsQueryCandidate *c; int r; assert(q); assert(s); - assert(key); - r = set_ensure_allocated(&q->transactions, NULL); + r = dns_query_candidate_new(&c, q, s); if (r < 0) return r; - t = dns_scope_find_transaction(s, key, true); - if (!t) { - r = dns_transaction_new(&t, s, key); - if (r < 0) - return r; - } - - r = set_ensure_allocated(&t->queries, NULL); + /* If this a single-label domain on DNS, we might append a suitable search domain first. */ + r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question)); if (r < 0) - goto gc; - - r = set_put(t->queries, q); - if (r < 0) - goto gc; + goto fail; + if (r > 0) { + /* OK, we need a search domain now. Let's find one for this scope */ - r = set_put(q->transactions, t); - if (r < 0) { - set_remove(t->queries, q); - goto gc; + r = dns_query_candidate_next_search_domain(c); + if (r <= 0) /* if there's no search domain, then we won't add any transaction. */ + goto fail; } + r = dns_query_candidate_setup_transactions(c); + if (r < 0) + goto fail; + return 0; -gc: - dns_transaction_gc(t); +fail: + dns_query_candidate_free(c); return r; } -static int dns_query_add_transaction_split(DnsQuery *q, DnsScope *s) { - unsigned i; - int r; - - assert(q); - assert(s); - - /* Create one transaction per question key */ - - for (i = 0; i < q->question->n_keys; i++) { - r = dns_query_add_transaction(q, s, q->question->keys[i]); - if (r < 0) - return r; - } - - return 0; -} - static int SYNTHESIZE_IFINDEX(int ifindex) { /* When the caller asked for resolving on a specific @@ -597,9 +855,9 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer = answer; answer = NULL; - q->answer_family = SYNTHESIZE_FAMILY(q->flags); - q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags); q->answer_rcode = DNS_RCODE_SUCCESS; + q->answer_protocol = SYNTHESIZE_PROTOCOL(q->flags); + q->answer_family = SYNTHESIZE_FAMILY(q->flags); *state = DNS_TRANSACTION_SUCCESS; @@ -609,9 +867,8 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { int dns_query_go(DnsQuery *q) { DnsScopeMatch found = DNS_SCOPE_NO; DnsScope *s, *first = NULL; - DnsTransaction *t; + DnsQueryCandidate *c; const char *name; - Iterator i; int r; assert(q); @@ -622,7 +879,7 @@ int dns_query_go(DnsQuery *q) { assert(q->question); assert(q->question->n_keys > 0); - name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]); + name = dns_question_first_name(q->question); LIST_FOREACH(scopes, s, q->manager->dns_scopes) { DnsScopeMatch match; @@ -655,7 +912,7 @@ int dns_query_go(DnsQuery *q) { return 1; } - r = dns_query_add_transaction_split(q, first); + r = dns_query_add_candidate(q, first); if (r < 0) goto fail; @@ -669,7 +926,7 @@ int dns_query_go(DnsQuery *q) { if (match != found) continue; - r = dns_query_add_transaction_split(q, s); + r = dns_query_add_candidate(q, s); if (r < 0) goto fail; } @@ -691,14 +948,13 @@ int dns_query_go(DnsQuery *q) { q->state = DNS_TRANSACTION_PENDING; q->block_ready++; - /* Start the transactions that are not started yet */ - SET_FOREACH(t, q->transactions, i) { - if (t->state != DNS_TRANSACTION_NULL) - continue; - - r = dns_transaction_go(t); - if (r < 0) + /* Start the transactions */ + LIST_FOREACH(candidates_by_query, c, q->candidates) { + r = dns_query_candidate_go(c); + if (r < 0) { + q->block_ready--; goto fail; + } } q->block_ready--; @@ -711,132 +967,128 @@ fail: return r; } -void dns_query_ready(DnsQuery *q) { - DnsTransaction *t; +static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - int rcode = 0; - DnsScope *scope = NULL; - bool pending = false; + DnsTransaction *t; Iterator i; assert(q); - assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); - /* Note that this call might invalidate the query. Callers - * should hence not attempt to access the query or transaction - * after calling this function, unless the block_ready - * counter was explicitly bumped before doing so. */ - - if (q->block_ready > 0) + if (!c) { + dns_query_synthesize_reply(q, &state); + dns_query_complete(q, state); return; + } - SET_FOREACH(t, q->transactions, i) { + SET_FOREACH(t, c->transactions, i) { - /* If we found a successful answer, ignore all answers from other scopes */ - if (state == DNS_TRANSACTION_SUCCESS && t->scope != scope) - continue; + switch (t->state) { - /* One of the transactions is still going on, let's maybe wait for it */ - if (IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL)) { - pending = true; - continue; - } + case DNS_TRANSACTION_SUCCESS: { + /* We found a successfuly reply, merge it into the answer */ + DnsAnswer *merged; - /* One of the transactions is successful, let's use - * it, and copy its data out */ - if (t->state == DNS_TRANSACTION_SUCCESS) { - DnsAnswer *a; - - if (t->received) { - rcode = DNS_PACKET_RCODE(t->received); - a = t->received->answer; - } else { - rcode = t->cached_rcode; - a = t->cached; + merged = dns_answer_merge(q->answer, t->answer); + if (!merged) { + dns_query_complete(q, DNS_TRANSACTION_RESOURCES); + return; } - if (state == DNS_TRANSACTION_SUCCESS) { - DnsAnswer *merged; + dns_answer_unref(q->answer); + q->answer = merged; + q->answer_rcode = t->answer_rcode; + + state = DNS_TRANSACTION_SUCCESS; + break; + } + + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_NULL: + case DNS_TRANSACTION_ABORTED: + /* Ignore transactions that didn't complete */ + continue; + + default: + /* Any kind of failure? Store the data away, + * if there's nothing stored yet. */ - merged = dns_answer_merge(answer, a); - if (!merged) { - dns_query_complete(q, DNS_TRANSACTION_RESOURCES); - return; - } + if (state != DNS_TRANSACTION_SUCCESS) { - dns_answer_unref(answer); - answer = merged; - } else { - dns_answer_unref(answer); - answer = dns_answer_ref(a); + dns_answer_unref(q->answer); + q->answer = dns_answer_ref(t->answer); + q->answer_rcode = t->answer_rcode; + + state = t->state; } - scope = t->scope; - state = DNS_TRANSACTION_SUCCESS; - continue; + break; } + } - /* One of the transactions has failed, let's see - * whether we find anything better, but if not, return - * its response data */ - if (state != DNS_TRANSACTION_SUCCESS && t->state == DNS_TRANSACTION_FAILURE) { - DnsAnswer *a; - - if (t->received) { - rcode = DNS_PACKET_RCODE(t->received); - a = t->received->answer; - } else { - rcode = t->cached_rcode; - a = t->cached; - } + q->answer_protocol = c->scope->protocol; + q->answer_family = c->scope->family; - dns_answer_unref(answer); - answer = dns_answer_ref(a); + dns_search_domain_unref(q->answer_search_domain); + q->answer_search_domain = dns_search_domain_ref(c->search_domain); - scope = t->scope; - state = DNS_TRANSACTION_FAILURE; - continue; - } + dns_query_synthesize_reply(q, &state); + dns_query_complete(q, state); +} - if (state == DNS_TRANSACTION_NO_SERVERS && t->state != DNS_TRANSACTION_NO_SERVERS) - state = t->state; - } +void dns_query_ready(DnsQuery *q) { + + DnsQueryCandidate *bad = NULL, *c; + bool pending = false; - if (pending) { + assert(q); + assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); - /* If so far we weren't successful, and there's - * something still pending, then wait for it */ - if (state != DNS_TRANSACTION_SUCCESS) + /* Note that this call might invalidate the query. Callers + * should hence not attempt to access the query or transaction + * after calling this function, unless the block_ready + * counter was explicitly bumped before doing so. */ + + if (q->block_ready > 0) + return; + + LIST_FOREACH(candidates_by_query, c, q->candidates) { + DnsTransactionState state; + + state = dns_query_candidate_state(c); + switch (state) { + + case DNS_TRANSACTION_SUCCESS: + /* One of the transactions is successful, + * let's use it, and copy its data out */ + dns_query_accept(q, c); return; - /* If we already were successful, then only wait for - * other transactions on the same scope to finish. */ - SET_FOREACH(t, q->transactions, i) { - if (t->scope == scope && IN_SET(t->state, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_NULL)) - return; - } - } + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_NULL: + /* One of the transactions is still going on, let's maybe wait for it */ + pending = true; + break; - if (IN_SET(state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE)) { - q->answer = dns_answer_ref(answer); - q->answer_rcode = rcode; - q->answer_protocol = scope ? scope->protocol : _DNS_PROTOCOL_INVALID; - q->answer_family = scope ? scope->family : AF_UNSPEC; + default: + /* Any kind of failure */ + bad = c; + break; + } } - /* Try to synthesize a reply if we couldn't resolve something. */ - dns_query_synthesize_reply(q, &state); + if (pending) + return; - dns_query_complete(q, state); + dns_query_accept(q, bad); } -int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) { +static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) { _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL; int r; assert(q); + q->n_cname_redirects ++; if (q->n_cname_redirects > CNAME_MAX) return -ELOOP; @@ -848,14 +1100,66 @@ int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) { q->question = nq; nq = NULL; - q->n_cname_redirects++; - dns_query_stop(q); q->state = DNS_TRANSACTION_NULL; return 0; } +int dns_query_process_cname(DnsQuery *q) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL; + DnsResourceRecord *rr; + int r; + + assert(q); + + if (q->state != DNS_TRANSACTION_SUCCESS) + return 0; + + DNS_ANSWER_FOREACH(rr, q->answer) { + + r = dns_question_matches_rr(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + if (r < 0) + return r; + if (r > 0) + return 0; /* The answer matches directly, no need to follow cnames */ + + r = dns_question_matches_cname(q->question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + if (r < 0) + return r; + if (r > 0 && !cname) + cname = dns_resource_record_ref(rr); + } + + if (!cname) + return 0; /* No cname to follow */ + + if (q->flags & SD_RESOLVED_NO_CNAME) + return -ELOOP; + + /* OK, let's actually follow the CNAME */ + r = dns_query_cname_redirect(q, cname); + if (r < 0) + return r; + + /* Let's see if the answer can already answer the new + * redirected question */ + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(q->question, rr, NULL); + if (r < 0) + return r; + if (r > 0) + return 0; /* It can answer it, yay! */ + } + + /* OK, it cannot, let's begin with the new query */ + r = dns_query_go(q); + if (r < 0) + return r; + + return 1; /* We return > 0, if we restarted the query for a new cname */ +} + static int on_bus_track(sd_bus_track *t, void *userdata) { DnsQuery *q = userdata; diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index e7063d9678..a9d7904a8d 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -23,56 +23,88 @@ #include "sd-bus.h" + #include "set.h" +typedef struct DnsQueryCandidate DnsQueryCandidate; typedef struct DnsQuery DnsQuery; -#include "resolved-dns-question.h" #include "resolved-dns-answer.h" +#include "resolved-dns-question.h" #include "resolved-dns-stream.h" +#include "resolved-dns-search-domain.h" + +struct DnsQueryCandidate { + DnsQuery *query; + DnsScope *scope; + + DnsSearchDomain *search_domain; + + int error_code; + Set *transactions; + + LIST_FIELDS(DnsQueryCandidate, candidates_by_query); + LIST_FIELDS(DnsQueryCandidate, candidates_by_scope); +}; struct DnsQuery { Manager *manager; - DnsQuestion *question; + /* When resolving a service, we first create a TXT+SRV query, + * and then for the hostnames we discover auxiliary A+AAAA + * queries. This pointer always points from the auxiliary + * queries back to the TXT+SRV query. */ + DnsQuery *auxiliary_for; + LIST_HEAD(DnsQuery, auxiliary_queries); + unsigned n_auxiliary_queries; + int auxiliary_result; + + DnsQuestion *question; uint64_t flags; int ifindex; DnsTransactionState state; unsigned n_cname_redirects; + LIST_HEAD(DnsQueryCandidate, candidates); sd_event_source *timeout_event_source; /* Discovered data */ DnsAnswer *answer; - int answer_family; - DnsProtocol answer_protocol; int answer_rcode; + DnsProtocol answer_protocol; + int answer_family; + DnsSearchDomain *answer_search_domain; /* Bus client information */ sd_bus_message *request; int request_family; - const char *request_hostname; + bool request_address_valid; union in_addr_union request_address; + unsigned block_all_complete; /* Completion callback */ void (*complete)(DnsQuery* q); unsigned block_ready; - Set *transactions; - sd_bus_track *bus_track; LIST_FIELDS(DnsQuery, queries); + LIST_FIELDS(DnsQuery, auxiliary_queries); }; +DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c); +void dns_query_candidate_ready(DnsQueryCandidate *c); + int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question, int family, uint64_t flags); DnsQuery *dns_query_free(DnsQuery *q); +int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for); + int dns_query_go(DnsQuery *q); void dns_query_ready(DnsQuery *q); -int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname); +int dns_query_process_cname(DnsQuery *q); int dns_query_bus_track(DnsQuery *q, sd_bus_message *m); diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c index 48951221dc..3249448d3b 100644 --- a/src/resolve/resolved-dns-question.c +++ b/src/resolve/resolved-dns-question.c @@ -89,7 +89,7 @@ int dns_question_add(DnsQuestion *q, DnsResourceKey *key) { return 0; } -int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) { +int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) { unsigned i; int r; @@ -99,7 +99,7 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) { return 0; for (i = 0; i < q->n_keys; i++) { - r = dns_resource_key_match_rr(q->keys[i], rr); + r = dns_resource_key_match_rr(q->keys[i], rr, search_domain); if (r != 0) return r; } @@ -107,7 +107,7 @@ int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr) { return 0; } -int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) { +int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) { unsigned i; int r; @@ -117,7 +117,7 @@ int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) { return 0; for (i = 0; i < q->n_keys; i++) { - r = dns_resource_key_match_cname(q->keys[i], rr); + r = dns_resource_key_match_cname(q->keys[i], rr, search_domain); if (r != 0) return r; } @@ -125,7 +125,7 @@ int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) { return 0; } -int dns_question_is_valid(DnsQuestion *q) { +int dns_question_is_valid_for_query(DnsQuestion *q) { const char *name; unsigned i; int r; @@ -155,50 +155,6 @@ int dns_question_is_valid(DnsQuestion *q) { return 1; } -int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other) { - unsigned j; - int r; - - /* Checks if all keys in "other" are also contained in "q" */ - - if (!other) - return 1; - - for (j = 0; j < other->n_keys; j++) { - DnsResourceKey *b = other->keys[j]; - bool found = false; - unsigned i; - - if (!q) - return 0; - - for (i = 0; i < q->n_keys; i++) { - DnsResourceKey *a = q->keys[i]; - - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b)); - if (r < 0) - return r; - - if (r == 0) - continue; - - if (a->class != b->class && a->class != DNS_CLASS_ANY) - continue; - - if (a->type != b->type && a->type != DNS_TYPE_ANY) - continue; - - found = true; - break; - } - - if (!found) - return 0; - } - - return 1; -} - int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) { unsigned j; int r; @@ -251,6 +207,7 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, assert(cname); assert(ret); + assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)); if (!q) { n = dns_question_new(0); @@ -263,7 +220,22 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, } for (i = 0; i < q->n_keys; i++) { - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), cname->cname.name); + _cleanup_free_ char *destination = NULL; + const char *d; + + if (cname->key->type == DNS_TYPE_CNAME) + d = cname->cname.name; + else { + r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(q->keys[i]), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination); + if (r < 0) + return r; + if (r == 0) + continue; + + d = destination; + } + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), d); if (r < 0) return r; @@ -301,3 +273,131 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, return 1; } + +const char *dns_question_first_name(DnsQuestion *q) { + + if (!q) + return NULL; + + if (q->n_keys < 1) + return NULL; + + return DNS_RESOURCE_KEY_NAME(q->keys[0]); +} + +int dns_question_new_address(DnsQuestion **ret, int family, const char *name) { + _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL; + int r; + + assert(ret); + assert(name); + + if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) + return -EAFNOSUPPORT; + + q = dns_question_new(family == AF_UNSPEC ? 2 : 1); + if (!q) + return -ENOMEM; + + if (family != AF_INET6) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, name); + if (!key) + return -ENOMEM; + + r = dns_question_add(q, key); + if (r < 0) + return r; + } + + if (family != AF_INET) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, name); + if (!key) + return -ENOMEM; + + r = dns_question_add(q, key); + if (r < 0) + return r; + } + + *ret = q; + q = NULL; + + return 0; +} + +int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL; + _cleanup_free_ char *reverse = NULL; + int r; + + assert(ret); + assert(a); + + if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) + return -EAFNOSUPPORT; + + r = dns_name_reverse(family, a, &reverse); + if (r < 0) + return r; + + q = dns_question_new(1); + if (!q) + return -ENOMEM; + + key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse); + if (!key) + return -ENOMEM; + + reverse = NULL; + + r = dns_question_add(q, key); + if (r < 0) + return r; + + *ret = q; + q = NULL; + + return 0; +} + +int dns_question_new_service(DnsQuestion **ret, const char *name, bool with_txt) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL; + int r; + + assert(ret); + assert(name); + + q = dns_question_new(1 + with_txt); + if (!q) + return -ENOMEM; + + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_SRV, name); + if (!key) + return -ENOMEM; + + r = dns_question_add(q, key); + if (r < 0) + return r; + + if (with_txt) { + dns_resource_key_unref(key); + key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_TXT, name); + if (!key) + return -ENOMEM; + + r = dns_question_add(q, key); + if (r < 0) + return r; + } + + *ret = q; + q = NULL; + + return 0; +} diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h index 13cd1f20f3..e77116c03a 100644 --- a/src/resolve/resolved-dns-question.h +++ b/src/resolve/resolved-dns-question.h @@ -37,15 +37,28 @@ DnsQuestion *dns_question_new(unsigned n); DnsQuestion *dns_question_ref(DnsQuestion *q); DnsQuestion *dns_question_unref(DnsQuestion *q); +int dns_question_new_address(DnsQuestion **ret, int family, const char *name); +int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a); +int dns_question_new_service(DnsQuestion **ret, const char *name, bool with_txt); + int dns_question_add(DnsQuestion *q, DnsResourceKey *key); -int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr); -int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr); -int dns_question_is_valid(DnsQuestion *q); -int dns_question_is_superset(DnsQuestion *q, DnsQuestion *other); +int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain); +int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr, const char* search_domain); +int dns_question_is_valid_for_query(DnsQuestion *q); int dns_question_contains(DnsQuestion *a, DnsResourceKey *k); int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b); int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret); +const char *dns_question_first_name(DnsQuestion *q); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref); + +#define DNS_QUESTION_FOREACH(key, q) \ + for (unsigned _i = ({ \ + (key) = ((q) && (q)->n_keys > 0) ? (q)->keys[0] : NULL; \ + 0; \ + }); \ + (q) && ((_i) < (q)->n_keys); \ + _i++, (key) = (_i < (q)->n_keys ? (q)->keys[_i] : NULL)) diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index ba2ea686f3..4a1abb0cdc 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -57,10 +57,61 @@ DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) { } DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) { + int r; + assert(key); assert(cname); - return dns_resource_key_new(key->class, key->type, cname->cname.name); + assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)); + + if (cname->key->type == DNS_TYPE_CNAME) + return dns_resource_key_new(key->class, key->type, cname->cname.name); + else { + DnsResourceKey *k; + char *destination = NULL; + + r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination); + if (r < 0) + return NULL; + if (r == 0) + return dns_resource_key_ref((DnsResourceKey*) key); + + k = dns_resource_key_new_consume(key->class, key->type, destination); + if (!k) { + free(destination); + return NULL; + } + + return k; + } +} + +int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) { + DnsResourceKey *new_key; + char *joined; + int r; + + assert(ret); + assert(key); + assert(name); + + if (dns_name_is_root(name)) { + *ret = dns_resource_key_ref(key); + return 0; + } + + r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined); + if (r < 0) + return r; + + new_key = dns_resource_key_new_consume(key->class, key->type, joined); + if (!new_key) { + free(joined); + return -ENOMEM; + } + + *ret = new_key; + return 0; } DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) { @@ -122,30 +173,73 @@ int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) { return 1; } -int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) { +int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) { + int r; + assert(key); assert(rr); + /* Checks if an rr matches the specified key. If a search + * domain is specified, it will also be checked if the key + * with the search domain suffixed might match the RR. */ + if (rr->key->class != key->class && key->class != DNS_CLASS_ANY) return 0; if (rr->key->type != key->type && key->type != DNS_TYPE_ANY) return 0; - return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); + if (r != 0) + return r; + + if (search_domain) { + _cleanup_free_ char *joined = NULL; + + r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined); + if (r < 0) + return r; + + return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined); + } + + return 0; } -int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) { +int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain) { + int r; + assert(key); assert(rr); if (rr->key->class != key->class && key->class != DNS_CLASS_ANY) return 0; - if (rr->key->type != DNS_TYPE_CNAME) + if (rr->key->type == DNS_TYPE_CNAME) + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key)); + else if (rr->key->type == DNS_TYPE_DNAME) + r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(rr->key)); + else return 0; - return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key)); + if (r != 0) + return r; + + if (search_domain) { + _cleanup_free_ char *joined = NULL; + + r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined); + if (r < 0) + return r; + + if (rr->key->type == DNS_TYPE_CNAME) + return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(rr->key)); + else if (rr->key->type == DNS_TYPE_DNAME) + return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(rr->key)); + } + + return 0; + } static void dns_resource_key_hash_func(const void *i, struct siphash *state) { @@ -273,7 +367,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { case DNS_TYPE_TXT: case DNS_TYPE_SPF: - strv_free(rr->txt.strings); + dns_txt_item_free_all(rr->txt.items); break; case DNS_TYPE_SOA: @@ -430,7 +524,7 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor case DNS_TYPE_SPF: /* exactly the same as TXT */ case DNS_TYPE_TXT: - return strv_equal(a->txt.strings, b->txt.strings); + return dns_txt_item_equal(a->txt.items, b->txt.items); case DNS_TYPE_A: return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0; @@ -600,6 +694,43 @@ static char *format_types(Bitmap *types) { return strjoin("( ", str, " )", NULL); } +static char *format_txt(DnsTxtItem *first) { + DnsTxtItem *i; + size_t c = 1; + char *p, *s; + + LIST_FOREACH(items, i, first) + c += i->length * 4 + 3; + + p = s = new(char, c); + if (!s) + return NULL; + + LIST_FOREACH(items, i, first) { + size_t j; + + if (i != first) + *(p++) = ' '; + + *(p++) = '"'; + + for (j = 0; j < i->length; j++) { + if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) { + *(p++) = '\\'; + *(p++) = '0' + (i->data[j] / 100); + *(p++) = '0' + ((i->data[j] / 10) % 10); + *(p++) = '0' + (i->data[j] % 10); + } else + *(p++) = i->data[j]; + } + + *(p++) = '"'; + } + + *p = 0; + return s; +} + int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { _cleanup_free_ char *k = NULL, *t = NULL; char *s; @@ -642,14 +773,13 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { case DNS_TYPE_SPF: /* exactly the same as TXT */ case DNS_TYPE_TXT: - t = strv_join_quoted(rr->txt.strings); + t = format_txt(rr->txt.items); if (!t) return -ENOMEM; s = strjoin(k, " ", t, NULL); if (!s) return -ENOMEM; - break; case DNS_TYPE_A: { @@ -890,3 +1020,32 @@ int dns_class_from_string(const char *s, uint16_t *class) { return 0; } + +DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) { + DnsTxtItem *n; + + if (!i) + return NULL; + + n = i->items_next; + + free(i); + return dns_txt_item_free_all(n); +} + +bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) { + + if (!a != !b) + return false; + + if (!a) + return true; + + if (a->length != b->length) + return false; + + if (memcmp(a->data, b->data, a->length) != 0) + return false; + + return dns_txt_item_equal(a->items_next, b->items_next); +} diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 9e2207c0aa..f8066c06a6 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -24,12 +24,14 @@ #include <netinet/in.h> #include "bitmap.h" +#include "dns-type.h" #include "hashmap.h" #include "in-addr-util.h" -#include "dns-type.h" +#include "list.h" typedef struct DnsResourceKey DnsResourceKey; typedef struct DnsResourceRecord DnsResourceRecord; +typedef struct DnsTxtItem DnsTxtItem; /* DNS record classes, see RFC 1035 */ enum { @@ -45,6 +47,12 @@ struct DnsResourceKey { char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */ }; +struct DnsTxtItem { + size_t length; + LIST_FIELDS(DnsTxtItem, items); + uint8_t data[]; +}; + struct DnsResourceRecord { unsigned n_ref; DnsResourceKey *key; @@ -73,7 +81,7 @@ struct DnsResourceRecord { } hinfo; struct { - char **strings; + DnsTxtItem *items; } txt, spf; struct { @@ -178,13 +186,15 @@ static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) { DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name); DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key); +DnsResourceKey* dns_resource_key_new_dname(const DnsResourceKey *key); DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname); +int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name); DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name); DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key); DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key); int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b); -int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr); -int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr); +int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain); +int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain); int dns_resource_key_to_string(const DnsResourceKey *key, char **ret); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref); @@ -198,6 +208,9 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref); +DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); +bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); + const char *dns_class_to_string(uint16_t type); int dns_class_from_string(const char *name, uint16_t *class); diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index b15370b017..fc4ae57ce0 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -69,18 +69,12 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int return 0; } -DnsScope* dns_scope_free(DnsScope *s) { - DnsTransaction *t; - DnsResourceRecord *rr; - - if (!s) - return NULL; - - log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family)); +static void dns_scope_abort_transactions(DnsScope *s) { + assert(s); - dns_scope_llmnr_membership(s, false); + while (s->transactions) { + DnsTransaction *t = s->transactions; - while ((t = hashmap_steal_first(s->transactions))) { /* Abort the transaction, but make sure it is not * freed while we still look at it */ @@ -90,8 +84,23 @@ DnsScope* dns_scope_free(DnsScope *s) { dns_transaction_free(t); } +} - hashmap_free(s->transactions); +DnsScope* dns_scope_free(DnsScope *s) { + DnsResourceRecord *rr; + + if (!s) + return NULL; + + log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family)); + + dns_scope_llmnr_membership(s, false); + dns_scope_abort_transactions(s); + + while (s->query_candidates) + dns_query_candidate_free(s->query_candidates); + + hashmap_free(s->transactions_by_key); while ((rr = ordered_hashmap_steal_first(s->conflict_queue))) dns_resource_record_unref(rr); @@ -103,7 +112,6 @@ DnsScope* dns_scope_free(DnsScope *s) { dns_zone_flush(&s->zone); LIST_REMOVE(scopes, s->manager->dns_scopes, s); - strv_free(s->domains); free(s); return NULL; @@ -136,11 +144,11 @@ void dns_scope_next_dns_server(DnsScope *s) { void dns_scope_packet_received(DnsScope *s, usec_t rtt) { assert(s); - if (rtt > s->max_rtt) { - s->max_rtt = rtt; - s->resend_timeout = MIN(MAX(MULTICAST_RESEND_TIMEOUT_MIN_USEC, s->max_rtt * 2), - MULTICAST_RESEND_TIMEOUT_MAX_USEC); - } + if (rtt <= s->max_rtt) + return; + + s->max_rtt = rtt; + s->resend_timeout = MIN(MAX(MULTICAST_RESEND_TIMEOUT_MIN_USEC, s->max_rtt * 2), MULTICAST_RESEND_TIMEOUT_MAX_USEC); } void dns_scope_packet_lost(DnsScope *s, usec_t usec) { @@ -323,7 +331,7 @@ int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *add } DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) { - char **i; + DnsSearchDomain *d; assert(s); assert(domain); @@ -334,7 +342,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0) return DNS_SCOPE_NO; - if (dns_name_root(domain) != 0) + if (dns_name_is_root(domain)) return DNS_SCOPE_NO; /* Never resolve any loopback hostname or IP address via DNS, @@ -345,15 +353,22 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co dns_name_equal(domain, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) return DNS_SCOPE_NO; - STRV_FOREACH(i, s->domains) - if (dns_name_endswith(domain, *i) > 0) + /* Always honour search domains for routing queries. Note that + * we return DNS_SCOPE_YES here, rather than just + * DNS_SCOPE_MAYBE, which means wildcard scopes won't be + * considered anymore. */ + LIST_FOREACH(domains, d, dns_scope_get_search_domains(s)) + if (dns_name_endswith(domain, d->name) > 0) return DNS_SCOPE_YES; switch (s->protocol) { + case DNS_PROTOCOL_DNS: - if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && - dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0 && - dns_name_single_label(domain) == 0) + + if ((!dns_name_is_single_label(domain) || + (!(flags & SD_RESOLVED_NO_SEARCH) && dns_scope_has_search_domains(s))) && + dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && + dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0) return DNS_SCOPE_MAYBE; return DNS_SCOPE_NO; @@ -371,7 +386,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co case DNS_PROTOCOL_LLMNR: if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) || - (dns_name_single_label(domain) > 0 && /* only resolve single label names via LLMNR */ + (dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */ !is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */ return DNS_SCOPE_MAYBE; @@ -543,6 +558,7 @@ static void dns_scope_verify_conflicts(DnsScope *s, DnsPacket *p) { void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; + DnsResourceKey *key = NULL; bool tentative = false; int r, fd; @@ -576,7 +592,10 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { return; } - r = dns_zone_lookup(&s->zone, p->question, &answer, &soa, &tentative); + assert(p->question->n_keys == 1); + key = p->question->keys[0]; + + r = dns_zone_lookup(&s->zone, key, &answer, &soa, &tentative); if (r < 0) { log_debug_errno(r, "Failed to lookup key: %m"); return; @@ -634,7 +653,7 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, /* Try to find an ongoing transaction that is a equal to the * specified question */ - t = hashmap_get(scope->transactions, key); + t = hashmap_get(scope->transactions_by_key, key); if (!t) return NULL; @@ -642,7 +661,7 @@ DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, * data instead of a real packet, if that's requested. */ if (!cache_ok && IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_FAILURE) && - !t->received) + t->answer_source != DNS_TRANSACTION_NETWORK) return NULL; return t; @@ -846,3 +865,45 @@ void dns_scope_dump(DnsScope *s, FILE *f) { dns_cache_dump(&s->cache, f); } } + +DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) { + assert(s); + + /* Returns the list of *local* search domains -- not the + * global ones. */ + + if (s->protocol != DNS_PROTOCOL_DNS) + return NULL; + + if (s->link) + return s->link->search_domains; + + return NULL; +} + +bool dns_scope_has_search_domains(DnsScope *s) { + assert(s); + + /* Tests if there are *any* search domains suitable for this + * scope. This means either local or global ones */ + + if (s->protocol != DNS_PROTOCOL_DNS) + return false; + + if (s->manager->search_domains) + return true; + + if (s->link && s->link->search_domains) + return true; + + return false; +} + +bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) { + assert(s); + + if (s->protocol != DNS_PROTOCOL_DNS) + return false; + + return dns_name_is_single_label(name); +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index b75f212897..7876410b7d 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -25,9 +25,9 @@ typedef struct DnsScope DnsScope; -#include "resolved-dns-server.h" -#include "resolved-dns-packet.h" #include "resolved-dns-cache.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-server.h" #include "resolved-dns-zone.h" #include "resolved-link.h" @@ -47,8 +47,6 @@ struct DnsScope { Link *link; - char **domains; - DnsCache cache; DnsZone zone; @@ -60,7 +58,18 @@ struct DnsScope { usec_t resend_timeout; usec_t max_rtt; - Hashmap *transactions; + LIST_HEAD(DnsQueryCandidate, query_candidates); + + /* Note that we keep track of ongoing transactions in two + * ways: once in a hashmap, indexed by the rr key, and once in + * a linked list. We use the hashmap to quickly find + * transactions we can reuse for a key. But note that there + * might be multiple transactions for the same key (because + * the zone probing can't reuse a transaction answered from + * the zone or the cache), and the hashmap only tracks the + * most recent entry. */ + Hashmap *transactions_by_key; + LIST_HEAD(DnsTransaction, transactions); LIST_FIELDS(DnsScope, scopes); }; @@ -91,3 +100,8 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr); void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p); void dns_scope_dump(DnsScope *s, FILE *f); + +DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s); +bool dns_scope_has_search_domains(DnsScope *s); + +bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name); diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c new file mode 100644 index 0000000000..f9d966abb1 --- /dev/null +++ b/src/resolve/resolved-dns-search-domain.c @@ -0,0 +1,232 @@ +/*-*- 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 "dns-domain.h" +#include "resolved-dns-search-domain.h" + +int dns_search_domain_new( + Manager *m, + DnsSearchDomain **ret, + DnsSearchDomainType type, + Link *l, + const char *name) { + + _cleanup_free_ char *normalized = NULL; + DnsSearchDomain *d; + int r; + + assert(m); + assert((type == DNS_SEARCH_DOMAIN_LINK) == !!l); + assert(name); + + r = dns_name_normalize(name, &normalized); + if (r < 0) + return r; + + if (dns_name_is_root(normalized)) + return -EINVAL; + + if (l) { + if (l->n_search_domains >= LINK_SEARCH_DOMAINS_MAX) + return -E2BIG; + } else { + if (m->n_search_domains >= MANAGER_SEARCH_DOMAINS_MAX) + return -E2BIG; + } + + d = new0(DnsSearchDomain, 1); + if (!d) + return -ENOMEM; + + d->n_ref = 1; + d->manager = m; + d->type = type; + d->name = normalized; + normalized = NULL; + + switch (type) { + + case DNS_SEARCH_DOMAIN_LINK: + d->link = l; + LIST_APPEND(domains, l->search_domains, d); + l->n_search_domains++; + break; + + case DNS_SERVER_SYSTEM: + LIST_APPEND(domains, m->search_domains, d); + m->n_search_domains++; + break; + + default: + assert_not_reached("Unknown search domain type"); + } + + d->linked = true; + + if (ret) + *ret = d; + + return 0; +} + +DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d) { + if (!d) + return NULL; + + assert(d->n_ref > 0); + d->n_ref++; + + return d; +} + +DnsSearchDomain* dns_search_domain_unref(DnsSearchDomain *d) { + if (!d) + return NULL; + + assert(d->n_ref > 0); + d->n_ref--; + + if (d->n_ref > 0) + return NULL; + + free(d->name); + free(d); + + return NULL; +} + +void dns_search_domain_unlink(DnsSearchDomain *d) { + assert(d); + assert(d->manager); + + if (!d->linked) + return; + + switch (d->type) { + + case DNS_SEARCH_DOMAIN_LINK: + assert(d->link); + assert(d->link->n_search_domains > 0); + LIST_REMOVE(domains, d->link->search_domains, d); + d->link->n_search_domains--; + break; + + case DNS_SEARCH_DOMAIN_SYSTEM: + assert(d->manager->n_search_domains > 0); + LIST_REMOVE(domains, d->manager->search_domains, d); + d->manager->n_search_domains--; + break; + } + + d->linked = false; + + dns_search_domain_unref(d); +} + +void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d) { + DnsSearchDomain *tail; + + assert(d); + + if (!d->marked) + return; + + d->marked = false; + + if (!d->linked || !d->domains_next) + return; + + switch (d->type) { + + case DNS_SEARCH_DOMAIN_LINK: + assert(d->link); + LIST_FIND_TAIL(domains, d, tail); + LIST_REMOVE(domains, d->link->search_domains, d); + LIST_INSERT_AFTER(domains, d->link->search_domains, tail, d); + break; + + case DNS_SEARCH_DOMAIN_SYSTEM: + LIST_FIND_TAIL(domains, d, tail); + LIST_REMOVE(domains, d->manager->search_domains, d); + LIST_INSERT_AFTER(domains, d->manager->search_domains, tail, d); + break; + + default: + assert_not_reached("Unknown search domain type"); + } +} + +void dns_search_domain_unlink_all(DnsSearchDomain *first) { + DnsSearchDomain *next; + + if (!first) + return; + + next = first->domains_next; + dns_search_domain_unlink(first); + + dns_search_domain_unlink_all(next); +} + +void dns_search_domain_unlink_marked(DnsSearchDomain *first) { + DnsSearchDomain *next; + + if (!first) + return; + + next = first->domains_next; + + if (first->marked) + dns_search_domain_unlink(first); + + dns_search_domain_unlink_marked(next); +} + +void dns_search_domain_mark_all(DnsSearchDomain *first) { + if (!first) + return; + + first->marked = true; + dns_search_domain_mark_all(first->domains_next); +} + +int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDomain **ret) { + DnsSearchDomain *d; + int r; + + assert(name); + assert(ret); + + LIST_FOREACH(domains, d, first) { + + r = dns_name_equal(name, d->name); + if (r < 0) + return r; + if (r > 0) { + *ret = d; + return 1; + } + } + + *ret = NULL; + return 0; +} diff --git a/src/resolve/resolved-dns-search-domain.h b/src/resolve/resolved-dns-search-domain.h new file mode 100644 index 0000000000..2e0af31dda --- /dev/null +++ b/src/resolve/resolved-dns-search-domain.h @@ -0,0 +1,75 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + 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 "macro.h" + +typedef struct DnsSearchDomain DnsSearchDomain; + +typedef enum DnsSearchDomainType { + DNS_SEARCH_DOMAIN_SYSTEM, + DNS_SEARCH_DOMAIN_LINK, +} DnsSearchDomainType; + +#include "resolved-link.h" +#include "resolved-manager.h" + +struct DnsSearchDomain { + Manager *manager; + + unsigned n_ref; + + DnsSearchDomainType type; + Link *link; + + char *name; + + bool marked:1; + + bool linked:1; + LIST_FIELDS(DnsSearchDomain, domains); +}; + +int dns_search_domain_new( + Manager *m, + DnsSearchDomain **ret, + DnsSearchDomainType type, + Link *link, + const char *name); + +DnsSearchDomain* dns_search_domain_ref(DnsSearchDomain *d); +DnsSearchDomain* dns_search_domain_unref(DnsSearchDomain *d); + +void dns_search_domain_unlink(DnsSearchDomain *d); +void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d); + +void dns_search_domain_unlink_all(DnsSearchDomain *first); +void dns_search_domain_unlink_marked(DnsSearchDomain *first); +void dns_search_domain_mark_all(DnsSearchDomain *first); + +int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDomain **ret); + +static inline const char* DNS_SEARCH_DOMAIN_NAME(DnsSearchDomain *d) { + return d ? d->name : NULL; +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(DnsSearchDomain*, dns_search_domain_unref); diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index e803f635ab..0ebd22fe22 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -21,7 +21,9 @@ #include "alloc-util.h" #include "resolved-dns-server.h" +#include "resolved-resolv-conf.h" #include "siphash24.h" +#include "string-util.h" /* After how much time to repeat classic DNS requests */ #define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC) @@ -35,36 +37,57 @@ int dns_server_new( int family, const union in_addr_union *in_addr) { - DnsServer *s, *tail; + DnsServer *s; assert(m); assert((type == DNS_SERVER_LINK) == !!l); assert(in_addr); + if (!IN_SET(family, AF_INET, AF_INET6)) + return -EAFNOSUPPORT; + + if (l) { + if (l->n_dns_servers >= LINK_DNS_SERVERS_MAX) + return -E2BIG; + } else { + if (m->n_dns_servers >= MANAGER_DNS_SERVERS_MAX) + return -E2BIG; + } + s = new0(DnsServer, 1); if (!s) return -ENOMEM; s->n_ref = 1; + s->manager = m; s->type = type; s->family = family; s->address = *in_addr; s->resend_timeout = DNS_TIMEOUT_MIN_USEC; - if (type == DNS_SERVER_LINK) { - LIST_FIND_TAIL(servers, l->dns_servers, tail); - LIST_INSERT_AFTER(servers, l->dns_servers, tail, s); + switch (type) { + + case DNS_SERVER_LINK: s->link = l; - } else if (type == DNS_SERVER_SYSTEM) { - LIST_FIND_TAIL(servers, m->dns_servers, tail); - LIST_INSERT_AFTER(servers, m->dns_servers, tail, s); - } else if (type == DNS_SERVER_FALLBACK) { - LIST_FIND_TAIL(servers, m->fallback_dns_servers, tail); - LIST_INSERT_AFTER(servers, m->fallback_dns_servers, tail, s); - } else + LIST_APPEND(servers, l->dns_servers, s); + l->n_dns_servers++; + break; + + case DNS_SERVER_SYSTEM: + LIST_APPEND(servers, m->dns_servers, s); + m->n_dns_servers++; + break; + + case DNS_SERVER_FALLBACK: + LIST_APPEND(servers, m->fallback_dns_servers, s); + m->n_dns_servers++; + break; + + default: assert_not_reached("Unknown server type"); + } - s->manager = m; + s->linked = true; /* A new DNS server that isn't fallback is added and the one * we used so far was a fallback one? Then let's try to pick @@ -85,56 +108,127 @@ DnsServer* dns_server_ref(DnsServer *s) { return NULL; assert(s->n_ref > 0); - s->n_ref ++; return s; } -static DnsServer* dns_server_free(DnsServer *s) { +DnsServer* dns_server_unref(DnsServer *s) { if (!s) return NULL; + assert(s->n_ref > 0); + s->n_ref --; + + if (s->n_ref > 0) + return NULL; + + free(s); + return NULL; +} + +void dns_server_unlink(DnsServer *s) { + assert(s); + assert(s->manager); + + /* This removes the specified server from the linked list of + * servers, but any server might still stay around if it has + * refs, for example from an ongoing transaction. */ + + if (!s->linked) + return; + + switch (s->type) { + + case DNS_SERVER_LINK: + assert(s->link); + assert(s->link->n_dns_servers > 0); + LIST_REMOVE(servers, s->link->dns_servers, s); + break; + + case DNS_SERVER_SYSTEM: + assert(s->manager->n_dns_servers > 0); + LIST_REMOVE(servers, s->manager->dns_servers, s); + s->manager->n_dns_servers--; + break; + + case DNS_SERVER_FALLBACK: + assert(s->manager->n_dns_servers > 0); + LIST_REMOVE(servers, s->manager->fallback_dns_servers, s); + s->manager->n_dns_servers--; + break; + } + + s->linked = false; + if (s->link && s->link->current_dns_server == s) link_set_dns_server(s->link, NULL); - if (s->manager && s->manager->current_dns_server == s) + if (s->manager->current_dns_server == s) manager_set_dns_server(s->manager, NULL); - free(s); - - return NULL; + dns_server_unref(s); } -DnsServer* dns_server_unref(DnsServer *s) { - if (!s) - return NULL; +void dns_server_move_back_and_unmark(DnsServer *s) { + DnsServer *tail; - assert(s->n_ref > 0); + assert(s); - if (s->n_ref == 1) - dns_server_free(s); - else - s->n_ref --; + if (!s->marked) + return; - return NULL; + s->marked = false; + + if (!s->linked || !s->servers_next) + return; + + /* Move us to the end of the list, so that the order is + * strictly kept, if we are not at the end anyway. */ + + switch (s->type) { + + case DNS_SERVER_LINK: + assert(s->link); + LIST_FIND_TAIL(servers, s, tail); + LIST_REMOVE(servers, s->link->dns_servers, s); + LIST_INSERT_AFTER(servers, s->link->dns_servers, tail, s); + break; + + case DNS_SERVER_SYSTEM: + LIST_FIND_TAIL(servers, s, tail); + LIST_REMOVE(servers, s->manager->dns_servers, s); + LIST_INSERT_AFTER(servers, s->manager->dns_servers, tail, s); + break; + + case DNS_SERVER_FALLBACK: + LIST_FIND_TAIL(servers, s, tail); + LIST_REMOVE(servers, s->manager->fallback_dns_servers, s); + LIST_INSERT_AFTER(servers, s->manager->fallback_dns_servers, tail, s); + break; + + default: + assert_not_reached("Unknown server type"); + } } void dns_server_packet_received(DnsServer *s, usec_t rtt) { assert(s); - if (rtt > s->max_rtt) { - s->max_rtt = rtt; - s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), - DNS_TIMEOUT_MAX_USEC); - } + if (rtt <= s->max_rtt) + return; + + s->max_rtt = rtt; + s->resend_timeout = MIN(MAX(DNS_TIMEOUT_MIN_USEC, s->max_rtt * 2), DNS_TIMEOUT_MAX_USEC); } void dns_server_packet_lost(DnsServer *s, usec_t usec) { assert(s); - if (s->resend_timeout <= usec) - s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC); + if (s->resend_timeout > usec) + return; + + s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC); } static void dns_server_hash_func(const void *p, struct siphash *state) { @@ -161,3 +255,140 @@ const struct hash_ops dns_server_hash_ops = { .hash = dns_server_hash_func, .compare = dns_server_compare_func }; + +void dns_server_unlink_all(DnsServer *first) { + DnsServer *next; + + if (!first) + return; + + next = first->servers_next; + dns_server_unlink(first); + + dns_server_unlink_all(next); +} + +void dns_server_unlink_marked(DnsServer *first) { + DnsServer *next; + + if (!first) + return; + + next = first->servers_next; + + if (first->marked) + dns_server_unlink(first); + + dns_server_unlink_marked(next); +} + +void dns_server_mark_all(DnsServer *first) { + if (!first) + return; + + first->marked = true; + dns_server_mark_all(first->servers_next); +} + +DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr) { + DnsServer *s; + + LIST_FOREACH(servers, s, first) + if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0) + return s; + + return NULL; +} + +DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t) { + assert(m); + + switch (t) { + + case DNS_SERVER_SYSTEM: + return m->dns_servers; + + case DNS_SERVER_FALLBACK: + return m->fallback_dns_servers; + + default: + return NULL; + } +} + +DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) { + assert(m); + + if (m->current_dns_server == s) + return s; + + if (s) { + _cleanup_free_ char *ip = NULL; + + in_addr_to_string(s->family, &s->address, &ip); + log_info("Switching to system DNS server %s.", strna(ip)); + } + + dns_server_unref(m->current_dns_server); + m->current_dns_server = dns_server_ref(s); + + if (m->unicast_scope) + dns_cache_flush(&m->unicast_scope->cache); + + return s; +} + +DnsServer *manager_get_dns_server(Manager *m) { + Link *l; + assert(m); + + /* Try to read updates resolv.conf */ + manager_read_resolv_conf(m); + + /* If no DNS server was chose so far, pick the first one */ + if (!m->current_dns_server) + manager_set_dns_server(m, m->dns_servers); + + if (!m->current_dns_server) { + bool found = false; + Iterator i; + + /* No DNS servers configured, let's see if there are + * any on any links. If not, we use the fallback + * servers */ + + HASHMAP_FOREACH(l, m->links, i) + if (l->dns_servers) { + found = true; + break; + } + + if (!found) + manager_set_dns_server(m, m->fallback_dns_servers); + } + + return m->current_dns_server; +} + +void manager_next_dns_server(Manager *m) { + assert(m); + + /* If there's currently no DNS server set, then the next + * manager_get_dns_server() will find one */ + if (!m->current_dns_server) + return; + + /* Change to the next one, but make sure to follow the linked + * list only if the server is still linked. */ + if (m->current_dns_server->linked && m->current_dns_server->servers_next) { + manager_set_dns_server(m, m->current_dns_server->servers_next); + return; + } + + /* If there was no next one, then start from the beginning of + * the list */ + if (m->current_dns_server->type == DNS_SERVER_FALLBACK) + manager_set_dns_server(m, m->fallback_dns_servers); + else + manager_set_dns_server(m, m->dns_servers); +} diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 10111fd6bd..3a78d4a3b5 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -24,7 +24,6 @@ #include "in-addr-util.h" typedef struct DnsServer DnsServer; -typedef enum DnsServerSource DnsServerSource; typedef enum DnsServerType { DNS_SERVER_SYSTEM, @@ -32,6 +31,7 @@ typedef enum DnsServerType { DNS_SERVER_LINK, } DnsServerType; +#include "resolved-manager.h" #include "resolved-link.h" struct DnsServer { @@ -40,7 +40,6 @@ struct DnsServer { unsigned n_ref; DnsServerType type; - Link *link; int family; @@ -51,23 +50,40 @@ struct DnsServer { bool marked:1; + /* If linked is set, then this server appears in the servers linked list */ + bool linked:1; LIST_FIELDS(DnsServer, servers); }; int dns_server_new( Manager *m, - DnsServer **s, + DnsServer **ret, DnsServerType type, - Link *l, + Link *link, int family, const union in_addr_union *address); DnsServer* dns_server_ref(DnsServer *s); DnsServer* dns_server_unref(DnsServer *s); +void dns_server_unlink(DnsServer *s); +void dns_server_move_back_and_unmark(DnsServer *s); + void dns_server_packet_received(DnsServer *s, usec_t rtt); void dns_server_packet_lost(DnsServer *s, usec_t usec); +DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr); + +void dns_server_unlink_all(DnsServer *first); +void dns_server_unlink_marked(DnsServer *first); +void dns_server_mark_all(DnsServer *first); + +DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t); + +DnsServer *manager_set_dns_server(Manager *m, DnsServer *s); +DnsServer *manager_get_dns_server(Manager *m); +void manager_next_dns_server(Manager *m); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref); extern const struct hash_ops dns_server_hash_ops; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 6545f6cd8a..8c4f23a4da 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -29,7 +29,7 @@ #include "string-table.h" DnsTransaction* dns_transaction_free(DnsTransaction *t) { - DnsQuery *q; + DnsQueryCandidate *c; DnsZoneItem *i; if (!t) @@ -39,7 +39,8 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_packet_unref(t->sent); dns_packet_unref(t->received); - dns_answer_unref(t->cached); + + dns_answer_unref(t->answer); sd_event_source_unref(t->dns_udp_event_source); safe_close(t->dns_udp_fd); @@ -48,7 +49,8 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_stream_free(t->stream); if (t->scope) { - hashmap_remove(t->scope->transactions, t->key); + hashmap_remove_value(t->scope->transactions_by_key, t->key, t); + LIST_REMOVE(transactions_by_scope, t->scope->transactions, t); if (t->id != 0) hashmap_remove(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id)); @@ -56,9 +58,10 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_resource_key_unref(t->key); - while ((q = set_steal_first(t->queries))) - set_remove(q->transactions, t); - set_free(t->queries); + while ((c = set_steal_first(t->query_candidates))) + set_remove(c->transactions, t); + + set_free(t->query_candidates); while ((i = set_steal_first(t->zone_items))) i->probe_transaction = NULL; @@ -76,7 +79,7 @@ void dns_transaction_gc(DnsTransaction *t) { if (t->block_gc > 0) return; - if (set_isempty(t->queries) && set_isempty(t->zone_items)) + if (set_isempty(t->query_candidates) && set_isempty(t->zone_items)) dns_transaction_free(t); } @@ -92,7 +95,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) if (r < 0) return r; - r = hashmap_ensure_allocated(&s->transactions, &dns_resource_key_hash_ops); + r = hashmap_ensure_allocated(&s->transactions_by_key, &dns_resource_key_hash_ops); if (r < 0) return r; @@ -101,6 +104,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) return -ENOMEM; t->dns_udp_fd = -1; + t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID; t->key = dns_resource_key_ref(key); /* Find a fresh, unused transaction id */ @@ -115,12 +119,13 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) return r; } - r = hashmap_put(s->transactions, t->key, t); + r = hashmap_replace(s->transactions_by_key, t->key, t); if (r < 0) { hashmap_remove(s->manager->dns_transactions, UINT_TO_PTR(t->id)); return r; } + LIST_PREPEND(transactions_by_scope, s->transactions, t); t->scope = s; if (ret) @@ -136,6 +141,9 @@ static void dns_transaction_stop(DnsTransaction *t) { t->timeout_event_source = sd_event_source_unref(t->timeout_event_source); t->stream = dns_stream_free(t->stream); + + /* Note that we do not drop the UDP socket here, as we want to + * reuse it to repeat the interaction. */ } static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { @@ -181,7 +189,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { } void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { - DnsQuery *q; + DnsQueryCandidate *c; DnsZoneItem *z; Iterator i; @@ -192,11 +200,12 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { * should hence not attempt to access the query or transaction * after calling this function. */ - log_debug("Transaction on scope %s on %s/%s now complete with <%s>", + log_debug("Transaction on scope %s on %s/%s now complete with <%s> from %s", dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->name : "*", t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family), - dns_transaction_state_to_string(state)); + dns_transaction_state_to_string(state), + t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source)); t->state = state; @@ -205,8 +214,8 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { /* Notify all queries that are interested, but make sure the * transaction isn't freed while we are still looking at it */ t->block_gc++; - SET_FOREACH(q, t->queries, i) - dns_query_ready(q); + SET_FOREACH(c, t->query_candidates, i) + dns_query_candidate_ready(c); SET_FOREACH(z, t->zone_items, i) dns_zone_item_ready(z); t->block_gc--; @@ -314,6 +323,8 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { dns_server_unref(t->server); t->server = dns_server_ref(server); t->received = dns_packet_unref(t->received); + t->answer = dns_answer_unref(t->answer); + t->answer_rcode = 0; t->stream->complete = on_stream_complete; t->stream->transaction = t; @@ -385,6 +396,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { t->received = dns_packet_ref(p); } + t->answer_source = DNS_TRANSACTION_NETWORK; + if (p->ipproto == IPPROTO_TCP) { if (DNS_PACKET_TC(p)) { /* Truncated via TCP? Somebody must be fucking with us */ @@ -453,6 +466,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { return; } + /* Install the answer as answer to the transaction */ + dns_answer_unref(t->answer); + t->answer = dns_answer_ref(p->answer); + t->answer_rcode = DNS_PACKET_RCODE(p); + /* Only consider responses with equivalent query section to the request */ if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); @@ -460,7 +478,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */ - dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); + if (DNS_PACKET_SHALL_CACHE(p)) + dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS) dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); @@ -623,8 +642,24 @@ int dns_transaction_go(DnsTransaction *t) { t->n_attempts++; t->start_usec = ts; t->received = dns_packet_unref(t->received); - t->cached = dns_answer_unref(t->cached); - t->cached_rcode = 0; + t->answer = dns_answer_unref(t->answer); + t->answer_rcode = 0; + t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID; + + /* Check the zone, but obly if this transaction is not used + * for probing or verifying a zone item. */ + if (set_isempty(t->zone_items)) { + + r = dns_zone_lookup(&t->scope->zone, t->key, &t->answer, NULL, NULL); + if (r < 0) + return r; + if (r > 0) { + t->answer_rcode = DNS_RCODE_SUCCESS; + t->answer_source = DNS_TRANSACTION_ZONE; + dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); + return 0; + } + } /* Check the cache, but only if this transaction is not used * for probing or verifying a zone item. */ @@ -638,11 +673,12 @@ int dns_transaction_go(DnsTransaction *t) { /* Let's then prune all outdated entries */ dns_cache_prune(&t->scope->cache); - r = dns_cache_lookup(&t->scope->cache, t->key, &t->cached_rcode, &t->cached); + r = dns_cache_lookup(&t->scope->cache, t->key, &t->answer_rcode, &t->answer); if (r < 0) return r; if (r > 0) { - if (t->cached_rcode == DNS_RCODE_SUCCESS) + t->answer_source = DNS_TRANSACTION_CACHE; + if (t->answer_rcode == DNS_RCODE_SUCCESS) dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); else dns_transaction_complete(t, DNS_TRANSACTION_FAILURE); @@ -745,3 +781,10 @@ static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] [DNS_TRANSACTION_ABORTED] = "aborted", }; DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState); + +static const char* const dns_transaction_source_table[_DNS_TRANSACTION_SOURCE_MAX] = { + [DNS_TRANSACTION_NETWORK] = "network", + [DNS_TRANSACTION_CACHE] = "cache", + [DNS_TRANSACTION_ZONE] = "zone", +}; +DEFINE_STRING_TABLE_LOOKUP(dns_transaction_source, DnsTransactionSource); diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index acf6a6f651..ee80dcf5a9 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -23,6 +23,7 @@ typedef struct DnsTransaction DnsTransaction; typedef enum DnsTransactionState DnsTransactionState; +typedef enum DnsTransactionSource DnsTransactionSource; enum DnsTransactionState { DNS_TRANSACTION_NULL, @@ -39,10 +40,18 @@ enum DnsTransactionState { _DNS_TRANSACTION_STATE_INVALID = -1 }; -#include "resolved-dns-scope.h" +enum DnsTransactionSource { + DNS_TRANSACTION_NETWORK, + DNS_TRANSACTION_CACHE, + DNS_TRANSACTION_ZONE, + _DNS_TRANSACTION_SOURCE_MAX, + _DNS_TRANSACTION_SOURCE_INVALID = -1 +}; + +#include "resolved-dns-answer.h" #include "resolved-dns-packet.h" #include "resolved-dns-question.h" -#include "resolved-dns-answer.h" +#include "resolved-dns-scope.h" struct DnsTransaction { DnsScope *scope; @@ -55,8 +64,10 @@ struct DnsTransaction { bool initial_jitter; DnsPacket *sent, *received; - DnsAnswer *cached; - int cached_rcode; + + DnsAnswer *answer; + int answer_rcode; + DnsTransactionSource answer_source; usec_t start_usec; sd_event_source *timeout_event_source; @@ -71,9 +82,10 @@ struct DnsTransaction { /* TCP connection logic, if we need it */ DnsStream *stream; - /* Queries this transaction is referenced by and that shall be - * notified about this specific transaction completing. */ - Set *queries; + /* Query candidates this transaction is referenced by and that + * shall be notified about this specific transaction + * completing. */ + Set *query_candidates; /* Zone items this transaction is referenced by and that shall * be notified about completion. */ @@ -96,6 +108,9 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state); const char* dns_transaction_state_to_string(DnsTransactionState p) _const_; DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; +const char* dns_transaction_source_to_string(DnsTransactionSource p) _const_; +DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_; + /* LLMNR Jitter interval, see RFC 4795 Section 7 */ #define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC) @@ -105,4 +120,4 @@ DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; /* Maximum attempts to send LLMNR requests, see RFC 4795 Section 2.7 */ #define LLMNR_TRANSACTION_ATTEMPTS_MAX 3 -#define TRANSACTION_ATTEMPTS_MAX(p) (p == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX) +#define TRANSACTION_ATTEMPTS_MAX(p) ((p) == DNS_PROTOCOL_LLMNR ? LLMNR_TRANSACTION_ATTEMPTS_MAX : DNS_TRANSACTION_ATTEMPTS_MAX) diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 48dcf76daa..493d11dd14 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -283,97 +283,76 @@ int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) { return 0; } -int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL, *soa = NULL; - unsigned i, n_answer = 0, n_soa = 0; - bool tentative = true; + unsigned n_answer = 0; + DnsZoneItem *j, *first; + bool tentative = true, need_soa = false; int r; assert(z); - assert(q); + assert(key); assert(ret_answer); - assert(ret_soa); - if (q->n_keys <= 0) { - *ret_answer = NULL; - *ret_soa = NULL; - - if (ret_tentative) - *ret_tentative = false; + /* First iteration, count what we have */ - return 0; - } + if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { + bool found = false, added = false; + int k; - /* First iteration, count what we have */ - for (i = 0; i < q->n_keys; i++) { - DnsZoneItem *j, *first; + /* If this is a generic match, then we have to + * go through the list by the name and look + * for everything manually */ - if (q->keys[i]->type == DNS_TYPE_ANY || - q->keys[i]->class == DNS_CLASS_ANY) { - bool found = false, added = false; - int k; + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - /* If this is a generic match, then we have to - * go through the list by the name and look - * for everything manually */ + found = true; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; + k = dns_resource_key_match_rr(key, j->rr, NULL); + if (k < 0) + return k; + if (k > 0) { + n_answer++; + added = true; + } - found = true; + } - k = dns_resource_key_match_rr(q->keys[i], j->rr); - if (k < 0) - return k; - if (k > 0) { - n_answer++; - added = true; - } + if (found && !added) + need_soa = true; - } + } else { + bool found = false; - if (found && !added) - n_soa++; + /* If this is a specific match, then look for + * the right key immediately */ - } else { - bool found = false; + first = hashmap_get(z->by_key, key); + LIST_FOREACH(by_key, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - /* If this is a specific match, then look for - * the right key immediately */ + found = true; + n_answer++; + } - first = hashmap_get(z->by_key, q->keys[i]); - LIST_FOREACH(by_key, j, first) { + if (!found) { + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) continue; - found = true; - n_answer++; - } - - if (!found) { - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; - - n_soa++; - break; - } + need_soa = true; + break; } } } - if (n_answer <= 0 && n_soa <= 0) { - *ret_answer = NULL; - *ret_soa = NULL; - - if (ret_tentative) - *ret_tentative = false; - - return 0; - } + if (n_answer <= 0 && !need_soa) + goto return_empty; if (n_answer > 0) { answer = dns_answer_new(n_answer); @@ -381,99 +360,113 @@ int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **ret_answer, DnsAnswe return -ENOMEM; } - if (n_soa > 0) { - soa = dns_answer_new(n_soa); + if (need_soa) { + soa = dns_answer_new(1); if (!soa) return -ENOMEM; } /* Second iteration, actually add the RRs to the answers */ - for (i = 0; i < q->n_keys; i++) { - DnsZoneItem *j, *first; - - if (q->keys[i]->type == DNS_TYPE_ANY || - q->keys[i]->class == DNS_CLASS_ANY) { - bool found = false, added = false; - int k; + if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { + bool found = false, added = false; + int k; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; - - found = true; + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - if (j->state != DNS_ZONE_ITEM_PROBING) - tentative = false; + found = true; - k = dns_resource_key_match_rr(q->keys[i], j->rr); - if (k < 0) - return k; - if (k > 0) { - r = dns_answer_add(answer, j->rr, 0); - if (r < 0) - return r; + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; - added = true; - } - } - - if (found && !added) { - r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(q->keys[i]), LLMNR_DEFAULT_TTL); + k = dns_resource_key_match_rr(key, j->rr, NULL); + if (k < 0) + return k; + if (k > 0) { + r = dns_answer_add(answer, j->rr, 0); if (r < 0) return r; + + added = true; } - } else { - bool found = false; + } - first = hashmap_get(z->by_key, q->keys[i]); - LIST_FOREACH(by_key, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; + if (found && !added) { + r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL); + if (r < 0) + return r; + } + } else { + bool found = false; - found = true; + first = hashmap_get(z->by_key, key); + LIST_FOREACH(by_key, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - if (j->state != DNS_ZONE_ITEM_PROBING) - tentative = false; + found = true; - r = dns_answer_add(answer, j->rr, 0); - if (r < 0) - return r; - } + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; + + r = dns_answer_add(answer, j->rr, 0); + if (r < 0) + return r; + } - if (!found) { - bool add_soa = false; + if (!found) { + bool add_soa = false; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); - LIST_FOREACH(by_name, j, first) { - if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) - continue; + first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(key)); + LIST_FOREACH(by_name, j, first) { + if (!IN_SET(j->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_ESTABLISHED, DNS_ZONE_ITEM_VERIFYING)) + continue; - if (j->state != DNS_ZONE_ITEM_PROBING) - tentative = false; + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; - add_soa = true; - } + add_soa = true; + } - if (add_soa) { - r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(q->keys[i]), LLMNR_DEFAULT_TTL); - if (r < 0) - return r; - } + if (add_soa) { + r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL); + if (r < 0) + return r; } } } + /* If the caller sets ret_tentative to NULL, then use this as + * indication to not return tentative entries */ + + if (!ret_tentative && tentative) + goto return_empty; + *ret_answer = answer; answer = NULL; - *ret_soa = soa; - soa = NULL; + if (ret_soa) { + *ret_soa = soa; + soa = NULL; + } if (ret_tentative) *ret_tentative = tentative; return 1; + +return_empty: + *ret_answer = NULL; + + if (ret_soa) + *ret_soa = NULL; + + if (ret_tentative) + *ret_tentative = false; + + return 0; } void dns_zone_item_conflict(DnsZoneItem *i) { diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h index 495d17cdb1..44a8624c30 100644 --- a/src/resolve/resolved-dns-zone.h +++ b/src/resolve/resolved-dns-zone.h @@ -31,9 +31,9 @@ typedef struct DnsZone { typedef struct DnsZoneItem DnsZoneItem; typedef enum DnsZoneItemState DnsZoneItemState; -#include "resolved-dns-rr.h" -#include "resolved-dns-question.h" #include "resolved-dns-answer.h" +#include "resolved-dns-question.h" +#include "resolved-dns-rr.h" #include "resolved-dns-transaction.h" /* RFC 4795 Section 2.8. suggests a TTL of 30s by default */ @@ -67,7 +67,7 @@ void dns_zone_flush(DnsZone *z); int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe); void dns_zone_remove_rr(DnsZone *z, DnsResourceRecord *rr); -int dns_zone_lookup(DnsZone *z, DnsQuestion *q, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); +int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, DnsAnswer **answer, DnsAnswer **soa, bool *tentative); void dns_zone_item_conflict(DnsZoneItem *i); void dns_zone_item_ready(DnsZoneItem *i); diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index 8e78fbf06a..50662656d5 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -14,6 +14,7 @@ struct ConfigPerfItem; %struct-type %includes %% -Resolve.DNS, config_parse_dnsv, DNS_SERVER_SYSTEM, 0 -Resolve.FallbackDNS, config_parse_dnsv, DNS_SERVER_FALLBACK, 0 -Resolve.LLMNR, config_parse_support, 0, offsetof(Manager, llmnr_support) +Resolve.DNS, config_parse_dns_servers, DNS_SERVER_SYSTEM, 0 +Resolve.FallbackDNS, config_parse_dns_servers, DNS_SERVER_FALLBACK, 0 +Resolve.Domains, config_parse_search_domains, 0, 0 +Resolve.LLMNR, config_parse_support, 0, offsetof(Manager, llmnr_support) diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 2892641075..ddd9427dab 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -65,19 +65,15 @@ Link *link_free(Link *l) { if (!l) return NULL; + dns_server_unlink_marked(l->dns_servers); + dns_search_domain_unlink_all(l->search_domains); + while (l->addresses) link_address_free(l->addresses); if (l->manager) hashmap_remove(l->manager->links, INT_TO_PTR(l->ifindex)); - while (l->dns_servers) { - DnsServer *s = l->dns_servers; - - LIST_REMOVE(servers, l->dns_servers, s); - dns_server_unref(s); - } - dns_scope_free(l->unicast_scope); dns_scope_free(l->llmnr_ipv4_scope); dns_scope_free(l->llmnr_ipv6_scope); @@ -158,7 +154,6 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) { static int link_update_dns_servers(Link *l) { _cleanup_strv_free_ char **nameservers = NULL; char **nameserver; - DnsServer *s, *nx; int r; assert(l); @@ -167,20 +162,20 @@ static int link_update_dns_servers(Link *l) { if (r < 0) goto clear; - LIST_FOREACH(servers, s, l->dns_servers) - s->marked = true; + dns_server_mark_all(l->dns_servers); STRV_FOREACH(nameserver, nameservers) { union in_addr_union a; + DnsServer *s; int family; r = in_addr_from_string_auto(*nameserver, &family, &a); if (r < 0) goto clear; - s = link_find_dns_server(l, family, &a); + s = dns_server_find(l->dns_servers, family, &a); if (s) - s->marked = false; + dns_server_move_back_and_unmark(s); else { r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, family, &a); if (r < 0) @@ -188,22 +183,11 @@ static int link_update_dns_servers(Link *l) { } } - LIST_FOREACH_SAFE(servers, s, nx, l->dns_servers) - if (s->marked) { - LIST_REMOVE(servers, l->dns_servers, s); - dns_server_unref(s); - } - + dns_server_unlink_marked(l->dns_servers); return 0; clear: - while (l->dns_servers) { - s = l->dns_servers; - - LIST_REMOVE(servers, l->dns_servers, s); - dns_server_unref(s); - } - + dns_server_unlink_all(l->dns_servers); return r; } @@ -236,29 +220,56 @@ clear: return r; } -static int link_update_domains(Link *l) { +static int link_update_search_domains(Link *l) { + _cleanup_strv_free_ char **domains = NULL; + char **i; int r; - if (!l->unicast_scope) - return 0; - - l->unicast_scope->domains = strv_free(l->unicast_scope->domains); + assert(l); - r = sd_network_link_get_domains(l->ifindex, - &l->unicast_scope->domains); + r = sd_network_link_get_domains(l->ifindex, &domains); if (r < 0) - return r; + goto clear; + + dns_search_domain_mark_all(l->search_domains); + + STRV_FOREACH(i, domains) { + DnsSearchDomain *d; + + r = dns_search_domain_find(l->search_domains, *i, &d); + if (r < 0) + goto clear; + + if (r > 0) + dns_search_domain_move_back_and_unmark(d); + else { + r = dns_search_domain_new(l->manager, NULL, DNS_SEARCH_DOMAIN_LINK, l, *i); + if (r < 0) + goto clear; + } + } + dns_search_domain_unlink_marked(l->search_domains); return 0; + +clear: + dns_search_domain_unlink_all(l->search_domains); + return r; } int link_update_monitor(Link *l) { + int r; + assert(l); link_update_dns_servers(l); link_update_llmnr_support(l); link_allocate_scopes(l); - link_update_domains(l); + + r = link_update_search_domains(l); + if (r < 0) + log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name); + link_add_rrs(l, false); return 0; @@ -303,17 +314,6 @@ LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *i return NULL; } -DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr) { - DnsServer *s; - - assert(l); - - LIST_FOREACH(servers, s, l->dns_servers) - if (s->family == family && in_addr_equal(family, &s->address, in_addr)) - return s; - return NULL; -} - DnsServer* link_set_dns_server(Link *l, DnsServer *s) { assert(l); @@ -327,7 +327,8 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) { log_info("Switching to DNS server %s for interface %s.", strna(ip), l->name); } - l->current_dns_server = s; + dns_server_unref(l->current_dns_server); + l->current_dns_server = dns_server_ref(s); if (l->unicast_scope) dns_cache_flush(&l->unicast_scope->cache); @@ -350,7 +351,9 @@ void link_next_dns_server(Link *l) { if (!l->current_dns_server) return; - if (l->current_dns_server->servers_next) { + /* Change to the next one, but make sure to follow the linked + * list only if this server is actually still linked. */ + if (l->current_dns_server->linked && l->current_dns_server->servers_next) { link_set_dns_server(l, l->current_dns_server->servers_next); return; } diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index e3ab27c249..eb00015bd5 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -30,8 +30,13 @@ typedef struct Link Link; typedef struct LinkAddress LinkAddress; #include "resolved-dns-rr.h" +#include "resolved-dns-search-domain.h" +#include "resolved-dns-server.h" #include "resolved-manager.h" +#define LINK_SEARCH_DOMAINS_MAX 32 +#define LINK_DNS_SERVERS_MAX 32 + struct LinkAddress { Link *link; @@ -56,6 +61,10 @@ struct Link { LIST_HEAD(DnsServer, dns_servers); DnsServer *current_dns_server; + unsigned n_dns_servers; + + LIST_HEAD(DnsSearchDomain, search_domains); + unsigned n_search_domains; Support llmnr_support; @@ -76,7 +85,6 @@ LinkAddress* link_find_address(Link *l, int family, const union in_addr_union *i void link_add_rrs(Link *l, bool force_remove); DnsServer* link_set_dns_server(Link *l, DnsServer *s); -DnsServer* link_find_dns_server(Link *l, int family, const union in_addr_union *in_addr); DnsServer* link_get_dns_server(Link *l); void link_next_dns_server(Link *l); diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 5c3a4a00c3..6a7ff9d245 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <resolv.h> #include <netinet/in.h> +#include <resolv.h> #include "fd-util.h" #include "resolved-llmnr.h" diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index a588538b52..f1f454c786 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -21,7 +21,6 @@ #include <netinet/in.h> #include <poll.h> -#include <resolv.h> #include <sys/ioctl.h> #include "af-list.h" @@ -40,6 +39,7 @@ #include "resolved-conf.h" #include "resolved-llmnr.h" #include "resolved-manager.h" +#include "resolved-resolv-conf.h" #include "socket-util.h" #include "string-table.h" #include "string-util.h" @@ -351,7 +351,7 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) { return -EINVAL; } - r = dns_label_escape(label, r, &n); + r = dns_label_escape_new(label, r, &n); if (r < 0) return log_error_errno(r, "Failed to escape host name: %m"); @@ -476,10 +476,7 @@ int manager_new(Manager **ret) { m->llmnr_support = SUPPORT_YES; m->read_resolv_conf = true; - - r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS); - if (r < 0) - return r; + m->need_builtin_fallbacks = true; r = sd_event_default(&m->event); if (r < 0) @@ -536,15 +533,16 @@ Manager *manager_free(Manager *m) { if (!m) return NULL; + dns_server_unlink_all(m->dns_servers); + dns_server_unlink_all(m->fallback_dns_servers); + dns_search_domain_unlink_all(m->search_domains); + while ((l = hashmap_first(m->links))) link_free(l); while (m->dns_queries) dns_query_free(m->dns_queries); - manager_flush_dns_servers(m, DNS_SERVER_SYSTEM); - manager_flush_dns_servers(m, DNS_SERVER_FALLBACK); - dns_scope_free(m->unicast_scope); hashmap_free(m->links); @@ -553,6 +551,9 @@ Manager *manager_free(Manager *m) { sd_event_source_unref(m->network_event_source); sd_network_monitor_unref(m->network_monitor); + sd_netlink_unref(m->rtnl); + sd_event_source_unref(m->rtnl_event_source); + manager_llmnr_stop(m); sd_bus_slot_unref(m->prepare_for_sleep_slot); @@ -576,294 +577,6 @@ Manager *manager_free(Manager *m) { return NULL; } -int manager_read_resolv_conf(Manager *m) { - _cleanup_fclose_ FILE *f = NULL; - struct stat st, own; - char line[LINE_MAX]; - DnsServer *s, *nx; - usec_t t; - int r; - - assert(m); - - /* Reads the system /etc/resolv.conf, if it exists and is not - * symlinked to our own resolv.conf instance */ - - if (!m->read_resolv_conf) - return 0; - - r = stat("/etc/resolv.conf", &st); - if (r < 0) { - if (errno != ENOENT) - log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m"); - r = -errno; - goto clear; - } - - /* Have we already seen the file? */ - t = timespec_load(&st.st_mtim); - if (t == m->resolv_conf_mtime) - return 0; - - m->resolv_conf_mtime = t; - - /* Is it symlinked to our own file? */ - if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 && - st.st_dev == own.st_dev && - st.st_ino == own.st_ino) { - r = 0; - goto clear; - } - - f = fopen("/etc/resolv.conf", "re"); - if (!f) { - if (errno != ENOENT) - log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m"); - r = -errno; - goto clear; - } - - if (fstat(fileno(f), &st) < 0) { - r = log_error_errno(errno, "Failed to stat open file: %m"); - goto clear; - } - - LIST_FOREACH(servers, s, m->dns_servers) - s->marked = true; - - FOREACH_LINE(line, f, r = -errno; goto clear) { - union in_addr_union address; - int family; - char *l; - const char *a; - - truncate_nl(line); - - l = strstrip(line); - if (*l == '#' || *l == ';') - continue; - - a = first_word(l, "nameserver"); - if (!a) - continue; - - r = in_addr_from_string_auto(a, &family, &address); - if (r < 0) { - log_warning("Failed to parse name server %s.", a); - continue; - } - - LIST_FOREACH(servers, s, m->dns_servers) - if (s->family == family && in_addr_equal(family, &s->address, &address) > 0) - break; - - if (s) - s->marked = false; - else { - r = dns_server_new(m, NULL, DNS_SERVER_SYSTEM, NULL, family, &address); - if (r < 0) - goto clear; - } - } - - LIST_FOREACH_SAFE(servers, s, nx, m->dns_servers) - if (s->marked) { - LIST_REMOVE(servers, m->dns_servers, s); - dns_server_unref(s); - } - - /* Whenever /etc/resolv.conf changes, start using the first - * DNS server of it. This is useful to deal with broken - * network managing implementations (like NetworkManager), - * that when connecting to a VPN place both the VPN DNS - * servers and the local ones in /etc/resolv.conf. Without - * resetting the DNS server to use back to the first entry we - * will continue to use the local one thus being unable to - * resolve VPN domains. */ - manager_set_dns_server(m, m->dns_servers); - - return 0; - -clear: - while (m->dns_servers) { - s = m->dns_servers; - - LIST_REMOVE(servers, m->dns_servers, s); - dns_server_unref(s); - } - - return r; -} - -static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { - _cleanup_free_ char *t = NULL; - int r; - - assert(s); - assert(f); - assert(count); - - r = in_addr_to_string(s->family, &s->address, &t); - if (r < 0) { - log_warning_errno(r, "Invalid DNS address. Ignoring: %m"); - return; - } - - if (*count == MAXNS) - fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f); - - fprintf(f, "nameserver %s\n", t); - (*count) ++; -} - -static void write_resolv_conf_search( - const char *domain, FILE *f, - unsigned *count, - unsigned *length) { - - assert(domain); - assert(f); - assert(length); - - if (*count >= MAXDNSRCH || - *length + strlen(domain) > 256) { - if (*count == MAXDNSRCH) - fputs(" # Too many search domains configured, remaining ones ignored.", f); - if (*length <= 256) - fputs(" # Total length of all search domains is too long, remaining ones ignored.", f); - - return; - } - - fprintf(f, " %s", domain); - - (*length) += strlen(domain); - (*count) ++; -} - -static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) { - Iterator i; - - fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n" - "# Third party programs must not access this file directly, but\n" - "# only through the symlink at /etc/resolv.conf. To manage\n" - "# resolv.conf(5) in a different way, replace the symlink by a\n" - "# static file or a different symlink.\n\n", f); - - if (ordered_set_isempty(dns)) - fputs("# No DNS servers known.\n", f); - else { - DnsServer *s; - unsigned count = 0; - - ORDERED_SET_FOREACH(s, dns, i) - write_resolv_conf_server(s, f, &count); - } - - if (!ordered_set_isempty(domains)) { - unsigned length = 0, count = 0; - char *domain; - - fputs("search", f); - ORDERED_SET_FOREACH(domain, domains, i) - write_resolv_conf_search(domain, f, &count, &length); - fputs("\n", f); - } - - return fflush_and_check(f); -} - -int manager_write_resolv_conf(Manager *m) { - static const char path[] = "/run/systemd/resolve/resolv.conf"; - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL; - DnsServer *s; - Iterator i; - Link *l; - int r; - - assert(m); - - /* Read the system /etc/resolv.conf first */ - manager_read_resolv_conf(m); - - /* Add the full list to a set, to filter out duplicates */ - dns = ordered_set_new(&dns_server_hash_ops); - if (!dns) - return -ENOMEM; - - domains = ordered_set_new(&dns_name_hash_ops); - if (!domains) - return -ENOMEM; - - /* First add the system-wide servers */ - LIST_FOREACH(servers, s, m->dns_servers) { - r = ordered_set_put(dns, s); - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - - /* Then, add the per-link servers and domains */ - HASHMAP_FOREACH(l, m->links, i) { - char **domain; - - LIST_FOREACH(servers, s, l->dns_servers) { - r = ordered_set_put(dns, s); - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - - if (!l->unicast_scope) - continue; - - STRV_FOREACH(domain, l->unicast_scope->domains) { - r = ordered_set_put(domains, *domain); - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - } - - /* If we found nothing, add the fallback servers */ - if (ordered_set_isempty(dns)) { - LIST_FOREACH(servers, s, m->fallback_dns_servers) { - r = ordered_set_put(dns, s); - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - } - - r = fopen_temporary_label(path, path, &f, &temp_path); - if (r < 0) - return r; - - fchmod(fileno(f), 0644); - - r = write_resolv_conf_contents(f, dns, domains); - if (r < 0) - goto fail; - - if (rename(temp_path, path) < 0) { - r = -errno; - goto fail; - } - - return 0; - -fail: - (void) unlink(path); - (void) unlink(temp_path); - return r; -} - int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; union { @@ -1171,97 +884,6 @@ int manager_send(Manager *m, int fd, int ifindex, int family, const union in_add return -EAFNOSUPPORT; } -DnsServer* manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr) { - DnsServer *s; - - assert(m); - assert(in_addr); - - LIST_FOREACH(servers, s, m->dns_servers) - if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0) - return s; - - LIST_FOREACH(servers, s, m->fallback_dns_servers) - if (s->family == family && in_addr_equal(family, &s->address, in_addr) > 0) - return s; - - return NULL; -} - -DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) { - assert(m); - - if (m->current_dns_server == s) - return s; - - if (s) { - _cleanup_free_ char *ip = NULL; - - in_addr_to_string(s->family, &s->address, &ip); - log_info("Switching to system DNS server %s.", strna(ip)); - } - - m->current_dns_server = s; - - if (m->unicast_scope) - dns_cache_flush(&m->unicast_scope->cache); - - return s; -} - -DnsServer *manager_get_dns_server(Manager *m) { - Link *l; - assert(m); - - /* Try to read updates resolv.conf */ - manager_read_resolv_conf(m); - - if (!m->current_dns_server) - manager_set_dns_server(m, m->dns_servers); - - if (!m->current_dns_server) { - bool found = false; - Iterator i; - - /* No DNS servers configured, let's see if there are - * any on any links. If not, we use the fallback - * servers */ - - HASHMAP_FOREACH(l, m->links, i) - if (l->dns_servers) { - found = true; - break; - } - - if (!found) - manager_set_dns_server(m, m->fallback_dns_servers); - } - - return m->current_dns_server; -} - -void manager_next_dns_server(Manager *m) { - assert(m); - - /* If there's currently no DNS server set, then the next - * manager_get_dns_server() will find one */ - if (!m->current_dns_server) - return; - - /* Change to the next one */ - if (m->current_dns_server->servers_next) { - manager_set_dns_server(m, m->current_dns_server->servers_next); - return; - } - - /* If there was no next one, then start from the beginning of - * the list */ - if (m->current_dns_server->type == DNS_SERVER_FALLBACK) - manager_set_dns_server(m, m->fallback_dns_servers); - else - manager_set_dns_server(m, m->dns_servers); -} - uint32_t manager_find_mtu(Manager *m) { uint32_t mtu = 0; Link *l; @@ -1415,42 +1037,102 @@ void manager_verify_all(Manager *m) { dns_zone_verify_all(&s->zone); } -void manager_flush_dns_servers(Manager *m, DnsServerType t) { +int manager_is_own_hostname(Manager *m, const char *name) { + int r; + + assert(m); + assert(name); + + if (m->llmnr_hostname) { + r = dns_name_equal(name, m->llmnr_hostname); + if (r != 0) + return r; + } + + if (m->mdns_hostname) + return dns_name_equal(name, m->mdns_hostname); + + return 0; +} + +int manager_compile_dns_servers(Manager *m, OrderedSet **dns) { DnsServer *s; + Iterator i; + Link *l; + int r; assert(m); + assert(dns); + + r = ordered_set_ensure_allocated(dns, &dns_server_hash_ops); + if (r < 0) + return r; - if (t == DNS_SERVER_SYSTEM) - while (m->dns_servers) { - s = m->dns_servers; + /* First add the system-wide servers and domains */ + LIST_FOREACH(servers, s, m->dns_servers) { + r = ordered_set_put(*dns, s); + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } - LIST_REMOVE(servers, m->dns_servers, s); - dns_server_unref(s); + /* Then, add the per-link servers */ + HASHMAP_FOREACH(l, m->links, i) { + LIST_FOREACH(servers, s, l->dns_servers) { + r = ordered_set_put(*dns, s); + if (r == -EEXIST) + continue; + if (r < 0) + return r; } + } - if (t == DNS_SERVER_FALLBACK) - while (m->fallback_dns_servers) { - s = m->fallback_dns_servers; - - LIST_REMOVE(servers, m->fallback_dns_servers, s); - dns_server_unref(s); + /* If we found nothing, add the fallback servers */ + if (ordered_set_isempty(*dns)) { + LIST_FOREACH(servers, s, m->fallback_dns_servers) { + r = ordered_set_put(*dns, s); + if (r == -EEXIST) + continue; + if (r < 0) + return r; } + } + + return 0; } -int manager_is_own_hostname(Manager *m, const char *name) { +int manager_compile_search_domains(Manager *m, OrderedSet **domains) { + DnsSearchDomain *d; + Iterator i; + Link *l; int r; assert(m); - assert(name); + assert(domains); - if (m->llmnr_hostname) { - r = dns_name_equal(name, m->llmnr_hostname); - if (r != 0) + r = ordered_set_ensure_allocated(domains, &dns_name_hash_ops); + if (r < 0) + return r; + + LIST_FOREACH(domains, d, m->search_domains) { + r = ordered_set_put(*domains, d->name); + if (r == -EEXIST) + continue; + if (r < 0) return r; } - if (m->mdns_hostname) - return dns_name_equal(name, m->mdns_hostname); + HASHMAP_FOREACH(l, m->links, i) { + + LIST_FOREACH(domains, d, l->search_domains) { + r = ordered_set_put(*domains, d->name); + if (r == -EEXIST) + continue; + if (r < 0) + return r; + } + } return 0; } diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index fe7fe99505..d00c444583 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -22,10 +22,12 @@ ***/ #include "sd-event.h" -#include "sd-network.h" #include "sd-netlink.h" -#include "list.h" +#include "sd-network.h" + #include "hashmap.h" +#include "list.h" +#include "ordered-set.h" typedef struct Manager Manager; typedef enum Support Support; @@ -39,9 +41,14 @@ enum Support { }; #include "resolved-dns-query.h" +#include "resolved-dns-search-domain.h" +#include "resolved-dns-server.h" #include "resolved-dns-stream.h" #include "resolved-link.h" +#define MANAGER_SEARCH_DOMAINS_MAX 32 +#define MANAGER_DNS_SERVERS_MAX 32 + struct Manager { sd_event *event; @@ -67,9 +74,15 @@ struct Manager { /* Unicast dns */ LIST_HEAD(DnsServer, dns_servers); LIST_HEAD(DnsServer, fallback_dns_servers); + unsigned n_dns_servers; /* counts both main and fallback */ DnsServer *current_dns_server; - bool read_resolv_conf; + LIST_HEAD(DnsSearchDomain, search_domains); + unsigned n_search_domains; + + bool need_builtin_fallbacks:1; + + bool read_resolv_conf:1; usec_t resolv_conf_mtime; LIST_HEAD(DnsScope, dns_scopes); @@ -112,13 +125,6 @@ int manager_new(Manager **ret); Manager* manager_free(Manager *m); int manager_start(Manager *m); -int manager_read_resolv_conf(Manager *m); -int manager_write_resolv_conf(Manager *m); - -DnsServer *manager_set_dns_server(Manager *m, DnsServer *s); -DnsServer *manager_find_dns_server(Manager *m, int family, const union in_addr_union *in_addr); -DnsServer *manager_get_dns_server(Manager *m); -void manager_next_dns_server(Manager *m); uint32_t manager_find_mtu(Manager *m); @@ -137,13 +143,14 @@ DnsScope* manager_find_scope(Manager *m, DnsPacket *p); void manager_verify_all(Manager *m); -void manager_flush_dns_servers(Manager *m, DnsServerType t); - DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define EXTRA_CMSG_SPACE 1024 int manager_is_own_hostname(Manager *m, const char *name); +int manager_compile_dns_servers(Manager *m, OrderedSet **servers); +int manager_compile_search_domains(Manager *m, OrderedSet **domains); + const char* support_to_string(Support p) _const_; int support_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c new file mode 100644 index 0000000000..956f380f3c --- /dev/null +++ b/src/resolve/resolved-resolv-conf.c @@ -0,0 +1,273 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 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 <resolv.h> + +#include "alloc-util.h" +#include "dns-domain.h" +#include "fd-util.h" +#include "fileio-label.h" +#include "fileio.h" +#include "ordered-set.h" +#include "resolved-conf.h" +#include "resolved-resolv-conf.h" +#include "string-util.h" +#include "strv.h" + +int manager_read_resolv_conf(Manager *m) { + _cleanup_fclose_ FILE *f = NULL; + struct stat st, own; + char line[LINE_MAX]; + usec_t t; + int r; + + assert(m); + + /* Reads the system /etc/resolv.conf, if it exists and is not + * symlinked to our own resolv.conf instance */ + + if (!m->read_resolv_conf) + return 0; + + r = stat("/etc/resolv.conf", &st); + if (r < 0) { + if (errno == ENOENT) + return 0; + + r = log_warning_errno(errno, "Failed to stat /etc/resolv.conf: %m"); + goto clear; + } + + /* Have we already seen the file? */ + t = timespec_load(&st.st_mtim); + if (t == m->resolv_conf_mtime) + return 0; + + /* Is it symlinked to our own file? */ + if (stat("/run/systemd/resolve/resolv.conf", &own) >= 0 && + st.st_dev == own.st_dev && + st.st_ino == own.st_ino) + return 0; + + f = fopen("/etc/resolv.conf", "re"); + if (!f) { + if (errno == ENOENT) + return 0; + + r = log_warning_errno(errno, "Failed to open /etc/resolv.conf: %m"); + goto clear; + } + + if (fstat(fileno(f), &st) < 0) { + r = log_error_errno(errno, "Failed to stat open file: %m"); + goto clear; + } + + dns_server_mark_all(m->dns_servers); + dns_search_domain_mark_all(m->search_domains); + + FOREACH_LINE(line, f, r = -errno; goto clear) { + const char *a; + char *l; + + l = strstrip(line); + if (*l == '#' || *l == ';') + continue; + + a = first_word(l, "nameserver"); + if (a) { + r = manager_add_dns_server_by_string(m, DNS_SERVER_SYSTEM, a); + if (r < 0) + log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a); + + continue; + } + + a = first_word(l, "domain"); + if (!a) /* We treat "domain" lines, and "search" lines as equivalent, and add both to our list. */ + a = first_word(l, "search"); + if (a) { + r = manager_parse_search_domains_and_warn(m, a); + if (r < 0) + log_warning_errno(r, "Failed to parse search domain string '%s', ignoring.", a); + } + } + + m->resolv_conf_mtime = t; + + /* Flush out all servers and search domains that are still + * marked. Those are then ones that didn't appear in the new + * /etc/resolv.conf */ + dns_server_unlink_marked(m->dns_servers); + dns_search_domain_unlink_marked(m->search_domains); + + /* Whenever /etc/resolv.conf changes, start using the first + * DNS server of it. This is useful to deal with broken + * network managing implementations (like NetworkManager), + * that when connecting to a VPN place both the VPN DNS + * servers and the local ones in /etc/resolv.conf. Without + * resetting the DNS server to use back to the first entry we + * will continue to use the local one thus being unable to + * resolve VPN domains. */ + manager_set_dns_server(m, m->dns_servers); + + /* Unconditionally flush the cache when /etc/resolv.conf is + * modified, even if the data it contained was completely + * identical to the previous version we used. We do this + * because altering /etc/resolv.conf is typically done when + * the network configuration changes, and that should be + * enough to flush the global unicast DNS cache. */ + if (m->unicast_scope) + dns_cache_flush(&m->unicast_scope->cache); + + return 0; + +clear: + dns_server_unlink_all(m->dns_servers); + dns_search_domain_unlink_all(m->search_domains); + return r; +} + +static void write_resolv_conf_server(DnsServer *s, FILE *f, unsigned *count) { + _cleanup_free_ char *t = NULL; + int r; + + assert(s); + assert(f); + assert(count); + + r = in_addr_to_string(s->family, &s->address, &t); + if (r < 0) { + log_warning_errno(r, "Invalid DNS address. Ignoring: %m"); + return; + } + + if (*count == MAXNS) + fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f); + (*count) ++; + + fprintf(f, "nameserver %s\n", t); +} + +static void write_resolv_conf_search( + const char *domain, + FILE *f, + unsigned *count, + unsigned *length) { + + assert(domain); + assert(f); + assert(length); + + if (*count >= MAXDNSRCH || + *length + strlen(domain) > 256) { + if (*count == MAXDNSRCH) + fputs(" # Too many search domains configured, remaining ones ignored.", f); + if (*length <= 256) + fputs(" # Total length of all search domains is too long, remaining ones ignored.", f); + + return; + } + + (*length) += strlen(domain); + (*count) ++; + + fputc(' ', f); + fputs(domain, f); +} + +static int write_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) { + Iterator i; + + fputs("# This file is managed by systemd-resolved(8). Do not edit.\n#\n" + "# Third party programs must not access this file directly, but\n" + "# only through the symlink at /etc/resolv.conf. To manage\n" + "# resolv.conf(5) in a different way, replace the symlink by a\n" + "# static file or a different symlink.\n\n", f); + + if (ordered_set_isempty(dns)) + fputs("# No DNS servers known.\n", f); + else { + unsigned count = 0; + DnsServer *s; + + ORDERED_SET_FOREACH(s, dns, i) + write_resolv_conf_server(s, f, &count); + } + + if (!ordered_set_isempty(domains)) { + unsigned length = 0, count = 0; + char *domain; + + fputs("search", f); + ORDERED_SET_FOREACH(domain, domains, i) + write_resolv_conf_search(domain, f, &count, &length); + fputs("\n", f); + } + + return fflush_and_check(f); +} + +int manager_write_resolv_conf(Manager *m) { + + #define PRIVATE_RESOLV_CONF "/run/systemd/resolve/resolv.conf" + + _cleanup_ordered_set_free_ OrderedSet *dns = NULL, *domains = NULL; + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(m); + + /* Read the system /etc/resolv.conf first */ + manager_read_resolv_conf(m); + + /* Add the full list to a set, to filter out duplicates */ + r = manager_compile_dns_servers(m, &dns); + if (r < 0) + return r; + + r = manager_compile_search_domains(m, &domains); + if (r < 0) + return r; + + r = fopen_temporary_label(PRIVATE_RESOLV_CONF, PRIVATE_RESOLV_CONF, &f, &temp_path); + if (r < 0) + return r; + + fchmod(fileno(f), 0644); + + r = write_resolv_conf_contents(f, dns, domains); + if (r < 0) + goto fail; + + if (rename(temp_path, PRIVATE_RESOLV_CONF) < 0) { + r = -errno; + goto fail; + } + + return 0; + +fail: + (void) unlink(PRIVATE_RESOLV_CONF); + (void) unlink(temp_path); + return r; +} diff --git a/src/resolve/resolved-resolv-conf.h b/src/resolve/resolved-resolv-conf.h new file mode 100644 index 0000000000..a3355e994b --- /dev/null +++ b/src/resolve/resolved-resolv-conf.h @@ -0,0 +1,27 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen <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 "resolved-manager.h" + +int manager_read_resolv_conf(Manager *m); +int manager_write_resolv_conf(Manager *m); diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index 7ba0546f4a..be406b71fe 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -26,6 +26,7 @@ #include "mkdir.h" #include "resolved-conf.h" #include "resolved-manager.h" +#include "resolved-resolv-conf.h" #include "selinux-util.h" #include "signal-util.h" #include "user-util.h" @@ -81,8 +82,10 @@ int main(int argc, char *argv[]) { } r = manager_parse_config_file(m); - if (r < 0) - log_warning_errno(r, "Failed to parse configuration file: %m"); + if (r < 0) { + log_error_errno(r, "Failed to parse configuration file: %m"); + goto finish; + } r = manager_start(m); if (r < 0) { diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index 3eb19e42b7..39ecf83217 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -14,4 +14,5 @@ [Resolve] #DNS= #FallbackDNS=@DNS_SERVERS@ +#Domains= #LLMNR=yes diff --git a/src/run/run.c b/src/run/run.c index 38a482bb11..e1accc467b 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -33,6 +33,7 @@ #include "event-util.h" #include "fd-util.h" #include "formats-util.h" +#include "parse-util.h" #include "path-util.h" #include "ptyfwd.h" #include "signal-util.h" @@ -41,7 +42,6 @@ #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; @@ -648,6 +648,11 @@ static int transient_timer_set_properties(sd_bus_message *m) { if (r < 0) return r; + /* Automatically clean up our transient timers */ + r = sd_bus_message_append(m, "(sv)", "RemainAfterElapse", "b", false); + if (r < 0) + return r; + if (arg_on_active) { r = sd_bus_message_append(m, "(sv)", "OnActiveSec", "t", arg_on_active); if (r < 0) @@ -687,6 +692,51 @@ static int transient_timer_set_properties(sd_bus_message *m) { return 0; } +static int make_unit_name(sd_bus *bus, UnitType t, char **ret) { + const char *unique, *id; + char *p; + int r; + + assert(bus); + assert(t >= 0); + assert(t < _UNIT_TYPE_MAX); + + r = sd_bus_get_unique_name(bus, &unique); + if (r < 0) { + sd_id128_t rnd; + + /* We couldn't get the unique name, which is a pretty + * common case if we are connected to systemd + * directly. In that case, just pick a random uuid as + * name */ + + r = sd_id128_randomize(&rnd); + if (r < 0) + return log_error_errno(r, "Failed to generate random run unit name: %m"); + + if (asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t)) < 0) + return log_oom(); + + return 0; + } + + /* We managed to get the unique name, then let's use that to + * name our transient units. */ + + id = startswith(unique, ":1."); + if (!id) { + log_error("Unique name %s has unexpected format.", unique); + return -EINVAL; + } + + p = strjoin("run-u", id, ".", unit_type_to_string(t), NULL); + if (!p) + return log_oom(); + + *ret = p; + return 0; +} + static int start_transient_service( sd_bus *bus, char **argv) { @@ -763,8 +813,11 @@ static int start_transient_service( r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service); if (r < 0) return log_error_errno(r, "Failed to mangle unit name: %m"); - } else if (asprintf(&service, "run-"PID_FMT".service", getpid()) < 0) - return log_oom(); + } else { + r = make_unit_name(bus, UNIT_SERVICE, &service); + if (r < 0) + return r; + } r = sd_bus_message_new_method_call( bus, @@ -882,8 +935,11 @@ static int start_transient_scope( r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope); if (r < 0) return log_error_errno(r, "Failed to mangle scope name: %m"); - } else if (asprintf(&scope, "run-"PID_FMT".scope", getpid()) < 0) - return log_oom(); + } else { + r = make_unit_name(bus, UNIT_SCOPE, &scope); + if (r < 0) + return r; + } r = sd_bus_message_new_method_call( bus, @@ -1052,9 +1108,15 @@ static int start_transient_timer( break; } - } else if ((asprintf(&service, "run-"PID_FMT".service", getpid()) < 0) || - (asprintf(&timer, "run-"PID_FMT".timer", getpid()) < 0)) - return log_oom(); + } else { + r = make_unit_name(bus, UNIT_SERVICE, &service); + if (r < 0) + return r; + + r = unit_name_change_suffix(service, ".timer", &timer); + if (r < 0) + return log_error_errno(r, "Failed to change unit suffix: %m"); + } r = sd_bus_message_new_method_call( bus, diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 79f5a60579..35f2e1b67d 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -22,8 +22,8 @@ #include <errno.h> #include <stdbool.h> -#include "alloc-util.h" #include "acl-util.h" +#include "alloc-util.h" #include "string-util.h" #include "strv.h" #include "user-util.h" diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index cf612e8722..256a6a5900 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -23,9 +23,9 @@ #ifdef HAVE_ACL +#include <acl/libacl.h> #include <stdbool.h> #include <sys/acl.h> -#include <acl/libacl.h> #include "macro.h" diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 8e36067f74..30e03c0652 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -25,8 +25,8 @@ #include <string.h> #include <unistd.h> -#include "alloc-util.h" #include "acpi-fpdt.h" +#include "alloc-util.h" #include "fd-util.h" #include "fileio.h" #include "time-util.h" diff --git a/src/shared/architecture.c b/src/shared/architecture.c index e2efa4272b..73937bd5a7 100644 --- a/src/shared/architecture.c +++ b/src/shared/architecture.c @@ -21,9 +21,9 @@ #include <sys/utsname.h> +#include "architecture.h" #include "string-table.h" #include "string-util.h" -#include "architecture.h" int uname_architecture(void) { diff --git a/src/shared/boot-timestamps.c b/src/shared/boot-timestamps.c index ecbe1aaa0f..879aca9374 100644 --- a/src/shared/boot-timestamps.c +++ b/src/shared/boot-timestamps.c @@ -20,8 +20,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "boot-timestamps.h" #include "acpi-fpdt.h" +#include "boot-timestamps.h" #include "efivars.h" int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) { diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 73ceeba18f..8775808da4 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1428,16 +1428,36 @@ 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; + return bus_log_create_error(r); r = sd_bus_message_append(m, "v", "a(sb)", 1, eq[0] == '-' ? eq + 1 : eq, eq[0] == '-'); if (r < 0) - return r; + return bus_log_create_error(r); + + return 0; + + } else if (streq(field, "RandomizedDelaySec")) { + usec_t t; + + r = parse_sec(eq, &t); + if (r < 0) + return log_error_errno(r, "Failed to parse RandomizedDelaySec= parameter: %s", eq); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "RandomizedDelayUSec"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "v", "t", t); + if (r < 0) + return bus_log_create_error(r); + return 0; } @@ -1450,13 +1470,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen "SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges", - "SyslogLevelPrefix", "Delegate")) { + "SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) { r = parse_boolean(eq); - if (r < 0) { - log_error("Failed to parse boolean assignment %s.", assignment); - return -EINVAL; - } + if (r < 0) + return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment); r = sd_bus_message_append(m, "v", "b", r); diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h index aa832454b5..5842bdd15e 100644 --- a/src/shared/cgroup-show.h +++ b/src/shared/cgroup-show.h @@ -23,6 +23,7 @@ #include <stdbool.h> #include <sys/types.h> + #include "logs-show.h" int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags); diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c index 835fe52423..71cc613704 100644 --- a/src/shared/clean-ipc.c +++ b/src/shared/clean-ipc.c @@ -29,13 +29,13 @@ #include <sys/stat.h> #include "clean-ipc.h" +#include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "string-util.h" #include "strv.h" #include "util.h" -#include "dirent-util.h" static int clean_sysvipc_shm(uid_t delete_uid) { _cleanup_fclose_ FILE *f = NULL; diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index fb0234baae..2872b22d9d 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> #include "macro.h" diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 7af15e0098..4cf6355b71 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -29,6 +29,8 @@ #include "hexdecoct.h" #include "parse-util.h" #include "string-util.h" +#include "strv.h" +#include "utf8.h" int dns_label_unescape(const char **name, char *dest, size_t sz) { const char *n; @@ -180,30 +182,31 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha return r; } -int dns_label_escape(const char *p, size_t l, char **ret) { - _cleanup_free_ char *s = NULL; +int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) { char *q; - int r; - - assert(p); - assert(ret); if (l > DNS_LABEL_MAX) return -EINVAL; + if (sz < 1) + return -ENOSPC; - s = malloc(l * 4 + 1); - if (!s) - return -ENOMEM; + assert(p); + assert(dest); - q = s; + q = dest; while (l > 0) { if (*p == '.' || *p == '\\') { + if (sz < 3) + return -ENOSPC; + /* Dot or backslash */ *(q++) = '\\'; *(q++) = *p; + sz -= 2; + } else if (*p == '_' || *p == '-' || (*p >= '0' && *p <= '9') || @@ -211,15 +214,27 @@ int dns_label_escape(const char *p, size_t l, char **ret) { (*p >= 'A' && *p <= 'Z')) { /* Proper character */ + + if (sz < 2) + return -ENOSPC; + *(q++) = *p; + sz -= 1; + } else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) { /* Everything else */ + + if (sz < 5) + return -ENOSPC; + *(q++) = '\\'; *(q++) = '0' + (char) ((uint8_t) *p / 100); *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10); *(q++) = '0' + (char) ((uint8_t) *p % 10); + sz -= 4; + } else return -EINVAL; @@ -228,8 +243,28 @@ int dns_label_escape(const char *p, size_t l, char **ret) { } *q = 0; + return (int) (q - dest); +} + +int dns_label_escape_new(const char *p, size_t l, char **ret) { + _cleanup_free_ char *s = NULL; + int r; + + assert(p); + assert(ret); + + if (l > DNS_LABEL_MAX) + return -EINVAL; + + s = new(char, DNS_LABEL_ESCAPED_MAX); + if (!s) + return -ENOMEM; + + r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + *ret = s; - r = q - s; s = NULL; return r; @@ -349,28 +384,32 @@ int dns_name_concat(const char *a, const char *b, char **_ret) { if (k > 0) r = k; - r = dns_label_escape(label, r, &t); - if (r < 0) - return r; - if (_ret) { - if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) return -ENOMEM; + r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + if (!first) - ret[n++] = '.'; - else - first = false; + ret[n] = '.'; + } else { + char escaped[DNS_LABEL_ESCAPED_MAX]; - memcpy(ret + n, t, r); + r = dns_label_escape(label, r, escaped, sizeof(escaped)); + if (r < 0) + return r; } + if (!first) + n++; + else + first = false; + n += r; } - if (n > DNS_NAME_MAX) - return -EINVAL; - if (_ret) { if (!GREEDY_REALLOC(ret, allocated, n + 1)) return -ENOMEM; @@ -546,6 +585,73 @@ int dns_name_endswith(const char *name, const char *suffix) { } } +int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) { + const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix; + int r, q, k, w; + + assert(name); + assert(old_suffix); + assert(new_suffix); + assert(ret); + + n = name; + s = old_suffix; + + for (;;) { + char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; + + if (!saved_before) + saved_before = n; + + r = dns_label_unescape(&n, ln, sizeof(ln)); + if (r < 0) + return r; + k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); + if (k < 0) + return k; + if (k > 0) + r = k; + + if (!saved_after) + saved_after = n; + + q = dns_label_unescape(&s, ls, sizeof(ls)); + if (q < 0) + return q; + w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); + if (w < 0) + return w; + if (w > 0) + q = w; + + if (r == 0 && q == 0) + break; + if (r == 0 && saved_after == n) { + *ret = NULL; /* doesn't match */ + return 0; + } + + ln[r] = ls[q] = 0; + + if (r != q || strcasecmp(ln, ls)) { + + /* Not the same, let's jump back, and try with the next label again */ + s = old_suffix; + n = saved_after; + saved_after = saved_before = NULL; + } + } + + /* Found it! Now generate the new name */ + prefix = strndupa(name, saved_before - name); + + r = dns_name_concat(prefix, new_suffix, ret); + if (r < 0) + return r; + + return 1; +} + int dns_name_between(const char *a, const char *b, const char *c) { int n; @@ -684,34 +790,283 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) { return 0; } -int dns_name_root(const char *name) { - char label[DNS_LABEL_MAX+1]; - int r; +bool dns_name_is_root(const char *name) { assert(name); - r = dns_label_unescape(&name, label, sizeof(label)); - if (r < 0) - return r; + /* There are exactly two ways to encode the root domain name: + * as empty string, or with a single dot. */ - return r == 0 && *name == 0; + return STR_IN_SET(name, "", "."); } -int dns_name_single_label(const char *name) { +bool dns_name_is_single_label(const char *name) { char label[DNS_LABEL_MAX+1]; int r; assert(name); r = dns_label_unescape(&name, label, sizeof(label)); + if (r <= 0) + return false; + + return dns_name_is_root(name); +} + +/* Encode a domain name according to RFC 1035 Section 3.1 */ +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len) { + uint8_t *label_length; + uint8_t *out; + int r; + + assert_return(buffer, -EINVAL); + assert_return(domain, -EINVAL); + assert_return(domain[0], -EINVAL); + + out = buffer; + + do { + /* reserve a byte for label length */ + if (len == 0) + return -ENOBUFS; + len--; + label_length = out; + out++; + + /* convert and copy a single label */ + r = dns_label_unescape(&domain, (char *) out, len); + if (r < 0) + return r; + + /* fill label length, move forward */ + *label_length = r; + out += r; + len -= r; + } while (r != 0); + + return out - buffer; +} + +static bool srv_type_label_is_valid(const char *label, size_t n) { + size_t k; + + assert(label); + + if (n < 2) /* Label needs to be at least 2 chars long */ + return false; + + if (label[0] != '_') /* First label char needs to be underscore */ + return false; + + /* Second char must be a letter */ + if (!(label[1] >= 'A' && label[1] <= 'Z') && + !(label[1] >= 'a' && label[1] <= 'z')) + return false; + + /* Third and further chars must be alphanumeric or a hyphen */ + for (k = 2; k < n; k++) { + if (!(label[k] >= 'A' && label[k] <= 'Z') && + !(label[k] >= 'a' && label[k] <= 'z') && + !(label[k] >= '0' && label[k] <= '9') && + label[k] != '-') + return false; + } + + return true; +} + +bool dns_srv_type_is_valid(const char *name) { + unsigned c = 0; + int r; + + if (!name) + return false; + + for (;;) { + char label[DNS_LABEL_MAX]; + + /* This more or less implements RFC 6335, Section 5.1 */ + + r = dns_label_unescape(&name, label, sizeof(label)); + if (r < 0) + return false; + if (r == 0) + break; + + if (c >= 2) + return false; + + if (!srv_type_label_is_valid(label, r)) + return false; + + c++; + } + + return c == 2; /* exactly two labels */ +} + +bool dns_service_name_is_valid(const char *name) { + size_t l; + + /* This more or less implements RFC 6763, Section 4.1.1 */ + + if (!name) + return false; + + if (!utf8_is_valid(name)) + return false; + + if (string_has_cc(name, NULL)) + return false; + + l = strlen(name); + if (l <= 0) + return false; + if (l > 63) + return false; + + return true; +} + +int dns_service_join(const char *name, const char *type, const char *domain, char **ret) { + char escaped[DNS_LABEL_ESCAPED_MAX]; + _cleanup_free_ char *n = NULL; + int r; + + assert(type); + assert(domain); + assert(ret); + + if (!dns_srv_type_is_valid(type)) + return -EINVAL; + + if (!name) + return dns_name_concat(type, domain, ret); + + if (!dns_service_name_is_valid(name)) + return -EINVAL; + + r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped)); if (r < 0) return r; - if (r == 0) - return 0; - r = dns_label_unescape(&name, label, sizeof(label)); + r = dns_name_concat(type, domain, &n); if (r < 0) return r; - return r == 0 && *name == 0; + return dns_name_concat(escaped, n, ret); +} + +static bool dns_service_name_label_is_valid(const char *label, size_t n) { + char *s; + + assert(label); + + if (memchr(label, 0, n)) + return false; + + s = strndupa(label, n); + return dns_service_name_is_valid(s); +} + +int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) { + _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL; + const char *p = joined, *q = NULL, *d = NULL; + char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX]; + int an, bn, cn, r; + unsigned x = 0; + + assert(joined); + + /* Get first label from the full name */ + an = dns_label_unescape(&p, a, sizeof(a)); + if (an < 0) + return an; + + if (an > 0) { + x++; + + /* If there was a first label, try to get the second one */ + bn = dns_label_unescape(&p, b, sizeof(b)); + if (bn < 0) + return bn; + + if (bn > 0) { + x++; + + /* If there was a second label, try to get the third one */ + q = p; + cn = dns_label_unescape(&p, c, sizeof(c)); + if (cn < 0) + return cn; + + if (cn > 0) + x++; + } else + cn = 0; + } else + an = 0; + + if (x >= 2 && srv_type_label_is_valid(b, bn)) { + + if (x >= 3 && srv_type_label_is_valid(c, cn)) { + + if (dns_service_name_label_is_valid(a, an)) { + + /* OK, got <name> . <type> . <type2> . <domain> */ + + name = strndup(a, an); + if (!name) + return -ENOMEM; + + type = new(char, bn+1+cn+1); + if (!type) + return -ENOMEM; + strcpy(stpcpy(stpcpy(type, b), "."), c); + + d = p; + goto finish; + } + + } else if (srv_type_label_is_valid(a, an)) { + + /* OK, got <type> . <type2> . <domain> */ + + name = NULL; + + type = new(char, an+1+bn+1); + if (!type) + return -ENOMEM; + strcpy(stpcpy(stpcpy(type, a), "."), b); + + d = q; + goto finish; + } + } + + name = NULL; + type = NULL; + d = joined; + +finish: + r = dns_name_normalize(d, &domain); + if (r < 0) + return r; + + if (_domain) { + *_domain = domain; + domain = NULL; + } + + if (_type) { + *_type = type; + type = NULL; + } + + if (_name) { + *_name = name; + name = NULL; + } + + return 0; } diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 1f0d242c18..99c72574db 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -26,11 +26,12 @@ #include "in-addr-util.h" #define DNS_LABEL_MAX 63 -#define DNS_NAME_MAX 255 +#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) int dns_label_unescape(const char **name, char *dest, size_t sz); int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz); -int dns_label_escape(const char *p, size_t l, char **ret); +int dns_label_escape(const char *p, size_t l, char *dest, size_t sz); +int dns_label_escape_new(const char *p, size_t l, char **ret); int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); @@ -62,8 +63,18 @@ int dns_name_between(const char *a, const char *b, const char *c); int dns_name_equal(const char *x, const char *y); int dns_name_endswith(const char *name, const char *suffix); +int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret); + int dns_name_reverse(int family, const union in_addr_union *a, char **ret); int dns_name_address(const char *p, int *family, union in_addr_union *a); -int dns_name_root(const char *name); -int dns_name_single_label(const char *name); +bool dns_name_is_root(const char *name); +bool dns_name_is_single_label(const char *name); + +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len); + +bool dns_srv_type_is_valid(const char *name); +bool dns_service_name_is_valid(const char *name); + +int dns_service_join(const char *name, const char *type, const char *domain, char **ret); +int dns_service_split(const char *joined, char **name, char **type, char **domain); diff --git a/src/shared/efivars.c b/src/shared/efivars.c index 86bb0b57c3..89deeb9b55 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <unistd.h> -#include <string.h> #include <fcntl.h> +#include <string.h> +#include <unistd.h> #include "alloc-util.h" #include "dirent-util.h" diff --git a/src/shared/efivars.h b/src/shared/efivars.h index e953a12737..5cb4c3af4e 100644 --- a/src/shared/efivars.h +++ b/src/shared/efivars.h @@ -24,6 +24,7 @@ #include <stdbool.h> #include "sd-id128.h" + #include "time-util.h" #define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f) diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index e178287872..5acfb0191b 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <arpa/inet.h> #include <net/if.h> +#include <sys/types.h> #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter/nf_nat.h> #include <linux/netfilter/xt_addrtype.h> diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h index 569e1faa55..98927bbc59 100644 --- a/src/shared/logs-show.h +++ b/src/shared/logs-show.h @@ -26,8 +26,8 @@ #include "sd-journal.h" -#include "util.h" #include "output-mode.h" +#include "util.h" int output_journal( FILE *f, diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index f041600fbf..038db7453c 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -21,9 +21,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "time-util.h" -#include "lockfile-util.h" #include "hashmap.h" +#include "lockfile-util.h" +#include "time-util.h" typedef enum ImageType { IMAGE_DIRECTORY, diff --git a/src/shared/nss-util.h b/src/shared/nss-util.h index 3657aa5d9c..a7b51a91da 100644 --- a/src/shared/nss-util.h +++ b/src/shared/nss-util.h @@ -21,11 +21,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <nss.h> +#include <grp.h> #include <netdb.h> -#include <resolv.h> +#include <nss.h> #include <pwd.h> -#include <grp.h> +#include <resolv.h> #define NSS_GETHOSTBYNAME_PROTOTYPES(module) \ diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index d71f379e76..4a82bd18cd 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -19,18 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> +#include <errno.h> #include <stdio.h> +#include <stdlib.h> #include <string.h> -#include <errno.h> #include "alloc-util.h" -#include "util.h" -#include "strv.h" -#include "path-util.h" #include "install.h" -#include "string-util.h" #include "path-lookup.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "util.h" int user_config_home(char **config_home) { const char *e; diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 63e81f4894..2666b8f7e2 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -19,9 +19,9 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include <limits.h> #include <sys/epoll.h> #include <sys/ioctl.h> -#include <limits.h> #include <termios.h> #include "alloc-util.h" diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index c518cf83ec..09baf51661 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -21,9 +21,9 @@ #include <seccomp.h> +#include "seccomp-util.h" #include "string-util.h" #include "util.h" -#include "seccomp-util.h" const char* seccomp_arch_to_string(uint32_t c) { diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c index 29db855c67..3fcea61873 100644 --- a/src/shared/spawn-ask-password-agent.c +++ b/src/shared/spawn-ask-password-agent.c @@ -25,8 +25,8 @@ #include "log.h" #include "process-util.h" -#include "util.h" #include "spawn-ask-password-agent.h" +#include "util.h" static pid_t agent_pid = 0; diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c index ec6e5a8312..8ea6cb830b 100644 --- a/src/shared/spawn-polkit-agent.c +++ b/src/shared/spawn-polkit-agent.c @@ -19,11 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdlib.h> -#include <unistd.h> -#include <signal.h> #include <errno.h> #include <poll.h> +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> #include "fd-util.h" #include "io-util.h" diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c index 21cb82ea1c..70caa542e7 100644 --- a/src/shared/sysctl-util.c +++ b/src/shared/sysctl-util.c @@ -30,8 +30,8 @@ #include "fileio.h" #include "log.h" #include "string-util.h" -#include "util.h" #include "sysctl-util.h" +#include "util.h" char *sysctl_normalize(char *s) { char *n; diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index d58f9873d5..7131e94cdb 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -19,15 +19,15 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/ioctl.h> #include <errno.h> #include <fcntl.h> +#include <sys/ioctl.h> #include <unistd.h> #include <linux/watchdog.h> -#include "watchdog.h" -#include "log.h" #include "fd-util.h" +#include "log.h" +#include "watchdog.h" static int watchdog_fd = -1; static usec_t watchdog_timeout = USEC_INFINITY; diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 51b82d57db..f478d809c2 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -3360,6 +3360,7 @@ typedef struct UnitStatusInfo { usec_t inactive_enter_timestamp; bool need_daemon_reload; + bool transient; /* Service */ pid_t main_pid; @@ -3459,7 +3460,7 @@ static void print_status_info( path = i->source_path ? i->source_path : i->fragment_path; - if (i->load_error) + if (i->load_error != 0) printf(" Loaded: %s%s%s (Reason: %s)\n", on, strna(i->load_state), off, i->load_error); else if (path && !isempty(i->unit_file_state) && !isempty(i->unit_file_preset)) @@ -3475,6 +3476,9 @@ static void print_status_info( printf(" Loaded: %s%s%s\n", on, strna(i->load_state), off); + if (i->transient) + printf("Transient: yes\n"); + if (!strv_isempty(i->dropin_paths)) { _cleanup_free_ char *dir = NULL; bool last = false; @@ -3839,6 +3843,8 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo * i->condition_result = b; else if (streq(name, "AssertResult")) i->assert_result = b; + else if (streq(name, "Transient")) + i->transient = b; break; } @@ -4646,8 +4652,7 @@ static int show(int argc, char *argv[], void *userdata) { return -EINVAL; } - if (show_properties) - pager_open_if_enabled(); + pager_open_if_enabled(); if (show_status) /* Increase max number of open files to 16K if we can, we @@ -6545,8 +6550,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return version(); case 't': { - if (isempty(optarg)) - return log_error_errno(r, "--type requires arguments."); + if (isempty(optarg)) { + log_error("--type requires arguments."); + return -EINVAL; + } p = optarg; for(;;) { @@ -6778,8 +6785,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_STATE: { - if (isempty(optarg)) - return log_error_errno(r, "--signal requires arguments."); + if (isempty(optarg)) { + log_error("--signal requires arguments."); + return -EINVAL; + } p = optarg; for(;;) { diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 43cf247cdf..d8adf59aca 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -27,8 +27,9 @@ #include <sys/types.h> #include <sys/uio.h> -#include "sd-id128.h" #include "sd-event.h" +#include "sd-id128.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h index 214e77cab1..c26cd1be3a 100644 --- a/src/systemd/sd-daemon.h +++ b/src/systemd/sd-daemon.h @@ -22,8 +22,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <inttypes.h> +#include <sys/types.h> #include "_sd-common.h" diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index fc11725821..edf80563ac 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -23,8 +23,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <inttypes.h> +#include <sys/types.h> #include "_sd-common.h" diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index c0146158f3..fc1d70e738 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -27,8 +27,8 @@ #include <netinet/in.h> #include <sys/types.h> -#include "sd-event.h" #include "sd-dhcp-lease.h" +#include "sd-event.h" #include "_sd-common.h" diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 55bceb1ea5..56b63c38da 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -27,6 +27,7 @@ #include <netinet/in.h> #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 9f0e92806e..29e95e2492 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -26,8 +26,8 @@ #include <net/ethernet.h> #include <sys/types.h> -#include "sd-event.h" #include "sd-dhcp6-lease.h" +#include "sd-event.h" #include "_sd-common.h" @@ -49,6 +49,7 @@ int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata); int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); +int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, size_t addr_len, uint16_t arp_type); int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 565de5495a..fb97f7f28d 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -22,11 +22,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> -#include <sys/signalfd.h> -#include <sys/epoll.h> #include <inttypes.h> #include <signal.h> +#include <sys/epoll.h> +#include <sys/signalfd.h> +#include <sys/types.h> #include "_sd-common.h" @@ -56,7 +56,8 @@ enum { SD_EVENT_PENDING, SD_EVENT_RUNNING, SD_EVENT_EXITING, - SD_EVENT_FINISHED + SD_EVENT_FINISHED, + SD_EVENT_PREPARING, }; enum { @@ -87,9 +88,9 @@ int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callb int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); int sd_event_prepare(sd_event *e); -int sd_event_wait(sd_event *e, uint64_t timeout); +int sd_event_wait(sd_event *e, uint64_t usec); int sd_event_dispatch(sd_event *e); -int sd_event_run(sd_event *e, uint64_t timeout); +int sd_event_run(sd_event *e, uint64_t usec); int sd_event_loop(sd_event *e); int sd_event_exit(sd_event *e, int code); diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index 6337d61452..c1e79640eb 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -23,10 +23,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/in.h> #include <net/ethernet.h> +#include <netinet/in.h> #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 2949f1dfb2..1d25f02bd0 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -22,10 +22,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <netinet/in.h> #include <net/ethernet.h> +#include <netinet/in.h> #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index 00237a2158..facb6d8a95 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -23,12 +23,13 @@ ***/ #include <inttypes.h> -#include <sys/types.h> #include <stdarg.h> +#include <sys/types.h> #include <sys/uio.h> #include <syslog.h> #include "sd-id128.h" + #include "_sd-common.h" /* Journal APIs. See sd-journal(3) for more information. */ diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 31651ce132..16d297a52d 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -23,10 +23,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <net/ethernet.h> #include <inttypes.h> +#include <net/ethernet.h> #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index 59c6eedcda..2ad6bcb357 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -22,8 +22,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <inttypes.h> +#include <sys/types.h> #include "_sd-common.h" diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 8aedaec6d1..072832a916 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -23,6 +23,7 @@ ***/ #include "sd-id128.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 80e24325f7..71e65d4425 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -26,6 +26,7 @@ #include <net/ethernet.h> #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 2960deda0a..dd5cc04ca6 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -23,12 +23,13 @@ ***/ #include <inttypes.h> -#include <netinet/in.h> #include <netinet/ether.h> +#include <netinet/in.h> #include <linux/rtnetlink.h> #include <linux/neighbour.h> #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 4179015fbf..076f45745d 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -23,8 +23,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <sys/types.h> #include <inttypes.h> +#include <sys/types.h> #include "_sd-common.h" diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 82c4b39efe..bfe32102f8 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -28,6 +28,7 @@ #include <sys/types.h> #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c index a5b66a7d2f..35479d67c1 100644 --- a/src/test/test-architecture.c +++ b/src/test/test-architecture.c @@ -19,10 +19,10 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "virt.h" #include "architecture.h" -#include "util.h" #include "log.h" +#include "util.h" +#include "virt.h" int main(int argc, char *argv[]) { int a, v; diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index 06d93af533..fab33d20c7 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -20,11 +20,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" -#include "log.h" +#include "acpi-fpdt.h" #include "boot-timestamps.h" #include "efivars.h" -#include "acpi-fpdt.h" +#include "log.h" +#include "util.h" static int test_acpi_fpdt(void) { usec_t loader_start; diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 70819b0371..9cef7154c6 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -75,7 +75,7 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_ u = after; r = calendar_spec_next_usec(c, after, &u); - printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp(buf, sizeof(buf), u)); + printf("At: %s\n", r < 0 ? strerror(-r) : format_timestamp_us(buf, sizeof(buf), u)); if (expect != (usec_t)-1) assert_se(r >= 0 && u == expect); else @@ -123,6 +123,9 @@ int main(int argc, char* argv[]) { 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_one("2016-03-27 03:17:00.4200005", "2016-03-27 03:17:00.420001"); + test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); + test_one("2016-03-27 03:17:00/0.42", "2016-03-27 03:17:00/0.420000"); test_next("2016-03-27 03:17:00", "", 12345, 1459048620000000); test_next("2016-03-27 03:17:00", "CET", 12345, 1459041420000000); @@ -131,11 +134,19 @@ int main(int argc, char* argv[]) { 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); + test_next("2016-03-27 03:17:00.420000001 UTC", "EET", 12345, 1459048620420000); + test_next("2016-03-27 03:17:00.4200005 UTC", "EET", 12345, 1459048620420001); + test_next("2015-11-13 09:11:23.42", "EET", 12345, 1447398683420000); + test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683420000, 1447398685190000); + test_next("2015-11-13 09:11:23.42/1.77", "EET", 1447398683419999, 1447398683420000); assert_se(calendar_spec_from_string("test", &c) < 0); assert_se(calendar_spec_from_string("", &c) < 0); assert_se(calendar_spec_from_string("7", &c) < 0); assert_se(calendar_spec_from_string("121212:1:2", &c) < 0); + assert_se(calendar_spec_from_string("2000-03-05.23 00:00:00", &c) < 0); + assert_se(calendar_spec_from_string("2000-03-05 00:00.1:00", &c) < 0); + assert_se(calendar_spec_from_string("00:00:00/0.00000001", &c) < 0); return 0; } diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index de6c421b82..2746013522 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -21,10 +21,10 @@ #include <stdio.h> -#include "manager.h" -#include "unit.h" #include "macro.h" +#include "manager.h" #include "test-helper.h" +#include "unit.h" static int test_cgroup_mask(void) { Manager *m = NULL; @@ -40,6 +40,16 @@ static int test_cgroup_mask(void) { puts("manager_new: Permission denied. Skipping test."); return EXIT_TEST_SKIP; } + + /* Turn off all kinds of default accouning, so that we can + * verify the masks resulting of our configuration and nothing + * else. */ + m->default_cpu_accounting = + m->default_memory_accounting = + m->default_blockio_accounting = + m->default_tasks_accounting = false; + m->default_tasks_max = (uint64_t) -1; + assert_se(r >= 0); assert_se(manager_startup(m, serial, fdset) >= 0); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index d5778748a0..f010e4e19a 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -52,6 +52,36 @@ static void test_dns_label_unescape(void) { test_dns_label_unescape_one("foobar.", "foobar", 20, 6); } +static void test_dns_name_to_wire_format_one(const char *what, const char *expect, size_t buffer_sz, int ret) { + uint8_t buffer[buffer_sz]; + int r; + + r = dns_name_to_wire_format(what, buffer, buffer_sz); + assert_se(r == ret); + + if (r < 0) + return; + + assert_se(!memcmp(buffer, expect, r)); +} + +static void test_dns_name_to_wire_format(void) { + const char out1[] = { 3, 'f', 'o', 'o', 0 }; + const char out2[] = { 5, 'h', 'a', 'l', 'l', 'o', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; + const char out3[] = { 4, ' ', 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; + + test_dns_name_to_wire_format_one("", NULL, 0, -EINVAL); + + test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1)); + test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) + 1, sizeof(out1)); + test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) - 1, -ENOBUFS); + + test_dns_name_to_wire_format_one("hallo.foo.bar", out2, sizeof(out2), sizeof(out2)); + test_dns_name_to_wire_format_one("hallo.foo..bar", NULL, 32, -EINVAL); + + test_dns_name_to_wire_format_one("\\032foo.bar", out3, sizeof(out3), sizeof(out3)); +} + static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) { char buffer[buffer_sz]; const char *label; @@ -96,7 +126,7 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex _cleanup_free_ char *t = NULL; int r; - r = dns_label_escape(what, l, &t); + r = dns_label_escape_new(what, l, &t); assert_se(r == ret); if (r < 0) @@ -216,21 +246,21 @@ static void test_dns_name_endswith(void) { test_dns_name_endswith_one("x.y\001.z", "waldo", -EINVAL); } -static void test_dns_name_root(void) { - assert_se(dns_name_root("") == true); - assert_se(dns_name_root(".") == true); - assert_se(dns_name_root("xxx") == false); - assert_se(dns_name_root("xxx.") == false); - assert_se(dns_name_root("..") == -EINVAL); +static void test_dns_name_is_root(void) { + assert_se(dns_name_is_root("")); + assert_se(dns_name_is_root(".")); + assert_se(!dns_name_is_root("xxx")); + assert_se(!dns_name_is_root("xxx.")); + assert_se(!dns_name_is_root("..")); } -static void test_dns_name_single_label(void) { - assert_se(dns_name_single_label("") == false); - assert_se(dns_name_single_label(".") == false); - assert_se(dns_name_single_label("..") == -EINVAL); - assert_se(dns_name_single_label("x") == true); - assert_se(dns_name_single_label("x.") == true); - assert_se(dns_name_single_label("xx.yy") == false); +static void test_dns_name_is_single_label(void) { + assert_se(!dns_name_is_single_label("")); + assert_se(!dns_name_is_single_label(".")); + assert_se(!dns_name_is_single_label("..")); + assert_se(dns_name_is_single_label("x")); + assert_se(dns_name_is_single_label("x.")); + assert_se(!dns_name_is_single_label("xx.yy")); } static void test_dns_name_reverse_one(const char *address, const char *name) { @@ -286,6 +316,117 @@ static void test_dns_name_is_valid(void) { test_dns_name_is_valid_one("\n", 0); } +static void test_dns_service_name_is_valid(void) { + assert_se(dns_service_name_is_valid("Lennart's Compüter")); + assert_se(dns_service_name_is_valid("piff.paff")); + + assert_se(!dns_service_name_is_valid(NULL)); + assert_se(!dns_service_name_is_valid("")); + assert_se(!dns_service_name_is_valid("foo\nbar")); + assert_se(!dns_service_name_is_valid("foo\201bar")); + assert_se(!dns_service_name_is_valid("this is an overly long string that is certainly longer than 63 characters")); +} + +static void test_dns_srv_type_is_valid(void) { + + assert_se(dns_srv_type_is_valid("_http._tcp")); + assert_se(dns_srv_type_is_valid("_foo-bar._tcp")); + assert_se(dns_srv_type_is_valid("_w._udp")); + assert_se(dns_srv_type_is_valid("_a800._tcp")); + assert_se(dns_srv_type_is_valid("_a-800._tcp")); + + assert_se(!dns_srv_type_is_valid(NULL)); + assert_se(!dns_srv_type_is_valid("")); + assert_se(!dns_srv_type_is_valid("x")); + assert_se(!dns_srv_type_is_valid("_foo")); + assert_se(!dns_srv_type_is_valid("_tcp")); + assert_se(!dns_srv_type_is_valid("_")); + assert_se(!dns_srv_type_is_valid("_foo.")); + assert_se(!dns_srv_type_is_valid("_föo._tcp")); + assert_se(!dns_srv_type_is_valid("_f\no._tcp")); + assert_se(!dns_srv_type_is_valid("_800._tcp")); + assert_se(!dns_srv_type_is_valid("_-800._tcp")); + assert_se(!dns_srv_type_is_valid("_-foo._tcp")); + assert_se(!dns_srv_type_is_valid("_piep._foo._udp")); +} + +static void test_dns_service_join_one(const char *a, const char *b, const char *c, int r, const char *d) { + _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL; + + assert_se(dns_service_join(a, b, c, &t) == r); + assert_se(streq_ptr(t, d)); + + if (r < 0) + return; + + assert_se(dns_service_split(t, &x, &y, &z) >= 0); + assert_se(streq_ptr(a, x)); + assert_se(streq_ptr(b, y)); + assert_se(streq_ptr(c, z)); +} + +static void test_dns_service_join(void) { + test_dns_service_join_one("", "", "", -EINVAL, NULL); + test_dns_service_join_one("", "_http._tcp", "", -EINVAL, NULL); + test_dns_service_join_one("", "_http._tcp", "foo", -EINVAL, NULL); + test_dns_service_join_one("foo", "", "foo", -EINVAL, NULL); + test_dns_service_join_one("foo", "foo", "foo", -EINVAL, NULL); + + test_dns_service_join_one("foo", "_http._tcp", "", 0, "foo._http._tcp"); + test_dns_service_join_one(NULL, "_http._tcp", "", 0, "_http._tcp"); + test_dns_service_join_one("foo", "_http._tcp", "foo", 0, "foo._http._tcp.foo"); + test_dns_service_join_one(NULL, "_http._tcp", "foo", 0, "_http._tcp.foo"); + test_dns_service_join_one("Lennart's PC", "_pc._tcp", "foo.bar.com", 0, "Lennart\\039s\\032PC._pc._tcp.foo.bar.com"); + test_dns_service_join_one(NULL, "_pc._tcp", "foo.bar.com", 0, "_pc._tcp.foo.bar.com"); +} + +static void test_dns_service_split_one(const char *joined, const char *a, const char *b, const char *c, int r) { + _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL, *t = NULL; + + assert_se(dns_service_split(joined, &x, &y, &z) == r); + assert_se(streq_ptr(x, a)); + assert_se(streq_ptr(y, b)); + assert_se(streq_ptr(z, c)); + + if (r < 0) + return; + + if (y) { + assert_se(dns_service_join(x, y, z, &t) == 0); + assert_se(streq_ptr(joined, t)); + } else + assert_se(!x && streq_ptr(z, joined)); +} + +static void test_dns_service_split(void) { + test_dns_service_split_one("", NULL, NULL, "", 0); + test_dns_service_split_one("foo", NULL, NULL, "foo", 0); + test_dns_service_split_one("foo.bar", NULL, NULL, "foo.bar", 0); + test_dns_service_split_one("_foo.bar", NULL, NULL, "_foo.bar", 0); + test_dns_service_split_one("_foo._bar", NULL, "_foo._bar", "", 0); + test_dns_service_split_one("_meh._foo._bar", "_meh", "_foo._bar", "", 0); + test_dns_service_split_one("Wuff\\032Wuff._foo._bar.waldo.com", "Wuff Wuff", "_foo._bar", "waldo.com", 0); +} + +static void test_dns_name_change_suffix_one(const char *name, const char *old_suffix, const char *new_suffix, int r, const char *result) { + _cleanup_free_ char *s = NULL; + + assert_se(dns_name_change_suffix(name, old_suffix, new_suffix, &s) == r); + assert_se(streq_ptr(s, result)); +} + +static void test_dns_name_change_suffix(void) { + test_dns_name_change_suffix_one("foo.bar", "bar", "waldo", 1, "foo.waldo"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "foo.bar.waldi.quux", "piff.paff", 1, "piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "bar.waldi.quux", "piff.paff", 1, "foo.piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "waldi.quux", "piff.paff", 1, "foo.bar.piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "quux", "piff.paff", 1, "foo.bar.waldi.piff.paff"); + test_dns_name_change_suffix_one("foo.bar.waldi.quux", "", "piff.paff", 1, "foo.bar.waldi.quux.piff.paff"); + test_dns_name_change_suffix_one("", "", "piff.paff", 1, "piff.paff"); + test_dns_name_change_suffix_one("", "", "", 1, ""); + test_dns_name_change_suffix_one("a", "b", "c", 0, NULL); +} + int main(int argc, char *argv[]) { test_dns_label_unescape(); @@ -295,11 +436,17 @@ int main(int argc, char *argv[]) { test_dns_name_equal(); test_dns_name_endswith(); test_dns_name_between(); - test_dns_name_root(); - test_dns_name_single_label(); + test_dns_name_is_root(); + test_dns_name_is_single_label(); test_dns_name_reverse(); test_dns_name_concat(); test_dns_name_is_valid(); + test_dns_name_to_wire_format(); + test_dns_service_name_is_valid(); + test_dns_srv_type_is_valid(); + test_dns_service_join(); + test_dns_service_split(); + test_dns_name_change_suffix(); return 0; } diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 954ed0d9e0..4f14c58788 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -19,12 +19,12 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <errno.h> +#include <stdio.h> #include <string.h> -#include "manager.h" #include "bus-util.h" +#include "manager.h" int main(int argc, char *argv[]) { _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index bde3c7c3cf..871c71e171 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <fcntl.h> +#include <stdio.h> #include <unistd.h> #include "alloc-util.h" diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c index d636e427c4..ff66bde094 100644 --- a/src/test/test-firewall-util.c +++ b/src/test/test-firewall-util.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "log.h" #include "firewall-util.h" +#include "log.h" #define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))} diff --git a/src/test/test-hashmap.c b/src/test/test-hashmap.c index d0e65001f5..83cea360e6 100644 --- a/src/test/test-hashmap.c +++ b/src/test/test-hashmap.c @@ -17,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "hashmap.h" +#include "util.h" void test_hashmap_funcs(void); void test_ordered_hashmap_funcs(void); diff --git a/src/test/test-install.c b/src/test/test-install.c index 359b262347..ef6f1efb89 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <stdio.h> +#include <string.h> #include "install.h" diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c index af0d76e894..75ce3a349e 100644 --- a/src/test/test-job-type.c +++ b/src/test/test-job-type.c @@ -22,8 +22,8 @@ #include <stdio.h> #include "job.h" -#include "unit.h" #include "service.h" +#include "unit.h" int main(int argc, char*argv[]) { JobType a, b, c, ab, bc, ab_c, bc_a, a_bc; diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c index 9765075365..427c698d1d 100644 --- a/src/test/test-locale-util.c +++ b/src/test/test-locale-util.c @@ -19,8 +19,8 @@ #include "locale-util.h" -#include "strv.h" #include "macro.h" +#include "strv.h" static void test_get_locales(void) { _cleanup_strv_free_ char **locales = NULL; diff --git a/src/test/test-log.c b/src/test/test-log.c index 9dcfa2f274..a01df9b049 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -22,9 +22,9 @@ #include <stddef.h> #include <unistd.h> +#include "formats-util.h" #include "log.h" #include "util.h" -#include "formats-util.h" int main(int argc, char* argv[]) { diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index e3e5a95add..556938a0f8 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -19,11 +19,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <string.h> #include <stdio.h> +#include <string.h> -#include "loopback-setup.h" #include "log.h" +#include "loopback-setup.h" int main(int argc, char* argv[]) { int r; diff --git a/src/test/test-ns.c b/src/test/test-ns.c index 3050be9e9d..1175114a3a 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -22,8 +22,8 @@ #include <stdlib.h> #include <unistd.h> -#include "namespace.h" #include "log.h" +#include "namespace.h" int main(int argc, char *argv[]) { const char * const writable[] = { diff --git a/src/test/test-ratelimit.c b/src/test/test-ratelimit.c index 462b55cdb3..990b834c79 100644 --- a/src/test/test-ratelimit.c +++ b/src/test/test-ratelimit.c @@ -19,9 +19,9 @@ #include <unistd.h> +#include "macro.h" #include "ratelimit.h" #include "time-util.h" -#include "macro.h" static void test_ratelimit_test(void) { int i; diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index ebc9110c4d..8396ae60f3 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -21,8 +21,8 @@ #include <sched.h> -#include "manager.h" #include "macro.h" +#include "manager.h" int main(int argc, char *argv[]) { Manager *m = NULL; diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c index 2402da6a6f..c20be99350 100644 --- a/src/test/test-siphash24.c +++ b/src/test/test-siphash24.c @@ -19,23 +19,18 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "util.h" #include "siphash24.h" +#include "util.h" #define ITERATIONS 10000000ULL -/* see https://131002.net/siphash/siphash.pdf, Appendix A */ -int main(int argc, char *argv[]) { +static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { 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)); + out = siphash24(in, len, key); + assert_se(out == 0xa129ca6149be45e5); /* verify the internal state as given in the above paper */ siphash24_init(&state, key); @@ -43,13 +38,13 @@ int main(int argc, char *argv[]) { assert_se(state.v1 == 0x6b617f6d656e6665); assert_se(state.v2 == 0x6b7f62616d677361); assert_se(state.v3 == 0x7b6b696e727e6c7b); - siphash24_compress(in, sizeof(in), &state); + siphash24_compress(in, len, &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)); + out = siphash24_finalize(&state); + assert_se(out == 0xa129ca6149be45e5); assert_se(state.v0 == 0xf6bcd53893fecff1); assert_se(state.v1 == 0x54b9964c7ea0d937); assert_se(state.v2 == 0x1b38329c099bb55a); @@ -57,14 +52,34 @@ int main(int argc, char *argv[]) { /* 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++) { + for (i = 0; i < len; i++) { + for (j = i; j < len; 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)); + siphash24_compress(&in[j], len - j, &state); + out = siphash24_finalize(&state); + assert_se(out == 0xa129ca6149be45e5); } } + return 0; +} + +/* see https://131002.net/siphash/siphash.pdf, Appendix A */ +int main(int argc, char *argv[]) { + 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}; + uint8_t in_buf[20]; + + /* Test with same input but different alignments. */ + memcpy(in_buf, in, sizeof(in)); + do_test(in_buf, sizeof(in), key); + memcpy(in_buf + 1, in, sizeof(in)); + do_test(in_buf + 1, sizeof(in), key); + memcpy(in_buf + 2, in, sizeof(in)); + do_test(in_buf + 2, sizeof(in), key); + memcpy(in_buf + 4, in, sizeof(in)); + do_test(in_buf + 4, sizeof(in), key); } diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c index 4308ddfb64..fb115ce4f3 100644 --- a/src/test/test-sleep.c +++ b/src/test/test-sleep.c @@ -21,10 +21,10 @@ #include <stdio.h> -#include "util.h" #include "log.h" #include "sleep-config.h" #include "strv.h" +#include "util.h" static void test_sleep(void) { _cleanup_strv_free_ char diff --git a/src/test/test-tables.c b/src/test/test-tables.c index da27cde3da..aef992ee3c 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -36,6 +36,7 @@ #include "logs-show.h" #include "mount.h" #include "path.h" +#include "rlimit-util.h" #include "scope.h" #include "service.h" #include "slice.h" @@ -43,13 +44,11 @@ #include "socket.h" #include "swap.h" #include "target.h" +#include "test-tables.h" #include "timer.h" #include "unit-name.h" #include "unit.h" #include "util.h" -#include "rlimit-util.h" - -#include "test-tables.h" int main(int argc, char **argv) { test_table(architecture, ARCHITECTURE); diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index e940b5a204..84b448a095 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -18,8 +18,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <stdio.h> #include <stdbool.h> +#include <stdio.h> #include "fd-util.h" #include "fileio.h" diff --git a/src/test/test-time.c b/src/test/test-time.c index 820e4aaee2..8896b2c92b 100644 --- a/src/test/test-time.c +++ b/src/test/test-time.c @@ -19,8 +19,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "time-util.h" #include "strv.h" +#include "time-util.h" static void test_parse_sec(void) { usec_t u; diff --git a/src/test/test-unaligned.c b/src/test/test-unaligned.c index 1754d06b2d..b18b3fca0e 100644 --- a/src/test/test-unaligned.c +++ b/src/test/test-unaligned.c @@ -17,8 +17,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "unaligned.h" #include "sparse-endian.h" +#include "unaligned.h" #include "util.h" static uint8_t data[] = { @@ -26,7 +26,7 @@ static uint8_t data[] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, }; -int main(int argc, const char *argv[]) { +static void test_be(void) { uint8_t scratch[16]; assert_se(unaligned_read_be16(&data[0]) == 0x0001); @@ -91,3 +91,75 @@ int main(int argc, const char *argv[]) { unaligned_write_be64(&scratch[7], 0x0708090a0b0c0d0e); assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0); } + +static void test_le(void) { + uint8_t scratch[16]; + + assert_se(unaligned_read_le16(&data[0]) == 0x0100); + assert_se(unaligned_read_le16(&data[1]) == 0x0201); + + assert_se(unaligned_read_le32(&data[0]) == 0x03020100); + assert_se(unaligned_read_le32(&data[1]) == 0x04030201); + assert_se(unaligned_read_le32(&data[2]) == 0x05040302); + assert_se(unaligned_read_le32(&data[3]) == 0x06050403); + + assert_se(unaligned_read_le64(&data[0]) == 0x0706050403020100); + assert_se(unaligned_read_le64(&data[1]) == 0x0807060504030201); + assert_se(unaligned_read_le64(&data[2]) == 0x0908070605040302); + assert_se(unaligned_read_le64(&data[3]) == 0x0a09080706050403); + assert_se(unaligned_read_le64(&data[4]) == 0x0b0a090807060504); + assert_se(unaligned_read_le64(&data[5]) == 0x0c0b0a0908070605); + assert_se(unaligned_read_le64(&data[6]) == 0x0d0c0b0a09080706); + assert_se(unaligned_read_le64(&data[7]) == 0x0e0d0c0b0a090807); + + zero(scratch); + unaligned_write_le16(&scratch[0], 0x0100); + assert_se(memcmp(&scratch[0], &data[0], sizeof(uint16_t)) == 0); + zero(scratch); + unaligned_write_le16(&scratch[1], 0x0201); + assert_se(memcmp(&scratch[1], &data[1], sizeof(uint16_t)) == 0); + + zero(scratch); + unaligned_write_le32(&scratch[0], 0x03020100); + + assert_se(memcmp(&scratch[0], &data[0], sizeof(uint32_t)) == 0); + zero(scratch); + unaligned_write_le32(&scratch[1], 0x04030201); + assert_se(memcmp(&scratch[1], &data[1], sizeof(uint32_t)) == 0); + zero(scratch); + unaligned_write_le32(&scratch[2], 0x05040302); + assert_se(memcmp(&scratch[2], &data[2], sizeof(uint32_t)) == 0); + zero(scratch); + unaligned_write_le32(&scratch[3], 0x06050403); + assert_se(memcmp(&scratch[3], &data[3], sizeof(uint32_t)) == 0); + + zero(scratch); + unaligned_write_le64(&scratch[0], 0x0706050403020100); + assert_se(memcmp(&scratch[0], &data[0], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[1], 0x0807060504030201); + assert_se(memcmp(&scratch[1], &data[1], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[2], 0x0908070605040302); + assert_se(memcmp(&scratch[2], &data[2], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[3], 0x0a09080706050403); + assert_se(memcmp(&scratch[3], &data[3], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[4], 0x0B0A090807060504); + assert_se(memcmp(&scratch[4], &data[4], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[5], 0x0c0b0a0908070605); + assert_se(memcmp(&scratch[5], &data[5], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[6], 0x0d0c0b0a09080706); + assert_se(memcmp(&scratch[6], &data[6], sizeof(uint64_t)) == 0); + zero(scratch); + unaligned_write_le64(&scratch[7], 0x0e0d0c0b0a090807); + assert_se(memcmp(&scratch[7], &data[7], sizeof(uint64_t)) == 0); +} + +int main(int argc, const char *argv[]) { + test_be(); + test_le(); +} diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index c3973a316e..0b3630f77c 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -680,11 +680,42 @@ static void test_config_parse_rlimit(void) { assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "55:66", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 55); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 66); + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity", rl, NULL) >= 0); assert_se(rl[RLIMIT_NOFILE]); assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "infinity:infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == rl[RLIMIT_NOFILE]->rlim_max); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "10:20:30", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + /* Invalid values don't change rl */ + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "wat:wat", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "66:wat", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitNOFILE", RLIMIT_NOFILE, "200:100", rl, NULL) >= 0); + assert_se(rl[RLIMIT_NOFILE]); + assert_se(rl[RLIMIT_NOFILE]->rlim_cur == 10); + assert_se(rl[RLIMIT_NOFILE]->rlim_max == 20); + rl[RLIMIT_NOFILE] = mfree(rl[RLIMIT_NOFILE]); assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); @@ -697,6 +728,11 @@ static void test_config_parse_rlimit(void) { assert_se(rl[RLIMIT_CPU]->rlim_cur == 57); assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "40s:1m", rl, NULL) >= 0); + assert_se(rl[RLIMIT_CPU]); + assert_se(rl[RLIMIT_CPU]->rlim_cur == 40); + assert_se(rl[RLIMIT_CPU]->rlim_max == 60); + assert_se(config_parse_sec_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "infinity", rl, NULL) >= 0); assert_se(rl[RLIMIT_CPU]); assert_se(rl[RLIMIT_CPU]->rlim_cur == RLIM_INFINITY); @@ -714,16 +750,31 @@ static void test_config_parse_rlimit(void) { assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58:60", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 58); + assert_se(rl[RLIMIT_RTTIME]->rlim_max == 60); + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s", rl, NULL) >= 0); assert_se(rl[RLIMIT_RTTIME]); assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "59s:123s", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 59 * USEC_PER_SEC); + assert_se(rl[RLIMIT_RTTIME]->rlim_max == 123 * USEC_PER_SEC); + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity", rl, NULL) >= 0); assert_se(rl[RLIMIT_RTTIME]); assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "infinity:infinity", rl, NULL) >= 0); + assert_se(rl[RLIMIT_RTTIME]); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == RLIM_INFINITY); + assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); + assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "2345ms", rl, NULL) >= 0); assert_se(rl[RLIMIT_RTTIME]); assert_se(rl[RLIMIT_RTTIME]->rlim_cur == 2345 * USEC_PER_MSEC); diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index 0af8349732..e98be5763c 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -20,9 +20,9 @@ ***/ #include "alloc-util.h" +#include "string-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-watchdog.c b/src/test/test-watchdog.c index 2e5d0c3aae..d10d9f49af 100644 --- a/src/test/test-watchdog.c +++ b/src/test/test-watchdog.c @@ -21,8 +21,8 @@ #include <unistd.h> -#include "watchdog.h" #include "log.h" +#include "watchdog.h" int main(int argc, char *argv[]) { usec_t t = 10 * USEC_PER_SEC; diff --git a/src/timesync/timesyncd-conf.h b/src/timesync/timesyncd-conf.h index 56466fe462..cbc19c4054 100644 --- a/src/timesync/timesyncd-conf.h +++ b/src/timesync/timesyncd-conf.h @@ -22,7 +22,6 @@ ***/ #include "conf-parser.h" - #include "timesyncd-manager.h" const struct ConfigPerfItem* timesyncd_gperf_lookup(const char *key, unsigned length); diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h index 090b2fcba8..fab22cfe84 100644 --- a/src/timesync/timesyncd-manager.h +++ b/src/timesync/timesyncd-manager.h @@ -22,8 +22,9 @@ ***/ #include "sd-event.h" -#include "sd-resolve.h" #include "sd-network.h" +#include "sd-resolve.h" + #include "list.h" #include "ratelimit.h" diff --git a/src/timesync/timesyncd-server.h b/src/timesync/timesyncd-server.h index 18c44445e1..f764d0737b 100644 --- a/src/timesync/timesyncd-server.h +++ b/src/timesync/timesyncd-server.h @@ -21,8 +21,8 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include "socket-util.h" #include "list.h" +#include "socket-util.h" typedef struct ServerAddress ServerAddress; typedef struct ServerName ServerName; diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 74b6b91593..f9a759e223 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1226,8 +1226,28 @@ static int create_item(Item *i) { mkdir_parents_label(i->path, 0755); 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); + + if (btrfs_is_subvol(isempty(arg_root) ? "/" : arg_root) <= 0) + + /* Don't create a subvolume unless the + * root directory is one, too. We do + * this under the assumption that if + * the root directory is just a plain + * directory (i.e. very light-weight), + * we shouldn't try to split it up + * into subvolumes (i.e. more + * heavy-weight). Thus, chroot() + * environments and suchlike will get + * a full brtfs subvolume set up below + * their tree only if they + * specifically set up a btrfs + * subvolume for the root dir too. */ + + r = -ENOTTY; + else { + RUN_WITH_UMASK((~i->mode) & 0777) + r = btrfs_subvol_make(i->path); + } } else r = 0; diff --git a/src/udev/mtd_probe/mtd_probe.c b/src/udev/mtd_probe/mtd_probe.c index 67b750c4b3..462fab7623 100644 --- a/src/udev/mtd_probe/mtd_probe.c +++ b/src/udev/mtd_probe/mtd_probe.c @@ -17,14 +17,14 @@ * Boston, MA 02110-1301 USA */ +#include <fcntl.h> +#include <mtd/mtd-user.h> #include <stdio.h> +#include <stdlib.h> #include <sys/ioctl.h> -#include <mtd/mtd-user.h> -#include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> +#include <sys/types.h> #include <unistd.h> -#include <stdlib.h> #include "mtd_probe.h" diff --git a/src/udev/mtd_probe/probe_smartmedia.c b/src/udev/mtd_probe/probe_smartmedia.c index a007ccee2f..6a6c5522a7 100644 --- a/src/udev/mtd_probe/probe_smartmedia.c +++ b/src/udev/mtd_probe/probe_smartmedia.c @@ -17,15 +17,16 @@ * Boston, MA 02110-1301 USA */ +#include <fcntl.h> +#include <mtd/mtd-user.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <mtd/mtd-user.h> #include <string.h> -#include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> +#include <sys/types.h> #include <unistd.h> -#include <stdint.h> + #include "mtd_probe.h" static const uint8_t cis_signature[] = { diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 776674e994..77d9bf995a 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -354,14 +354,14 @@ static int get_mac(struct udev_device *device, bool want_random, if (want_random) random_bytes(mac->ether_addr_octet, ETH_ALEN); else { - uint8_t result[8]; + uint64_t result; - r = net_get_unique_predictable_data(device, result); + r = net_get_unique_predictable_data(device, &result); if (r < 0) return r; assert_cc(ETH_ALEN <= sizeof(result)); - memcpy(mac->ether_addr_octet, result, ETH_ALEN); + memcpy(mac->ether_addr_octet, &result, ETH_ALEN); } /* see eth_random_addr in the kernel */ diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index bbda9de08c..3ebe36f043 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -18,9 +18,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <errno.h> #include <stdio.h> #include <stdlib.h> -#include <errno.h> #include "sd-login.h" diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 1e05be51a5..962de22f43 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -10,13 +10,13 @@ */ #include <errno.h> -#include <stdlib.h> +#include <poll.h> #include <stddef.h> +#include <stdlib.h> #include <string.h> -#include <unistd.h> -#include <poll.h> #include <sys/socket.h> #include <sys/un.h> +#include <unistd.h> #include "alloc-util.h" #include "fd-util.h" diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index 9aa5ab185d..f1fdccaed8 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -17,12 +17,12 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <errno.h> -#include <stdio.h> #include <dirent.h> +#include <errno.h> #include <stddef.h> -#include <unistd.h> +#include <stdio.h> #include <sys/inotify.h> +#include <unistd.h> #include "udev.h" diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 78170463b6..989decbe95 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -13,15 +13,15 @@ */ #include <errno.h> +#include <getopt.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> -#include <stddef.h> #include <string.h> #include <unistd.h> -#include <getopt.h> -#include "udev.h" #include "udev-util.h" +#include "udev.h" static void print_help(void) { printf("%s control COMMAND\n\n" diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index 30aa53feb2..f9cb5e63a2 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -15,15 +15,15 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdio.h> -#include <stddef.h> -#include <string.h> #include <errno.h> -#include <signal.h> #include <getopt.h> -#include <time.h> -#include <sys/time.h> +#include <signal.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> #include <sys/epoll.h> +#include <sys/time.h> +#include <time.h> #include "fd-util.h" #include "formats-util.h" diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index c25071b0fe..6a5dc6e9e4 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -17,14 +17,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <stdio.h> -#include <unistd.h> #include <errno.h> #include <getopt.h> #include <poll.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> #include "parse-util.h" #include "udev.h" diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 5364b92a57..6d9d765153 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -191,7 +191,7 @@ static void worker_free(struct worker *worker) { assert(worker->manager); - hashmap_remove(worker->manager->workers, UINT_TO_PTR(worker->pid)); + hashmap_remove(worker->manager->workers, PID_TO_PTR(worker->pid)); udev_monitor_unref(worker->monitor); event_free(worker->event); @@ -234,7 +234,7 @@ static int worker_new(struct worker **ret, Manager *manager, struct udev_monitor if (r < 0) return r; - r = hashmap_put(manager->workers, UINT_TO_PTR(pid), worker); + r = hashmap_put(manager->workers, PID_TO_PTR(pid), worker); if (r < 0) return r; @@ -891,7 +891,7 @@ static int on_worker(sd_event_source *s, int fd, uint32_t revents, void *userdat } /* lookup worker who sent the signal */ - worker = hashmap_get(manager->workers, UINT_TO_PTR(ucred->pid)); + worker = hashmap_get(manager->workers, PID_TO_PTR(ucred->pid)); if (!worker) { log_debug("worker ["PID_FMT"] returned, but is no longer tracked", ucred->pid); continue; @@ -1195,7 +1195,7 @@ static int on_sigchld(sd_event_source *s, const struct signalfd_siginfo *si, voi if (pid <= 0) break; - worker = hashmap_get(manager->workers, UINT_TO_PTR(pid)); + worker = hashmap_get(manager->workers, PID_TO_PTR(pid)); if (!worker) { log_warning("worker ["PID_FMT"] is unknown, ignoring", pid); continue; diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c index 607d78a019..aec6676a33 100644 --- a/src/udev/v4l_id/v4l_id.c +++ b/src/udev/v4l_id/v4l_id.c @@ -13,17 +13,17 @@ * General Public License for more details: */ -#include <stdio.h> -#include <errno.h> -#include <string.h> #include <ctype.h> -#include <stdlib.h> -#include <unistd.h> +#include <errno.h> #include <fcntl.h> #include <getopt.h> -#include <sys/types.h> -#include <sys/time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <sys/ioctl.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> #include <linux/videodev2.h> #include "fd-util.h" diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in index d5f600ef45..5e04c821b6 100644 --- a/sysctl.d/50-coredump.conf.in +++ b/sysctl.d/50-coredump.conf.in @@ -9,4 +9,4 @@ # and systemd-coredump(8) and core(5) for the explanation of the # setting below. -kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %p %u %g %s %t %e +kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %e diff --git a/test/README.testsuite b/test/README.testsuite index 5c7aca43a8..fa7e73ce3a 100644 --- a/test/README.testsuite +++ b/test/README.testsuite @@ -36,7 +36,7 @@ you can even skip the "clean" and "setup" if you want to run the machine again. $ sudo make KERNEL_APPEND="systemd.unit=multi-user.target" run You can specify a different kernel and initramfs with $KERNEL_BIN and $INITRD. -(Fedora's default kernel path and initramfs are used by default) +(Fedora's or Debian's default kernel path and initramfs are used by default) $ sudo make KERNEL_BIN=/boot/vmlinuz-foo INITRD=/boot/initramfs-bar clean check diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh index b6b474393d..6963d8c88d 100755 --- a/test/TEST-01-BASIC/test.sh +++ b/test/TEST-01-BASIC/test.sh @@ -11,7 +11,7 @@ check_result_qemu() { mount ${LOOPDEV}p1 $TESTDIR/root [[ -e $TESTDIR/root/testok ]] && ret=0 [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR - [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR umount $TESTDIR/root [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed ls -l $TESTDIR/journal/*/*.journal @@ -58,9 +58,16 @@ Type=oneshot EOF setup_testsuite - ) + ) || return 1 setup_nspawn_root + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + ddebug "umount $TESTDIR/root" umount $TESTDIR/root } diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh index 2997da06ff..dada99df59 100755 --- a/test/TEST-02-CRYPTSETUP/test.sh +++ b/test/TEST-02-CRYPTSETUP/test.sh @@ -13,7 +13,7 @@ check_result_qemu() { [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile mount /dev/mapper/varcrypt $TESTDIR/root/var - [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR umount $TESTDIR/root/var umount $TESTDIR/root cryptsetup luksClose /dev/mapper/varcrypt @@ -76,7 +76,7 @@ EOF cat >>$initdir/etc/fstab <<EOF /dev/mapper/varcrypt /var ext3 defaults 0 1 EOF - ) + ) || return 1 setup_nspawn_root ddebug "umount $TESTDIR/root/var" diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh index 41e02e2c8a..83393435f0 100755 --- a/test/TEST-03-JOBS/test.sh +++ b/test/TEST-03-JOBS/test.sh @@ -63,7 +63,7 @@ EOF cp test-jobs.sh $initdir/ setup_testsuite - ) + ) || return 1 setup_nspawn_root ddebug "umount $TESTDIR/root" diff --git a/test/TEST-04-JOURNAL/Makefile b/test/TEST-04-JOURNAL/Makefile new file mode 120000 index 0000000000..e9f93b1104 --- /dev/null +++ b/test/TEST-04-JOURNAL/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile
\ No newline at end of file diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh new file mode 100755 index 0000000000..956e377100 --- /dev/null +++ b/test/TEST-04-JOURNAL/test-journal.sh @@ -0,0 +1,55 @@ +#!/bin/bash + +set -x +set -e +set -o pipefail + +# Test stdout stream + +# Skip empty lines +ID=$(journalctl --new-id128 | sed -n 2p) +>/expected +printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false +journalctl --flush +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +>/expected +printf $'<5>\n<6>\n<7>\n' | systemd-cat -t "$ID" --level-prefix true +journalctl --flush +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Remove trailing spaces +ID=$(journalctl --new-id128 | sed -n 2p) +printf "Trailing spaces\n">/expected +printf $'<5>Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix true +journalctl --flush +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +printf "Trailing spaces\n">/expected +printf $'Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix false +journalctl --flush +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Don't remove leading spaces +ID=$(journalctl --new-id128 | sed -n 2p) +printf $' \t Leading spaces\n'>/expected +printf $'<5> \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix true +journalctl --flush +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +printf $' \t Leading spaces\n'>/expected +printf $' \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix false +journalctl --flush +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +touch /testok +exit 0 diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh new file mode 100755 index 0000000000..e37cb7d412 --- /dev/null +++ b/test/TEST-04-JOURNAL/test.sh @@ -0,0 +1,76 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="Journal-related tests" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if check_nspawn; then + run_nspawn + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <<EOF +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-journal.sh +Type=oneshot +EOF + + cp test-journal.sh $initdir/ + + setup_testsuite + ) + setup_nspawn_root + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/test-functions b/test/test-functions index 49f143ec1e..9288200717 100644 --- a/test/test-functions +++ b/test/test-functions @@ -4,6 +4,7 @@ PATH=/sbin:/bin:/usr/sbin:/usr/bin export PATH +LOOKS_LIKE_DEBIAN=$(source /etc/os-release && [[ "$ID" = "debian" || "$ID_LIKE" = "debian" ]] && echo yes) KERNEL_VER=${KERNEL_VER-$(uname -r)} KERNEL_MODS="/lib/modules/$KERNEL_VER/" @@ -12,7 +13,7 @@ if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then ROOTLIBDIR=/usr/lib/systemd fi -BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe" +BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee" DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname" function find_qemu_bin() { @@ -50,8 +51,11 @@ run_qemu() { && KERNEL_BIN="/boot/$MACHINE_ID/$KERNEL_VER/linux" fi + default_fedora_initrd=/boot/initramfs-${KERNEL_VER}.img + default_debian_initrd=/boot/initrd.img-${KERNEL_VER} [ "$KERNEL_BIN" ] || KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER - [ "$INITRD" ] || INITRD=/boot/initramfs-${KERNEL_VER}.img + [ "$INITRD" ] || { [ -e "$default_fedora_initrd" ] && INITRD=$default_fedora_initrd; } + [ "$INITRD" ] || { [ "$LOOKS_LIKE_DEBIAN" ] && [ -e "$default_debian_initrd" ] && INITRD=$default_debian_initrd; } [ "$QEMU_SMP" ] || QEMU_SMP=1 find_qemu_bin || return 1 @@ -67,8 +71,7 @@ selinux=0 \ $KERNEL_APPEND \ " - QEMU_OPTIONS="-machine accel=kvm:tcg \ --smp $QEMU_SMP \ + QEMU_OPTIONS="-smp $QEMU_SMP \ -net none \ -m 512M \ -nographic \ @@ -79,13 +82,17 @@ $KERNEL_APPEND \ QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD" fi + if [ -c /dev/kvm ]; then + QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host" + fi + ( set -x $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND" $TESTDIR/rootdisk.img ) || return 1 } run_nspawn() { set -x - ../../systemd-nspawn --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND + ../../systemd-nspawn --register=no --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND } setup_basic_environment() { @@ -141,12 +148,12 @@ install_missing_libraries() { create_empty_image() { rm -f "$TESTDIR/rootdisk.img" # Create the blank file to use as a root filesystem - dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=300 + dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=400 LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img) [ -b "$LOOPDEV" ] || return 1 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE sfdisk "$LOOPDEV" <<EOF -,290M +,390M , EOF @@ -225,6 +232,7 @@ install_config_files() { inst /etc/sysconfig/init inst /etc/passwd inst /etc/shadow + inst /etc/login.defs inst /etc/group inst /etc/shells inst /etc/nsswitch.conf @@ -272,14 +280,19 @@ install_dbus() { } install_pam() { + ( + [[ "$LOOKS_LIKE_DEBIAN" ]] && type -p dpkg-architecture &>/dev/null && find "/lib/$(dpkg-architecture -qDEB_HOST_MULTIARCH)/security" -xtype f find \ /etc/pam.d \ /etc/security \ /lib64/security \ /lib/security -xtype f \ - | while read file; do + ) | while read file; do inst $file done + + [[ "$LOOKS_LIKE_DEBIAN" ]] && + cp /etc/pam.d/systemd-user $initdir/etc/pam.d/ } install_keymaps() { @@ -1121,7 +1134,7 @@ inst_libdir_file() { } check_nspawn() { - [[ -d /sys/fs/cgroup/systemd ]] + [[ -d /run/systemd/system ]] } diff --git a/tools/make-directive-index.py b/tools/make-directive-index.py index 17b1325bba..8091683fee 100755 --- a/tools/make-directive-index.py +++ b/tools/make-directive-index.py @@ -268,6 +268,7 @@ def _make_section(template, name, directives, formatting): b = tree.SubElement(para, 'citerefentry') c = tree.SubElement(b, 'refentrytitle') c.text = manpage + c.attrib['target'] = varname d = tree.SubElement(b, 'manvolnum') d.text = manvolume entry.tail = '\n\n' diff --git a/units/systemd-nspawn@.service.in b/units/systemd-nspawn@.service.in index 2e79adff44..eb10343ac6 100644 --- a/units/systemd-nspawn@.service.in +++ b/units/systemd-nspawn@.service.in @@ -20,6 +20,7 @@ RestartForceExitStatus=133 SuccessExitStatus=133 Slice=machine.slice Delegate=yes +TasksMax=8192 # Enforce a strict device policy, similar to the one nspawn configures # when it allocates its own scope unit. Make sure to keep these diff --git a/units/user@.service.m4.in b/units/user@.service.m4.in index 1e21d51aae..66aba4f985 100644 --- a/units/user@.service.m4.in +++ b/units/user@.service.m4.in @@ -17,3 +17,4 @@ ExecStart=-@rootlibexecdir@/systemd --user Slice=user-%i.slice KillMode=mixed Delegate=yes +TasksMax=infinity |